Harden git commit calls

Two fixes on the same files. First: git commit messages are constructed via template literals and passed through the shell — user-controlled text in `--reason` can break commits or theoretically execute code. Replace all 5 `execSync` git commit calls with `spawnSync` so message content is never shell-interpreted. Second: the `work complete` output has a nudge block that re-reads the entire proof_chain.json to decide whether to show a recommendation. The nudge is the wrong design — it's a one-shot discoverability hack with an arbitrary threshold, not a data-driven signal. Remove it entirely and replace the chain output line with a cleaner format that includes the per-run finding delta.

verdict PASSscore 15 / 15findings 4 (0 risk · 0 debt · 4 obs)duration 39mrejection cycles 0shipped Apr 29, 2026surface cli

Pipeline timeline

Intent to proven code in 39m across Think, Plan, Build, and Verify.

Think
6m
Plan
6m
Build
17m
Verify
16m

Assertion ledger

15 claims, each independently verified. Showing 8 — show all →

IDSaysMatcher
A001Proof close commits use safe argument passing instead of shell interpolationverifiedok
A002Artifact save commits use safe argument passing instead of shell interpolationverifiedok
A003Work complete commits use safe argument passing instead of shell interpolationverifiedok
A004Commit messages with special characters and newlines produce correct git commitsverifiedok
A005Failed commits still show error messages and exit the processverifiedok
A006Proof chain stats include the count of new findings from the latest runverifiedok
A007New findings count comes from the current entry's findingsverifiedok
A008Completion output shows satisfied count without the word coveredverifiedok

Findings 4 total

obspackages/cli/tests/commands/work.test.tsclosed
Test name 'shows maintenance line when findings were auto-closed' is now inverted — assertions check not.toContain('Maintenance:') but name says 'shows'
obspackages/cli/tests/commands/work.test.tsclosed
@ana tag collision: A001-A005 tags in work.test.ts match previous features' contracts, not this one. Pre-check reports COVERED for spawnSync assertions but no tagged test actually verifies spawnSync usage. Spec says no new unit tests needed; source verification confirms correctness.
obspackages/cli/src/commands/work.tsclosed
Recovery path counts total findings via loop but main path uses stats.findings — two different counting mechanisms for the same display. If totalFindings computation in writeProofChain diverges from the simple loop, recovery output could drift.
obsclosed
Spec says to remove ProofChain from import type on line 23 — but ProofChain is still used in writeProofChain (line 748). Spec guidance was incorrect; builder correctly kept the import.

Integrity seal

scopesha256:ff0ffb0d97145...
contractsha256:1a76ad4a8862b...
plansha256:77e08b66d66ba...
specsha256:21a734910ba37...
build-reportsha256:5e20d877e6199...
build-datasha256:fb88c3765b174...
verify-reportsha256:c8c2a96d31c39...
verify-datasha256:44d39d9e4db58...
audit cmd$ ana proof audit harden-git-commit-calls   → all hashes match