Skip to content

Commit 684146b

Browse files
fix(pm): check-harness-current watches the skills tree, and compares content as well as placement (#18610)
Part of #18544 — this PR is the TOOL half only. The card stays open for the charter half. Clause-②: no ## What moved `scripts/pm/check-harness-current.mjs` only. Its header declares the question it answers — "is every harness-loaded file on `origin/main` already in the shared (primary) checkout's HEAD?" — while `PATHS` enumerated three paths and left out `.claude/skills/**`, which the harness loads the same way and never reloads. Two additions, both strictly widening: 1. **`.claude/skills/**` joins the watched population.** The card's blind spot, closed in the direction the card names: the predicate's population catches up to the population it claims to guard. ⛔ Nothing was narrowed or deleted to obtain a green verdict. 2. **A second reading per path — CONTENT, not just placement.** The placement reading asks "is the commit that last touched this path on the ref an ancestor of the shared HEAD?", and a seat's round-open marker asks "has that sha moved since my last marker?". Both are blind to the same case: a checkout that was ALREADY behind when the seat sat down. The touch sha is then identical from one marker to the next — nothing moved, because the thing that is wrong never moves. The new reading compares the bytes directly, needs no history at all, and refuses (UNDECIDED) rather than reporting "identical" when the comparison cannot be made. A path is STALE if EITHER reading places it behind, counted once per path. ## The spelling was measured, not assumed Every `PATHS` entry is a git pathspec. On this tree the three candidate spellings are equivalent — each selects the same 9 files and the same `git log -1` sha: | pathspec | `git log -1 origin/main -- SPEC` | files differing HEAD vs origin/main | |---|---|---:| | `.claude/skills/**` | `ab1d35925` | 9 | | `.claude/skills/*` | `ab1d35925` | 9 | | `.claude/skills` | `ab1d35925` | 9 | | **FIRING CONTROL** `.claude/hooks/*` (a term this diff does not move) | `674872a5b` | 2 | Taken on the shared checkout, HEAD `b48abc48a9` vs `origin/main` `e81c4e5f30`. The control fires on the same tree with the same command shape, so the 9 is a reading and not a dead instrument. ## The pre-existing three paths are byte-identical `origin/main`'s copy of the tool and this branch's copy, run back to back against the SAME shared checkout (HEAD `b48abc48a9`), placement lines for the three original paths extracted the same way from each run: ``` before lines: 3 after lines: 3 diff before after -> exit 0, no output md5 5adef83673d48840d4a6374405be751f (before) md5 5adef83673d48840d4a6374405be751f (after) FIRING CONTROL, same extraction, a term this diff DOES move: lines naming `skills` before: 0 after: 2 summary count before: STALE -- 3 after: STALE -- 4 ``` The self-test carries the same proof at fixture level: all 15 pre-existing cases pass unchanged with the widened `PATHS` and the second reading in place. ## Self-test: floor 15 to 26, and it is live 11 new cases. Both directions on a real fixture, the marker-blind case, and the anti-silent-green case: - the watched population places `.claude/skills/**` by name; 4 placement lines and 4 content lines on one run; - **already-stale-at-seating**: two round-open readings of the charter touch sha, taken either side of a ref advance, are IDENTICAL — and the content reading still names the skills path, lists the differing file, exits 1, and counts the path ONCE; - **firing control on that same run**: the three original paths read clean, so the stale verdict is a reading of that path and not a blanket failure; - **the other direction**: a checkout whose skills tree matches `origin/main` reads CURRENT at exit 0, summary byte-identical to the one seats already read; - **the content reading fires alone**: the placement reading passes (the last touch on `origin/main` IS an ancestor of HEAD) while the loaded charter is not `origin/main`'s — still named STALE; - ⛔ a comparison that could not be made is UNDECIDED, never "identical". ## Ablation ledger — 4 legs, each mutate / RED / restore-proven `scripts/ablation-replace.mjs` is not on this base (`e81c4e5f3`), so the same evidence was produced by hand, with an EXIT/INT/TERM trap, absolute paths, before/after occurrence counts on the anchor, the exit code captured before any pipe, and a restore proven against the HEAD blob. | leg | mutation (anchor counts before/after) | self-test | restore | |---|---|---|---| | A1 | drop `.claude/skills/**` from `PATHS` (10 to 9) | **exit 1, 5 FAILED** | hash `9b8c7a933f` == HEAD blob, `git diff HEAD` empty | | A2 | content reading always reports identical (0 to 1) | **exit 1, 2 FAILED** | same | | A3 | an unmakeable comparison reads as identical (`'unreadable'` 1 to 0) | **exit 1, 1 FAILED** | same | | A4 | floor raised to 27, one above the real battery | **exit 1**, names "only 26 case(s) registered" | same | Every leg refused to proceed on an anchor miss, and every leg checked that the post-mutation hash was non-empty and differed from the HEAD blob before reading any verdict — an empty hash reads as FAILURE, not as success. After all four legs: `--self-test` exit 0, all 26 cases passed, working tree clean. ## Gates Derived with `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`, then re-derived after `git fetch origin main` advanced the local `origin/main` to `d93400f42`: the command set is IDENTICAL, 29 families. All 29 run, all exit 0. `check:pm-dispatch-gates` was detached and waited on with `tail --pid`: **1746 cases pass**, 818.2s on this box. `pnpm lint` ran as the full repo union at HEAD `b32fba174`: **6804 files, 0 errors, 0 warnings** — no narrowing to declare. ## Changeset: skip-changeset, measured One criterion: does anything PUBLISHED move? Probe over all 82 `package.json` in the workspace (70 publishable with a `files[]`), asking whether the changed path lands inside any package's shipped content: ``` scripts/pm/check-harness-current.mjs -> shipped by 0 package(s) FIRING CONTROLS, same probe, same run: packages/lint/CHANGELOG.md -> shipped by 1: @objectstack/lint [dist, README.md, CHANGELOG.md] packages/lint/README.md -> shipped by 1: @objectstack/lint [dist, README.md, CHANGELOG.md] packages/spec/src/index.ts -> shipped by 0 (spec ships `dist`, not `src`) ``` The `packages/lint` row is the exact trap the "scripts are exempt" reflex would have walked into; the probe distinguishes it from source that is not shipped. Nothing published moves, so `skip-changeset`. ## Still open on the card The charter half. `.claude/skills/pm-dispatch/SKILL.md:88-92`'s step-2 reading names THREE files while the loaded surface is a DIRECTORY — the same shape as this card's title, a different predicate. That file is a governed surface, it belongs to the `domain:skills` seat, and an open PR is already on it, so it is deliberately untouched here. Hence `Part of`, not a closing keyword. --- _Generated by [Claude Code](https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 21b7c12 commit 684146b

1 file changed

Lines changed: 207 additions & 16 deletions

File tree

0 commit comments

Comments
 (0)