fix(#3968): measure commit claims at all three surfaces — ledger, verifier BLOCKER, porcelain HANDOFF (#4230)

* test(#3968): commit claims must be measured against git, never narrated

* fix(#3968): measure commit claims at all three surfaces

Emitted-Drift-Ack-Growth: gsd-executor.md — #3968 plan commit ledger and measured commits contract (held under the agent size cap)
Emitted-Drift-Ack-Growth: verify-work.md — #3968 commit-claim reconciliation with the same rev-list instrument
Emitted-Drift-Ack-Growth: pause-work.md — #3968 uncommitted_files from git status --porcelain

* fix(#3968): retired slash syntax, allowlist line pin, git-compare test pin

* fix(#3968): persist the ledger on disk and reconcile with the same rev-list instrument

Emitted-Drift-Ack-Growth: gsd-executor.md — #3968 plan commit ledger and measured commits contract (held under the agent size cap)
Emitted-Drift-Ack-Growth: verify-work.md — #3968 commit-claim reconciliation with the same rev-list instrument

* fix(#3968): hold the gsd-executor size cap with a compact ledger contract

Emitted-Drift-Ack-Growth: gsd-executor.md — #3968 plan commit ledger and measured commits contract (held under the agent size cap)

* fix(#3968): allowlist pin and HALT regex track the final prose

* chore(#3968): changeset for measured commit claims

* chore(#3968): backfill changeset pr number

* fix(#3968): quote the BASE expansion (SC2086)

* ci: raise the test-lane budget 21 to 32 minutes (measured cost grew past the cap)

---------

Co-authored-by: sim <sim@local>
This commit is contained in:
Tom Boucher
2026-09-03 05:43:16 -04:00
committed by GitHub
parent d5f8191f66
commit 3639ab0431
8 changed files with 137 additions and 7 deletions

View File

@@ -537,6 +537,18 @@ git add src/types/user.ts
```bash
gsd_run query commit-to-subrepo "{type}({phase}-{plan}): {concise task description}" --files file1 file2 ...
```
**0c. Plan commit ledger (#3968, single-repo — before the first commit):**
Each Bash call is a FRESH shell, so the ledger persists on disk like the #3097 sentinel above
(a variable would be unset at SUMMARY time and `rev-list ..HEAD` would measure zero).
Per-plan filename, so sequential plans cannot contaminate each other:
```bash
_GSD_LEDGER="$(git rev-parse --git-dir)/gsd-plan-head-before-{phase}-{plan}"
[ -f "$_GSD_LEDGER" ] || git rev-parse HEAD > "$_GSD_LEDGER"
```
The SUMMARY's `commits:` is MEASURED from this ledger, the base recorded as
`plan_head_before:` for `/gsd:verify-work`'s same-instrument check. Multi-repo keeps commit-to-subrepo
JSON hashes instead.
Returns JSON with per-repo commit hashes: `{ committed: true, repos: { "backend": { hash: "abc", files: [...] }, ... } }`. Record all hashes for SUMMARY.
**Otherwise (standard single-repo):**
@@ -649,10 +661,22 @@ This file is the canonical output of this step. The orchestrator reads `.plannin
actuals:
tokens: 74000 # chars/4 over the files you actually changed
tasks: 5 # tasks completed
commits: 7 # commits made
commits: 7 # MEASURED: git rev-list --count ${PLAN_HEAD_BEFORE}..HEAD (#3968)
```
These pair with the plan's `estimate` to calibrate future estimates (ADR-2629). Do not round to look closer to the estimate — a flattering number corrupts every later projection.
**`commits:` is measured, never narrated (#3968).** At SUMMARY write, read the persisted
ledger (protocol 0c — a fresh shell per Bash call; the base comes from disk):
```bash
PLAN_HEAD_BEFORE=$(cat "$(git rev-parse --git-dir)/gsd-plan-head-before-{phase}-{plan}")
COMMITS_ACTUAL=$(git rev-list --count ${PLAN_HEAD_BEFORE}..HEAD)
```
Write BOTH into the frontmatter — `commits: ${COMMITS_ACTUAL}`,
`plan_head_before: ${PLAN_HEAD_BEFORE}` — including when the count is `0`.
A `0` with code changes means the changes sit UNCOMMITTED: **HALT — do not write the
SUMMARY with a narrated count**; surface `git status --short` in your return. A `0` with no
code changes (docs-only) is legitimate. `/gsd:verify-work` flags mismatches as BLOCKER.
**Title:** `# Phase [X] Plan [Y]: [Name] Summary`
**One-liner must be substantive:**