Repository navigation
Commit 684146b
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
0 commit comments