Repository navigation
test(scripts): batch 10a — class-3 floors at the verdict site for four self-tests - #15327
Merged
Merged
Conversation
…self-tests The class-3 shape: the body that REGISTERS cases is not the body that prints the verdict, so the floor is evaluated at the verdict site — the place that prints the green line — with roster, sink and ledger at module scope. Copies the placement PR #15309 settled. - check-osv-exemptions: recipe A over the 17 literal table rows; floor at the verdict site in main()'s --self-test branch. Boolean `passed` converted to a `failures` counter so the floor shares the counted sink (sink/verdict lines only). - typecheck-configs: recipe A over BOTH literal tables under one roster (11 keys, size pin 11); check in the --self-test dispatch block, so the two importers that fold this self-test in never reach it. - check-comment-mask-corpus: concise arrow sink converted to a block-bodied helper calling registerCase(); one hoisted battery, floor 12; check at the verdict site in selfTest(), so the production sweep in main() — which calls runSelfTestCases() too — never reaches it. SELF_TEST_CASE_COUNT and its production read are untouched. - check-workspace-manifest-cycles: Tier B multi-battery, one battery per named section banner (7), floors measured per battery on a run; check at the verdict site in runSelfTest(). Every floor is read off a run with the roster pinned at 9999, never counted from source. No assertion condition, message or argument is changed. Also adds the one ENTRY_BY_HAND row the instrument needs to probe check-workspace-manifest-cycles at all: it defines two self-test-shaped functions and reads NOT MEASURED without it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
baozhoutao
marked this pull request as ready for review
September 4, 2026 11:55
baozhoutao
enabled auto-merge
September 4, 2026 11:56
This was referenced Sep 4, 2026
Merged
This was referenced Sep 18, 2026
akarma-synetal
pushed a commit
to akarma-synetal/framework
that referenced
this pull request
Sep 28, 2026
…E on objectstack-ai#18373) (objectstack-ai#18946) Fixes objectstack-ai#18373 Clause-②: no `skip-changeset` — measured, not asserted; see Verification below. Executes the maintainer ruling of 2026-09-18 on this card (batch objectstack-ai#153 item 3, **letter E**): retire `check-type-source-resolution`. This PR is EXECUTION — it does not re-argue A/B/C/D. ## What the ruling ordered, and where each piece landed | the ruling's words | landed as | |:--|:--| | delete `scripts/check-type-source-resolution.mjs` and its self-test | file deleted. Its "self-test" was the file's OWN `--self-test` dispatch, not a separate file, so it went with it (`git ls-files` matched exactly one path for the name). | | `KNOWN_DIST_RESOLVED_TYPE_IMPORTS` with it | that registry lived inside the deleted file; the identifier now has **0** occurrences anywhere in the tree. | | the `check:type-source-resolution` entry in the root `package.json` | removed (one line). | | the 「Type-source resolution gate」 step in `.github/workflows/lint.yml` | step removed, together with the 23-line comment block that exists only to explain it. | | `AGENTS.md` and any doc that names the gate as a standing check | **`AGENTS.md` names it zero times — re-measured here, see §1. This diff does not touch the governed surface.** | | `docs/audits/gate-census-2026-09.md:215` verdict | rewritten to the ruling's exact text, see §2. | | PR objectstack-ai#18708 | not touched. | | `check:test-source-alias` (the vitest-axis sibling) | not touched, and its ledger is not touched. | ## 1. `AGENTS.md`: the ruling's sentence describes a sentence that does not exist Re-measured independently of the dispatch, whitespace-**flattened** first so wrapped prose cannot give a false zero, every zero paired with a control drawn from the same flattened population: ``` type-source-resolution 0 check:test-source-alias 1 (control, hits) Type-source resolution 0 check: 47 (control, hits) type source resolution 0 test-source-alias 1 (control, hits) TYPE SOURCE RESOLUTION 0 KNOWN_DIST_RESOLVED 0 check-type-source-resolution 0 file 78,857 bytes / flattened 76,881 bytes ``` My reading **agrees with the dispatch's**. So the ruling's `AGENTS.md` clause has no referent, no line was hunted for there, and `AGENTS.md` / `CLAUDE.md` / `.claude/**` / `skills/**` / `docs/adr/**` are all absent from this diff. ## 2. The two censuses — deliberately different acts **`docs/audits/gate-census-2026-09.md` — verdict REWRITTEN.** Its verdict column is a forward-looking *disposition* (what should happen to the gate), which is exactly what a later ruling can override. The row's verdict now reads `retire · maintainer ruling 2026-09-18 on objectstack-ai#18373`, the ruling's own spelling. Because that is a NEW verdict spelling, the document's own verdict-count table was kept arithmetically true in the same edit: `keep` 133 to 132, a new row for the new spelling at 1, `retire (all spellings)` 59 to 60, `keep (all spellings)` 150 to 149. The union still sums to 225 rows. Nothing else on the row moved — class, contract, blast radius and the measured catch window are what the census measured, and this PR did not re-measure them. **`docs/audits/2026-09-self-test-shape-census.md:341` — deliberately LEFT ALONE.** The dispatch flagged it as a second carrier the ruling did not name; it holds a `ROSTER | HELD` row for this gate. It gets nothing, for a reason, not by omission: - That document's header pins it to a tree — `origin/main` at `d30ccb9bd`, re-verified at `1be26b0de`. Its rows are not dispositions; each one is **the result of a behavioural probe run against that sha**. Retiring the gate today does not make "at `d30ccb9bd` this script's self-test exited non-zero when it ran zero cases" untrue. - **Deleting** the row would break the document's own arithmetic — 179 total, 165 HELD, 4 DEFEATED, 1 ACCIDENT, 9 NOT MEASURED — and with it the whole reconciliation the document exists to perform against objectstack-ai#15410's competing count of 170. A record you can subtract rows from is not a record. - **Rewriting** the verdict would assert a measurement nobody took. Rule applied, and the same rule decides every prose carrier below: **a sentence that makes a present-tense claim about the gate acting is now false and is repaired; a sentence recording a past measurement or why a past change happened is not.** ## 3. The hard coupling: `check:ratchet-remedy-authority`, measured before and after That gate keeps a hand-classified control corpus keyed on gate FILENAME, and its self-test asserts the sweep reaches every entry. Both legs, run from this worktree: | leg | `--self-test` | main run | |:--|:--|:--| | **before** any change (at `02bdeaaf2`) | exit **0** | exit **0** — 257 scripts swept, 15 marked, 6 refused, control corpus 31 | | **after deleting the file only** | exit **1** — `the sweep still REACHES every known instance; it no longer reaches: check-type-source-resolution.mjs` | exit **1** — `STALE: the control corpus ... covers scripts/check-type-source-resolution.mjs, which is no longer in the corpus. Drop the entry, or restore the file.` | | **after the repair in this PR** | exit **0** | exit **0** — 256 scripts swept, 15 marked, 5 refused, control corpus 30 | **The repair is the gate's own prescribed remedy, and no floor moved.** What that gate pins is `SELF_TEST_BATTERIES` — a roster of battery NAMES with a per-battery count floor and a pinned roster SIZE, and its own comment at the roster says deleting an entry silences a floor as effectively as zeroing it. That roster is a **different registry** from the control corpus, and it is untouched in substance: ``` declared batteries: 21 SELF_TEST_BATTERY_FLOOR: 21 sum of counts: 30 battery (12) count: 1 (unchanged) ``` The control corpus (`CONTROL`) has no pinned size — the gate prints `Object.keys(CONTROL).length` — and its STALE branch names dropping the entry as the fix. 257 to 256 swept, 6 to 5 refused and 31 to 30 classified are the mechanical consequence of one file leaving the corpus, not a weakened floor. Three further carriers in that same file, each judged by the rule in §2: - `:16` "The precedents are ..." — present tense, names four files a reader is told to open. The dead name is dropped; the other three stay. - `:1221` the author-facing remedy "turn it down outright the way `check-type-source-resolution.mjs` does" — present tense, and after this PR it points an author at a file that does not exist. The exemplar is swapped to `check-test-source-alias.mjs`, the co-precedent of the identical PREDICATION shape that this same file already names at `:16` and in battery (12). ⛔ This names that gate; it does not touch it or its ledger. - battery (12)'s label and its assertion text ("the shape the two registry gates use") — present tense, now one gate. Label renamed, assertion reworded. Roster size and the battery's own count are unchanged, so nothing is unpinned. - `:662` "…which turned check-type-source-resolution's CORRECT remedy into a reported violation" — a record of a measurement that was taken and rejected. **Historical: kept.** ## 4. The coupling the dispatch did not name: `check-type-check-coverage.mjs` Found by re-measuring rather than by the brief. That gate's **live, author-facing** TEST_DEBT graduation remedy told an author route (b) was "Available ONLY while `pnpm check:type-source-resolution` still passes with the tests re-admitted ... Run it before you commit". After this PR that is a command that does not exist, in a message whose whole job is to tell an author which of two routes is open. Repaired so it keeps the WARNING and loses the dead instruction: it now records that the gate that decided the route was retired under this ruling, that its silence is ⛔ not a clearance, that what it measured has not changed (the re-admitted tests import workspace packages the src program never held; it read red on 14 of the 18 entries with an exclusion to drop), and that (a) is the route to prefer. **⛔ The self-test that pins that message is NOT weakened.** Its `present` needles (`check:type-source-resolution`, `SHRINK-ONLY`, `tsconfig.test.json`) and the sibling FUTURE_DEBT case's `absent` needles are left **byte-identical** — the rewritten message still carries all three, because it names the retired gate and its former registry explicitly. Only the case LABEL and its explanatory `why` changed. `pnpm check:type-check-coverage` exits **0** after the edit. The other five mentions in that file (`:934`, `:986`, `:1099`, `:4462`, and the `:537` / `:5629` provenance notes) are records of measurements — "MEASURED as a red `main`", "SINCE MEASURED ... by dropping each entry's exclusion and reading `check:type-source-resolution`", "measured by doing it". Under the §2 rule the measurements are kept; the two that also made a present-tense claim about a live consumer (`:537`, `:5629`) now say the gate was retired. ## 5. The other repo-root tooling carriers - `scripts/typecheck-configs.mjs` — this library existed *because* two gates needed the same predicate. One is gone. Its self-test does **not** assert a consumer set (checked: no consumer array, only prose), so nothing reds; but "Two gates need this predicate", "both consumers resolve", "the two callers" and ":201 `check-type-source-resolution.mjs` imports the predicates" were all present-tense and false. Repaired to name the one live consumer and record the retirement. ⛔ Folding the module back into its remaining caller is explicitly left as a separate decision — its cases are floored in its own dispatch (PR objectstack-ai#15327) and a fold-in would not inherit that floor. - `scripts/check-undeclared-dep-imports.mjs:42` — "the two gates that look adjacent" is now one. - `scripts/workspace-enumerator.mjs:66` — the `WORKSPACE_PARENT_GLOBS` declaration list named the deleted file; it now names the live one and records where the other went. - `scripts/pm/dispatch-gates.mjs` — five mentions, **all left alone**: every one is a recorded measurement in a docblock (pair counts of a matcher variant that was measured and refused). Historical under the §2 rule. The tool derives its families from `package.json` and the workflows at run time, so the retired gate simply leaves its output; it needs no edit and reds nothing. - `scripts/pm/check-clause2-carriers.mjs:8209` / `:8250` — **verified offline before deciding, and left alone.** The record is a frozen inline array of comment bodies passed `headSha: 'offline'`; nothing in it resolves a remote ref, and the two mentions are branch names inside a historical claim-contest fixture about this card, unrelated to the gate. - `scripts/typecheck-configs.mjs:202`'s stale comment about its importer — see above; that is the comment the dispatch flagged as pointing the other way. ## 6. Out of scope, on purpose - ⛔ **`packages/*/CHANGELOG.md` (five files) — untouched.** `AGENTS.md:686` is unconditional: a factual error in a released entry is repaired in a dedicated docs-only PR, ⛔ never as a rider on code changes. They are also *correct* as historical records of what those releases did. Same for `content/docs/releases/**` (which names it zero times anyway). - **About 30 prose carriers in `packages/**/tsconfig*.json` comments, test docblocks, `packages/cli/bin/run-dev.js` and `examples/*/tsconfig.json` — untouched, and reported to the PM as a residual.** Boundary applied: the ruling scoped this diff itself when it moved the lane to `domain:devx` 「the diff is repo-root tooling, `package.json` and the lint workflow」. Editing those comments would pull roughly 18 packages and 3 examples into the changeset, change the diff's lane, and multiply the derived gate set — for comments that mostly explain *why a `paths` rule exists*, a reason that outlives the gate. ## 7. The workflow step removal leaves the required context intact Measured, not asserted. The required context is the JOB's `name:`, and no context name is derived from a step: ``` BASE 02bdeaa : lint job `name:` = Lint & Repo Gates steps = 179 (step present) HEAD : lint job `name:` = Lint & Repo Gates steps = 178 (step absent) ``` The job keeps 178 other steps and its name is byte-identical, so the six required contexts are unchanged. `pnpm check:required-contexts` exits 0.⚠️ One wording note for the record: the ruling writes the job as 「Lint and Repo Gates」; the job's actual `name:` is `Lint & Repo Gates` (ampersand). Same job, and the ruling's conclusion holds. ## 8. `skip-changeset`, measured Criterion: nothing already published moves. Measured against every workspace manifest's `files[]`, with a positive control proving the reader works rather than merely reporting zeros. ``` changed paths (9) files[] reaches .github/workflows/lint.yml NONE docs/audits/gate-census-2026-09.md NONE package.json (private:true) NONE scripts/check-ratchet-remedy-authority.mjs NONE scripts/check-type-check-coverage.mjs NONE scripts/check-type-source-resolution.mjs NONE (deleted) scripts/check-undeclared-dep-imports.mjs NONE scripts/typecheck-configs.mjs NONE scripts/workspace-enumerator.mjs NONE POSITIVE CONTROL — must be reported as reached packages/spec/src/data/query.zod.ts @objectstack/spec (glob entry) packages/cli/dist/index.js @objectstack/cli (directory entry) packages/spec/CHANGELOG.md @objectstack/spec (literal entry) ``` 3 of 3 controls hit, across two packages and all three `files[]` entry kinds, so the zeros above are readings and not an empty read. The root `package.json` is `private: true` and is never published at all. ## 9. Verification Gate set derived in-worktree with `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` (no paths passed — the tool takes its own change set from the merge base), then run. Union taken at `13b2b68ef`, the final commit. - **69 of 69 derived commands run. 63 exit 0.** - **6 exit 3 = `PREREQUISITE NOT MET`, NOT MEASURED, declared to CI**: `check:dts-closure`, `check:dual-build-cjs-loads`, `check:lean-entry-closure`, `check:sourcemap-no-sources-content`, `check:type-check-debt` and `@objectstack/lint check:doc-formula-expressions`. Every one of them refuses because this worktree has no build; each prints its own "this is NOT a pass" line and exits 3 rather than 1. They are derived from the root `package.json` edit, and they read the `dist/` of packages this diff does not touch — this diff changes no package source, so their verdict cannot depend on it. CI's build lanes measure them. - `pnpm lint` (`eslint . --no-inline-config`, the whole repo, no narrowing) — exit **0**. - `pnpm check:ratchet-remedy-authority` — exit 0, before/after table in §3. - `pnpm check:type-check-coverage` — exit 0. - `pnpm check:pm-dispatch-gates` — exit **0**, `dispatch-gates self-test: 1848 cases pass` (976.3s on this box; run on its own because it does not fit a ten-minute foreground window). - `pnpm check:required-contexts`, `check:step-collectors`, `check:self-test-wired`, `check:self-test-workflow-commands`, `check:aggregator-roster`, `check:scripts-symbol-anchors`, `check:declaration-mirrors`, `check:ci-filter-parity`, `check:nul-bytes`, `check:workflow-step-name-quoting` — all exit 0. - Control-byte self-scan over every changed file (`grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'`) — clean. -⚠️ `dispatch-gates` prints its own warning that `--commands` is **not** a complete account of CI; the artifact-roster, wide-population, workflow-valued and path-scheduled CI families are outside that list by construction. -⚠️ `dispatch-gates` also reported a STALE TREE note: `origin/main` moved 3 commits after this branch point and `scripts/pm/check-widening-tells.mjs` changed there. The derivation itself uses three-dot merge-base semantics, so the change set above is correct; the note affects only that one family's shape. No path of this diff overlaps it. ## 10. Serial constraint with two in-flight PRs Both **objectstack-ai#18889** (draft) and **objectstack-ai#18414** (open, non-draft) also edit `.github/workflows/lint.yml` and the root `package.json`. Re-checked immediately before pushing: **both are still open and unmerged**, so neither had landed under this branch. This diff is written to survive either landing first — ⛔ no line number was used as a reading: - the workflow step is located by **its own name**, and the edit asserted the literal text of `- name: Type-source resolution gate`, its `run:` line and the first line of its comment block before removing anything; a shifted file fails the assertion instead of deleting the wrong step. - the `package.json` entry is matched as a **unique exact string**, never by offset. The ruling's `.github/workflows/lint.yml:4187` and the dispatch's `package.json:172` were both treated as clues; both happened to still be correct at `02bdeaaf2`, but nothing here depends on that. Also re-measured against a freshly fetched `origin/main` (`46559f61c`, five commits past this branch point): **none of those five commits touches any of this diff's nine paths**, so no merge was needed and no line re-derivation was owed. **objectstack-ai#18708 is closed, unmerged** (2026-09-18T06:37Z) — confirmed here, not assumed. This PR does not touch it. **objectstack-ai#18903** is editing `scripts/pm/check-clause2-carriers.mjs`, the file holding the frozen objectstack-ai#18708 fixture this PR deliberately leaves alone — adjacent, not overlapping. ## Acceptance notes - Noted, not filed: the gate census's inventory counts (182 check files, 225 rows) are pinned to the census's own tree and were deliberately not re-derived — only the verdict column and its roll-up were touched. Carrier for a future re-derivation: whoever executes the next batch of the 58 remaining `retire` rows. - Noted, not filed: `docs/audits/gate-census-2026-09.md` now carries a verdict spelling (`retire · maintainer ruling ...`) that no other row uses, where the existing convention for a ruling-driven retirement is the verdict `retire (ruled)` plus `ruled retire: #NNNNN X` in column 3. The ruling's literal text was followed rather than the convention. --- _Generated by [Claude Code](https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk)_ --- _Generated by [Claude Code](https://claude.ai/code)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #13799
Part of #14842
Batch 10a: the four remaining class-3 self-tests — the shape where the body that
REGISTERS cases is not the body that prints the verdict. Copies the placement PR #15309
settled: roster, sink and ledger at module scope, and the FLOOR CHECK evaluated at the
verdict site, on a path reached only from
--self-test.Floors are measured on a run (roster pinned at 9999, read off the breach line), never
counted from source. No assertion condition, message or argument is changed.
The four files
scripts/check-osv-exemptions.mjsmain()'s--self-testbranchscripts/typecheck-configs.mjs--self-testdispatch blockscripts/check-comment-mask-corpus.mjsselfTest()scripts/check-workspace-manifest-cycles.mjsrunSelfTest()registerCase()is the FIRST statement of each driving loop body (recipe A) or of thefile's own case sink (b3/b5/Tier B). Each handshake is kept exactly as it landed — two
selfTestReachedVerdictflags, twoSELF_TEST_VERDICTsentinels. Handshake and floor stayorthogonal.
Roster cross-checked against the source both ways, by this branch:
check-osv-exemptions17 roster keys vs 17name:rows, 0 duplicates either side, emptydifference both directions;
typecheck-configs11 vs 11, same;check-workspace-manifest-cycles7 roster keys vs 7
battery()openers, and each opener's string is byte-equal to the bannerabove it (⛔ no comment was promoted to a section head — the seven names are the seven
banners the file already had).
Two library scopings, proven rather than asserted
typecheck-configsis a library. ItsselfTest()is folded intocheck-type-check-coverage.mjsand its predicates are imported bycheck-type-source-resolution.mjs. Those importers callselfTest(), which registers intothe module ledger — but the FLOOR lives in this file's own
--self-testdispatch, which animporter never reaches. Neither importer is edited.
check-comment-mask-corpus's production path callsrunSelfTestCases()on every sweep.The floor is in
selfTest(), which the sweep never calls.SELF_TEST_CASE_COUNTand itsproduction read are untouched; the roster does not replace it.
Deletions — sink/verdict lines only, declared
8 deleted lines in total, in two files; the other three add only.
check-comment-mask-corpus— 1: the concise arrow sinkok = (label, cond) => cases.push(...),replaced by the block-bodied helper that calls
registerCase()and then pushes the same object(the b3 conversion, PR test(scripts): give six more self-tests a battery roster and floor (#13799 batch 3) #15156's shape).
check-osv-exemptions— 7, the boolean→counter conversion 8b landed oncheck-override-consistency:let passed = true,if (!ok) passed = false,return { passed, lines },the
@returnsJSDoc,const { passed, lines } = …,if (!passed) {, and the old red verdict line.The red run now prints the uniform
N failure(s) (cases and floor); the GREEN line is untouched."after the existing failures branch and immediately before the success line". In
check-osv-exemptionsthe same dispatch also ordered the boolean→counter conversion so the floorshares the counted sink — and those two cannot both hold, because a shared sink means ONE branch,
not one after another. The counter conversion won (it is the per-file instruction, with a named
precedent); the floor is still immediately before the success line. The other three files have a
separate floor branch after the existing failures branch, exactly as the pilot does.
The instrument row (
Part of #14842)node scripts/measure-self-test-floor.mjs --probestill readsscripts/check-workspace-manifest-cycles.mjsas NOT MEASURED (ambiguous entry (selfTest,runSelfTest) and no ENTRY_BY_HAND row) on this pin — checked before editing, so the row #14842
prescribes is still needed. Added as one line (plus a three-line reason). With it, the probe reads:
{"verdict":"HELD","entry":"runSelfTest","baselineExit":0,"mutatedExit":1,"mutatedBytes":220, "mutatedHead":"✗ check-workspace-manifest-cycles self-test: runSelfTest() returned without reaching its verdict,"}Ablations — 18 legs across the split, mutation AND restore proven on disk
Every leg: the mutation is proven by counting the text it was anchored on (removed count → 0,
injected count ≥ 1) and the blob hash moving; the restore is
git checkout HEAD --anABSOLUTE path in a
finally(with SIGTERM/SIGINT handlers, so a cap kill cannot leave a mutatedtree), proven by
git hash-objectequalling the HEAD blob and an emptygit diff HEAD— anempty hash is read as FAILURE, not as "nothing to compare". All 18 restores passed; the tree is
clean. These are plain
.mjsscripts executed from source with nodist, so no rebuild legapplies — stated rather than skipped.
registerCase()removedOK -- 11 cases holdAll 12 … passedall cases passedreturnin the registering body⭐ (d) came out in two directions, and both are reported as observed rather than as the template
predicted. Where the handshake flag is set on the last line of the registering body
(
check-osv-exemptions,typecheck-configs), an early return trips the handshake before thefloor is ever consulted — the two holes catching the same defect at different depths, which is what
orthogonal looks like in practice. For those two an extra leg (d2) injects a skip guard into
the driving loop instead — the "a guard that now skips" defect the floor's own remedy text names —
and it lands as exactly one battery DID NOT RUN with every other case green, count below floor.
Where the handshake sits on the deciding body (
check-comment-mask-corpus,check-workspace-manifest-cycles), (d) reaches the floor as designed; inmanifest-cyclesthe setdifference names the four banners that stopped and leaves the three that ran at their floors.
Byte comparison vs the installed base
A second worktree detached at the same pin
103677652,pnpm installexit 0 (an uninstalled basewould be exit 3 = NOT MEASURED, not a reading). Both modes, stdout and stderr compared separately
with
cmp:check-osv-exemptions--self-test/ normaltypecheck-configs--self-test/ normalcheck-comment-mask-corpus--self-testcheck-comment-mask-corpuscheck-workspace-manifest-cycles--self-test/ normalcheck-type-source-resolution(importer)--self-test/ normalcheck-type-check-coverage(importer, foldstypecheck-configs)--self-test/ normalThe one varying line, proven to vary base-against-base. The corpus sweep prints its own
elapsed time. Branch 58.9s vs base 56.4s — and a second run of the BASE tree against the first
gives 63.7s vs 56.4s, so the field varies with nothing changed at all. Every other byte of that
line is equal across all three runs (
5889 files, 0 disagree, 0 unparseable,comparator self-test: 12 cases pass), and masking the seconds makes base and branchbyte-identical.
Both importers of
typecheck-configsare byte-identical in both modes, in both directions —that is the proof that the floor is scoped to this file's own dispatch and cannot fire inside a
fold-in. Neither importer is edited.
check-type-check-coverage --self-teststill reports its sixfamilies (
48 + 68 + 45 + 28 + 19 + 18) unchanged.to
os-verify-lock.shas parts joined with;, so the lock's own line saysVERDICT batch-last-exit 0 · ⚠ NOT A VERDICT ON THE WHOLE COMMAND. It is right to say so: that 0covers only the last part. The evidence here is not that number — each of the nine runs printed and
captured its own exit code (
TCCST_W=0 TCCST_B=0 TCCN_W=0 TCCN_B=0 CMN_W=0 CMN_B=0 CMN_B2=0 TSRN_W=0 TSRN_B=0), and those are what is reported. Thepnpm check:pm-dispatch-gatesrun was asingle command and its line reads a real
VERDICT command-exit 0.Instrument before/after
node scripts/measure-self-test-floor.mjs --json, run in each tree, exit 0, 170 rows both times:103677652NONE drops by exactly 4 —
check-comment-mask-corpus,check-osv-exemptions,check-workspace-manifest-cycles,typecheck-configs— and nothing entered NONE. Thesymmetric difference between the set that left and this batch's worklist is empty.
extractWatchHints(imported fromscripts/pm/dispatch-gates.mjs), computed in both trees:identical on all four target files. The fifth edited file,
measure-self-test-floor.mjs,gains exactly one hint —
scripts/check-workspace-manifest-cycles.mjs, the path its new rownames, which is the point of the row.
pnpm check:watch-hint-literalexit 0.Gates
Exit codes captured by redirect BEFORE any pipe throughout (
cmd > out 2>&1; ec=$?), and eachresult is quoted from the gate's own verdict line, never from a bare
$?.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack(no hand-built path list — the script takes its own change set from the merge base; it reports
5 paths, committed 5 / working tree 0 / untracked 0): 26 commands, 26 exit 0.
pnpm check:pm-dispatch-gatesin the foreground underscripts/pm/os-verify-lock.sh—✓ dispatch-gates self-test: 1381 cases pass., lock VERDICTcommand-exit 0 · held 367s · waited 160s;check-self-test-workflow-commands.mjsand its--self-test;check:declared-population-live;check-self-test-wired.mjsand its--self-test;check:ratchet-remedy-authority;check:nul-bytes;check:watch-hint-literal.--self-test, all exit 0:node scripts/check-osv-exemptions.mjs×2 (validate-deps.yml runs exactly these two — there isno
check:osv-exemptionspackage script),pnpm check:workspace-manifest-cycles,pnpm check:type-source-resolution,pnpm check:type-check-coverage,node scripts/check-comment-mask-corpus.mjs,node scripts/typecheck-configs.mjs --self-test.pnpm lint(eslint . --no-inline-config) exit 0 — the full farm, no narrowingclaimed and none needed.
scripts/measure-self-test-floor.mjsships no--self-test(its controls run inline on everyinvocation) and no test file in the tree names it, so running the instrument IS its own suite:
exit 0 in both trees.
Control-byte scan (
grep -naPover the five edited files and over every body posted for thisbatch): no hits.
Classification (measurement only, no edit)
scripts/audits/14744-before-update-per-row-value-census.mjs— its census row is in the reportcomment on #13799. Headline: recipe A, 10 literal table rows, no handshake in any of the
three landed spellings, verdict INSIDE the body (so not class-3), a derived
SELF_TEST_CASES.lengthnothing compares, 0 banners, and zero CI wiring — no package.jsonscript, no workflow mention. Measuring it also turned up an instrument defect, filed as #15324:
the probe awards
HELDon a non-zero exit code alone, and this file exits 1 printing zero byteson an early return, so a file with no handshake at all scores
HELD.🤖 Generated with Claude Code
https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
Generated by Claude Code