Skip to content

fix(pm): check-harness-current prints boundary, not a fabricated sha, when a harness path's latest touch is not provable on the shallow checkout - #18352

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-18330-harness-current-provable-touch
Sep 16, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
claude/issue-18330-harness-current-provable-touch

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes #18330

The defect

scripts/pm/check-harness-current.mjs took each harness path's latest touch from raw git log -1 REF -- PATH on the shared SHALLOW checkout and printed the resulting sha as that path's provenance. On a shallow clone that sha is routinely the clone's own graft boundary: the boundary's commit object names a parent the clone does not have, git applies the graft at traversal, diffs the commit against the EMPTY tree, and every path in its tree reads as touched there — at exit 0, with no warning.

The same mechanism was observed three times on the shared checkout within one shift, at three different fetch states, naming three different shas for .claude/hooks/*: 9b00f9f9cf (the card's reading), af3add1601, and a0dd872c1b (the reading quoted below). None of them changed a hook.

What changed

The provenance clause — and only that clause — now goes through touchIsProvable from scripts/pm/git-history.mjs (the proven leg that landed with PR #18327, itself the second half of the finding filed from #18180):

  • provable — the sha is printed as before, with the proof named: [proven: N parent(s) present locally, diff-tree touches PATH].
  • graft boundary — the word boundary is printed in place of the sha, followed by the tool's own reason.
  • unprovable for any other reason — the word unprovable, followed by the reason.

It never fetches. The shared checkout is not this tool's to deepen (deepening is an operator action per scripts/pm/git-history.mjs's header), and a seat-side reading must not mutate the tree every other seat is reading. A self-test case pins that the clone is still shallow and its boundary unmoved after a run.

What deliberately did NOT change

The verdict computation (the merge-base --is-ancestor test and the committer-time / shallow fallback), the three exit codes, and the CURRENT / STALE / UNDECIDED summary line are byte-identical — the seating protocol and the triage seat's stand-down logic read those.

The header now records WHY the verdict survives a boundary reading: the verdict is a placement question about a COMMIT, not about the path, and a boundary is only ever named when no commit above the shallow floor touched the path — so the true touch sits at or below the floor, hence is an ancestor of the named boundary, and a commit whose descendant is already under HEAD is under HEAD too. The negative direction was already conservative: a negative ancestry test on a shallow clone reports UNDECIDED rather than STALE.

Reverse verification (both versions run back to back on the shared checkout, same tree, same moment)

BEFORE (origin/main version):

✓ .claude/hooks/*: latest touch a0dd872c1b (2026-09-13T13:15:30+00:00) is in the shared HEAD
check-harness-current: CURRENT -- every harness-loaded path on origin/main is in /home/user/objectstack HEAD ceb6b5fb46

AFTER (this branch):

✓ .claude/hooks/*: latest touch boundary (2026-09-13T13:15:30+00:00) [a0dd872c1 is a shallow graft boundary — its object names parent 9489e2c05, which this clone does not have, so git diffed it against the EMPTY tree and every path in its tree reads as touched there; nothing says whether .claude/hooks/* was really changed by it] is in the shared HEAD
✓ .claude/agents/*.md: latest touch 9fa9955ab4 (2026-09-15T06:58:14+00:00) [proven: 1 parent(s) present locally, diff-tree touches .claude/agents/os-dev.md] is in the shared HEAD
check-harness-current: CURRENT -- every harness-loaded path on origin/main is in /home/user/objectstack HEAD ceb6b5fb46

diff of the two summary lines is empty; both runs exit 0; the shared checkout is still shallow and .git/shallow is unchanged (md5 66039b7f8cfd0bcc7ea50d01daf5865d). The provable path (.claude/agents/*.md) keeps the same sha it printed before, now with its proof.

Firing control — a deepened clone must print the TRUE sha for the same path, or boundary would be a constant rather than a reading. That control runs inside the self-test rather than by hand: the fixture's hook file is touched only at c1, below every shallow floor the test cuts, so the depth-5 clone prints boundary and the complete clone of the same upstream prints c1's real sha.

Self-test — 14 cases, floor pinned at 14

node scripts/pm/check-harness-current.mjs --self-test builds a 40-commit fixture upstream carrying the three real harness paths, then clones it shallow (depth 5), complete, and behind:

  1. BASELINE — raw git log -1 names the graft boundary for a hook the boundary never changed
  2. the unprovable reading prints boundary, with the graft mechanism named
  3. the fabricated sha is nowhere offered AS the touch
  4. the verdict clause on that same line is untouched
  5. a PROVABLE reading on the SAME shallow clone still prints its sha, with the proof
  6. the summary line is byte-identical on the run that withheld a sha
  7. the exit code is unchanged
  8. nothing was fetched — still shallow, boundary unmoved
  9. FIRING CONTROL — the complete clone prints the true sha for that same path
  10. the summary line is byte-identical there too, same exit code
  11. the STALE branch keeps the provenance clause spliced in and -- STALE line-terminal
  12. the STALE summary line, byte for byte
  13. an unreadable path stays UNDECIDED at exit 2, in today's exact words
  14. the UNDECIDED summary line, byte for byte

Plus a case floor, because failures === 0 alone cannot tell "every case held" from "the cases never ran".

Gates

node scripts/pm/dispatch-gates.mjs --commands scripts/pm/check-harness-current.mjs derived 29 commands; all 29 ran and all exit 0, reconciled with --ran (29 derived, 29 run, 0 NOT-MEASURED, 0 UNRUN). Plus npx eslint scripts/pm/check-harness-current.mjs (exit 0) and the new --self-test (14/14). pnpm check:pm-dispatch-gates is not derived for this path and was not run.

Acceptance notes (noted, not filed)

  • The new --self-test runs in no CI job. check-self-test-wired counts 228 scripts under scripts/ carrying a --self-test and 212 that CI runs; this script is named by no workflow and no root package.json alias, so it is outside that gate's population and joins a pre-existing set of ~15. Wiring it would mean a fourth run_self_test line in lint.yml's Shallow-history guard self-tests collector (plus that step's closing prose, which check-step-collectors.mjs --self-test extracts and drives) — both outside this card's file surface. Left for the seat.
  • touchIsProvable reports boundary: false for a registered graft whose parent has since been fetched. Measured on the shared checkout earlier in the same shift: af3add1601 was listed in .git/shallow, so git log and git show --stat applied the graft and credited it with every path in its tree, while its object's parent d285bf0f was present locally — so leg 1 (object parents present) passed and the verdict came back provable: false, boundary: false with the reason "has its parent(s) locally but its diff does not touch PATH". The refusal is correct and this script prints unprovable rather than a fabricated sha either way, but the boundary flag is a false negative, and the discriminator that would not miss it is membership in .git/shallow rather than object-parent presence. scripts/pm/git-history.mjs is consumed, not edited, on this card; carded in the report for the seat to file. Dedupe words: touchIsProvable stale shallow entry · graft registered parent present · boundary false negative diff-tree · git shallow file membership · objectParents presence insufficient.

Generated by Claude Code

… when a harness path's latest touch is not provable

`git log -1 <ref> -- <path>` on the shared SHALLOW checkout names the clone's
graft boundary whenever no commit above the shallow floor touched the path:
the boundary's object names a parent the clone lacks, git applies the graft at
traversal, diffs the commit against the EMPTY tree, and every path in its tree
reads as touched there -- at exit 0, with no warning. The harness-currency
verdict survives that (it is a placement question about a COMMIT, and the
boundary is an ancestor-side stand-in for a true touch that sits at or below
the floor), but the sha printed beside it was offered as the path's provenance
and is not a reading of the path.

Take the reading through `touchIsProvable` and print `boundary` / `unprovable`
with the reason in place of a sha that cannot be proven, and the sha WITH its
proof (parents present, diff-tree touches the path) when it can. No fetching:
the shared checkout is not this tool's to deepen. The verdict computation, the
exit codes and the CURRENT / STALE / UNDECIDED summary line are untouched --
other seats read those.

Adds a 14-case `--self-test` over real shallow and complete fixture clones:
the boundary reading, the provable reading on the same clone, the byte-identical
summary in both, the STALE and UNDECIDED branches, and the no-fetch invariant.

Claude-Session: https://claude.ai/code/session_01HZfg2AwVX191qCizp88gQr
Co-authored-by: Claude <noreply@anthropic.com>

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 6b750117909adb1e74ff9319d73d1ce02dc1c5b9

Reviewing seat: domain:skills, in-seat review at the contract-review tier — get_session read at 2026-09-15T07:15Z: configured_model = session_context.model = last_served_model, the constant's tier, no fallback notice this round. Card #18330, claim 5691007290, report 5691189101 (posted through the tool; read back clean, author os-zhuang#18350); Clause-②: no on the claim; default-tier build, seat review at tier.

① Derived judgments

  • Accept set / public surface: none moves — scripts/pm/check-harness-current.mjs (59 → 286 lines, the only file) against merge base ceb6b5fb (= origin/main); nothing published; skip-changeset read back (size/m + skip-changeset). Non-governed ⇒ in-seat landing. git-history.mjs consumed (two imports), not edited — the claim's surface exactly.
  • The change, read whole on a detached worktree of the head: the per-path provenance clause goes through touchIsProvable — a provable sha prints WITH its proof (parents present, diff-tree touches the path), an unprovable one prints boundary (the graft case) or unprovable with the tool's reason in place of the sha; the verdict logic (merge-base --is-ancestor, the committer-time / shallow fallback), the three exit codes and the CURRENT / STALE / UNDECIDED summary lines are byte-identical (the diff moves them into main() unchanged); it never fetches; the header records why the verdict survives a boundary reading (a boundary is named only when the true touch sits at or below the floor, hence an ancestor of it); a 14-case --self-test over real file:// fixture clones (shallow / complete / behind / no-hooks) with a case-count floor of 14. Seat re-runs on the head: self-test 14 / 14, ESLint 0/0, check-self-test-wired 0 (this script is outside its population — see the wiring card), check-scripts-symbol-anchors 0, --pair 18352 0. The seat ran BOTH versions back to back on the shared shallow checkout: the old prints a0dd872c1b as .claude/hooks/*'s touch (a graft boundary), the new prints boundary (…) [a0dd872c1 is a shallow graft boundary — its object names parent 9489e2c05 …] and the two provable paths keep their shas with proofs; the summary line is byte-identical (CURRENT … HEAD ceb6b5fb46), both exit 0, the checkout still shallow.
  • Gates 29 / 29 / 0 / 0 by --ran on the head (the battery is not derived for this file — none run, none owed); ESLint clean. Reverse verification: the self-test's firing control — the same hook path prints its TRUE sha on a complete clone of the same fixture, boundary on the depth-5 clone; STALE and UNDECIDED branches pinned byte for byte; the no-fetch invariant pinned (.git/shallow md5 unchanged on the live run).

② Semver level

Not applicable — nothing published moves; skip-changeset measured.

③ Boundary flags

open_questions: two, answered here — (1) 「wire the new self-test into CI?」 → C then A: the seat filed #18356 (one run_self_test line in lint.yml's shallow-history collector + its prose; serial behind this PR); not this card's surface. (2) 「keep the raw sha inside the boundary / unprovable reason?」 → A, as built: the defect was the sha in the latest touch X POSITION, which a case now pins empty; the reason sentence needs it to name the graft. One design choice argued on the four axes and CONFIRMED by the seat: print boundary and keep the verdict (the tool's one consumer, SKILL.md :92, reads the verdict; a refusal on every fresh shallow container would answer 「I do not know」 where the verdict is correct, and its only remedy — deepening the shared checkout — is the act the protocol forbids; the loud-refusal instinct is met at the producer: nothing quotable remains in the clause). One seat premise PARTLY refuted: the boundary sha 9b00f9f9 no longer reproduces — the shared checkout was fetched by other seats during the card and the graft moved (af3add16a0dd872c); the mechanism reproduced at every state. Three deviations answered (none against the surface; the before/after taken back to back at the end for comparability — accepted; the earlier state reported too). Out of scope: one card FILED, #18355 (touchIsProvable reports boundary: false for a registered graft whose parent was fetched later — the flag and the reason lie while the refusal stays right; this lane, git-history.mjs, p3); noted, not filed: ~15 scripts/ self-tests CI names nowhere (the gate's population is deliberate). Landing: in-seat once every check on this head is green — ready through the CCR route, auto-merge SQUASH, the enqueue event and the queue ref read, provenance below.

Implemented-by: claude/issue-18330-harness-current-provable-touch
Reviewed-by: session_01HZfg2AwVX191qCizp88gQr

VERDICT: PASS


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

Landing provenance — skills seat, session session_01HZfg2AwVX191qCizp88gQr, 2026-09-16T02:51Z. Non-governed landing (scripts/pm/check-harness-current.mjs only): review of record 5691229321 PASS on head 6b750117909adb1e74ff9319d73d1ce02dc1c5b9, ACCEPT 5691229608 on #18330; every check on that head read green at 2026-09-16T02:50Z (24 success / 11 skipped / running none / failed none; the battery is not derived for this file). The seat flipped the PR ready through POST …/pulls/18352/ccr/ready_for_review (the first attempt answered 503 from the proxy, the retry 200 — the same idempotent call, no other write between) and armed auto-merge SQUASH through PUT …/pulls/18352/ccr/auto_merge (the echo is not the reading); the ready_for_review event reads 2026-09-16T02:50Z and the added_to_merge_queue event two seconds later, both by os-zhuang — the proxy's write identity since 01:53Z (#18350); the queue ref pr-18352-* read 1 fifteen seconds after the enqueue. Landing is confirmed by the three readings (merged_at + git log origin/main carrying (#18352) single-parent + the queue ref gone) at the next wake; then #18330's residue is stripped and the landing record posted; #18356 (the self-test's CI wiring) becomes dispatchable behind it.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants