Repository navigation
test(cli): read the emitJson exit count off the source in the two os validate --json pins - #18880
Merged
os-support-ai merged 1 commit intoSep 18, 2026
Conversation
…os validate --json` pins `validate.ts` has SEVEN `await emitJson(` exits; both nightly-only pins asserted SIX, so `main`'s nightly tier has been red since the seventh exit landed with #18769 — with no run able to say so, because these files are nightly-tier by NAME and a `packages/cli/**` diff never triggers that workflow. Both CONTRACTS the two files exist for still hold: every one of the seven exits carries `warnings` AND `conversions`. Only the COUNT was stale. So the integer is not re-pinned to 7 — that re-arms the identical trap for exit eight, and only a cron would ever read it. It is derived instead: the extractor must produce one payload literal per `emitJson` call site the file actually has, whatever today's number is. That is strictly stronger than an integer — it also catches a call site the extractor CANNOT see (one spelled without `await`), which a hard-coded count reads as green. The one integer left is demoted from an equality to a floor (six, the population the #12047 / #12125 rulings were made over). It rots only in the direction that has to be reviewed anyway — exits being removed — and it floors the derived pair away from the single vacuum they share, an `emitJson` renamed out of existence taking both sides to zero. Nothing is skipped, disabled or deleted: the count assertion, the success/failure partition and the contract negative are all still there. `validate.ts` is untouched. Measured on this branch, `packages/cli`: OS_TEST_TIERS unset 266 files collected, ZERO of them these two OS_TEST_TIERS=nightly 68 files collected, both of them present Claude-Session: https://claude.ai/code/session_01DvvamiacK328idtBYJBxV3 Co-authored-by: Claude <noreply@anthropic.com>
Contributor
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs. What this run could not see
Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
os-support-ai
marked this pull request as ready for review
September 18, 2026 04:32
os-support-ai
enabled auto-merge
September 18, 2026 04:32
This was referenced Sep 18, 2026
os-support-ai
deleted the
claude/issue-18848-validate-emitjson-exit-count-pins
branch
September 18, 2026 04:55
os-support-ai
pushed a commit
that referenced
this pull request
Sep 18, 2026
… so an honest new exit cannot red `main` at night
`build-json-failure-{warnings,conversions}.e2e.test.ts` each froze three
integers read off `packages/cli/src/commands/compile.ts` — 11 payload
literals, 10 `success: false`, 1 `success: true`. All six were correct; the
defect is the shape. Both files are nightly-tier by name, so the pull request
that adds an honest twelfth exit cannot collect them (measured: `OS_TEST_TIERS`
unset collects 267 files in this package with zero of these two among them,
`=nightly` collects 68 with both), merges green, and leaves `main` red until a
cron says so — the #18848 incident, pre-staged.
Ported from the shape PR #18880 landed on the `validate-json-failure-*` pair:
the count is derived (`toHaveLength(callSites.length)` against a word-boundary
`emitJson` call-site match over the same masked source the extractor reads),
the old integer is demoted to a `toBeGreaterThanOrEqual(10)` floor that rots
only in the exits-are-removed direction, and one partition assertion
(`success: true` ×1, `success: false` = `literals.length - 1`) replaces the two
frozen counts.
The verdict key was re-derived rather than copied: `compile.ts` spells it
`success:`, not the `valid:` of `validate.ts` — measured over the 11 masked
payload literals, `success: false` 10 / `success: true` 1 / `valid:` 0.
Claude-Session: https://claude.ai/code/session_01DvvamiacK328idtBYJBxV3
Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal
pushed a commit
to akarma-synetal/framework
that referenced
this pull request
Sep 28, 2026
… so an honest new exit cannot red `main` at night (objectstack-ai#18966) Fixes objectstack-ai#18894 Clause-②: no ## What this changes `packages/cli/test/build-json-failure-warnings.e2e.test.ts` and `packages/cli/test/build-json-failure-conversions.e2e.test.ts` each froze three integers read off `packages/cli/src/commands/compile.ts` — 11 payload literals, 10 `success: false`, 1 `success: true`. **All six were correct**, and that is the defect: the *shape*, not a stale number. One honest new exit — the very thing these two files exist to enforce — turns all six red, and because both files are nightly-tier by NAME they turn red only at night, hours after the PR that did it has merged. That is objectstack-ai#18848's `priority:p1` pre-staged on `compile.ts`. Ported from the shape PR objectstack-ai#18880 landed on the sibling `validate-json-failure-*` pair: - the count is **derived** — `toHaveLength(callSites.length)` against a word-boundary `emitJson` call-site match over **the same masked source** the payload extractor reads; - the old integer is demoted to a **floor**, `toBeGreaterThanOrEqual(10)`, which rots only in the exits-are-REMOVED direction; - one **partition** assertion (`success: true` ×1, `success: false` = `literals.length - 1`) replaces the two frozen counts. ⛔ No production file is touched. The diff is those two test files and nothing else — `compile.ts` is card objectstack-ai#18431's carrier (branch `ccdc9f5389`) and is left alone. ## Premises, re-measured on `origin/main` before a line was written Re-derived with the tests' OWN extractor against the masked `compile.ts` at `f112a740bd` (`origin/main` at branch point), ⛔ not inherited from the card: ``` payload literals 11 the pins' 11 was correct success: false 10 correct success: true 1 correct /\bemitJson\s*\(/g 11 symmetric with the extractor ``` **Collection, re-measured in this worktree** (`vitest list --filesOnly`, `packages/cli`): `OS_TEST_TIERS` unset ⇒ 267 files, **0** of these two among them, lit control `artifact-packages.test.ts` present; `=nightly` ⇒ 68 files, **both** present, lit control absent. Both files sit in the `integration` project (`--project unit` collects 0 of them). ##⚠️ The trap this card names — the verdict key, MEASURED not copied **`compile.ts` spells its verdict key `success:`. `validate.ts` spells it `valid:`.** Measured over the 11 masked payload literals of `compile.ts`: | needle | count | |:--|--:| | `success: false` | 10 | | `success: true` | 1 | | `valid: false` | **0** | | `valid: true` | **0** | A verbatim port of objectstack-ai#18880's two partition lines would have asserted over an **empty population**. The lines here read `success:`, and the reading is recorded in the code comment beside them so the next author does not have to re-derive it. ## The symmetry the derived form needs — every `emitJson` occurrence enumerated The looser `/\bemitJson\s*\(/g` can only be trusted equal to the extractor's `await emitJson(` needle if nothing else in the file matches it. Enumerated with left context on `compile.ts`, **13 raw occurrences**: | where | reading | |:--|:--| | `:43` | `emitJson,` — an **import** from `../utils/format.js`. No paren ⇒ matches neither side. | | `:104`, `:694` | prose inside comments — the shared `maskComments` blanks both (objectstack-ai#18520, applied to these two files by objectstack-ai#18924) | | the other 10 | `await emitJson(` call sites, plus the multi-line ones ⇒ 11 payload literals | ⭐ `emitJson` is **IMPORTED here, never declared** — there is no `function emitJson(` in `compile.ts` (grep: zero hits for `function emitJson` / `const emitJson`), so the looser pattern cannot over-count and red the pin by construction. Raw and masked agree: 11 literals, 11 call sites, both ways. That agreement is a **reading, not a law**, and the derived equality is exactly where a future file that broke it would report. ## The floor's anchor — 10, and why not 11 objectstack-ai#18880 chose "the population the governing ruling was made over", not today's count. The equivalent anchor here is the commit that landed each file's ruling, read out of git: | file | ruling | landed by | count pinned that day | |:--|:--|:--|--:| | `build-json-failure-warnings.e2e.test.ts` | maintainer, 2026-08-25, option 1 (objectstack-ai#11772) | `d114d5e140` (objectstack-ai#12079) | `toHaveLength(10)` — 9 failure + 1 success | | `build-json-failure-conversions.e2e.test.ts` | the same 2026-08-25 ruling applied to `conversions` (objectstack-ai#12125) | `79cf692b0e` (objectstack-ai#12285) | `toHaveLength(10)` — "all nine of its failure exits" + 1 | Control for the anchor rule: the sibling `validate-json-failure-warnings.e2e.test.ts` was created at `33e81a5fe0` (objectstack-ai#12130) pinning `toHaveLength(6)`, and objectstack-ai#18880's floor is `6`. Same rule, same arithmetic. ⇒ **the floor here is 10.** Today's eleventh exit is ADR-0130 D4's per-package author-time rule leg (objectstack-ai#14439), which arrived *after* the ruling — exactly what a derived count absorbs and a frozen one trips over. ## Ablation battery — every leg's mutation proven on disk, every restore proven by hash Harness: a bash trap on EXIT, INT and TERM whose handler is the restore function, absolute paths, restore is `git checkout HEAD -- PATH` (never a bare `git checkout --`), verified by comparing `git hash-object` against the HEAD blob hash **and** by `git diff HEAD` being empty. Each leg prints the extractor's counts BEFORE and AFTER the mutation and a marker grep, so a no-op leg is refused rather than read as green. All runs `OS_TEST_TIERS=nightly`, exit codes captured before any pipe. No rebuild is needed or done: both files read `compile.ts` from disk and the CLI is loaded from `src/` through `bin/run-dev.js`, as each file's own header states. | leg | mutation to `compile.ts` | measured on disk after | THIS branch | the frozen `11/10/1` | |:--|:--|:--|:--|:--| | 0 control | none | literals 11 · sites 11 | **GREEN** 7/7 | — | | A | honest 12th exit carrying **both** keys | literals 12 · sites 12 | **GREEN** 7/7 | **RED** — `expected [ …(12) ] to have a length of 11` (both files) | | B | 12th exit **missing** both keys | literals 12 · sites 12 | **RED** — `an os build --json exit publishes no warnings` / `no conversions` | — | | C | 12th call site spelled **without `await`** | literals 11 · sites **12** | **RED** — `an emitJson( call site the payload extractor could not read: expected [ …(11) ] to have a length of 12` | **GREEN** 7/7 | | D | two exits deleted (truncation) | literals 9 · sites 9 | **RED** — `publishes fewer exits than the ruling above was made over: expected 9 to be greater than or equal to 10` | — | ⭐ **Leg C is the one that decides it.** A twelfth call site the payload extractor cannot read leaves the frozen integer **green** and reddens the derived equality. The frozen form is not a parallel option — it is strictly weaker. Leg A is the mirror: the honest exit this contract exists to welcome now stays green instead of reddening `main` at 20:44Z. The "old" arms of A and C ran the pre-change files restored worktree-only with `git restore --source=f112a740bd -- PATH`, hashes printed and matched against the BASE blobs, then reset with `git checkout HEAD -- PATH`. ## `skip-changeset`, by measurement with controls both ways `packages/cli` `files[]` is `["dist","README.md","CHANGELOG.md"]`; `tsconfig.build.json` has `rootDir: "src"`, `include: ["src"]` and an `exclude` that drops every `*.test.ts`. Measured against the freshly built `packages/cli/dist`: | probe | direction | hits in `dist/` | |:--|:--|--:| | `an emitJson( call site the payload extractor could not read` | new, this diff | **0** | | `publishes fewer exits than the ruling above was made over` | new, this diff | **0** | | `ABLATION` | new, this diff | **0** | | `access matrix drift` | positive control, lives in `src/commands/compile.ts` | 1 | | `warningsSoFar` | positive control | 2 | | `runtime bundle failed` | positive control | 1 | | `build-json-failure` |⚠️ 1 hit — `dist/commands/compile.js:621`, a **comment** compiled from `src/commands/compile.ts:698` that names the test file. Not this diff's content; `compile.ts` is untouched. | 1 | The positive controls prove the grep was reading `dist`. Nothing this diff adds reaches any published path from any released package ⇒ `skip-changeset`, label applied on this PR. ##⚠️ The adjacent axis — a POSITION, not a silent widening Comment 5726117707 on the card asked for a judgement on the byte-exact multi-line spread ORDER pin, and warned its own probe was narrow. **Re-derived here with a different predicate** (`expect(SRC)` / `SRC.match` / `SRC.indexOf` across all four files), which finds MORE than the seat's word probe did — including one in `validate-json-failure-conversions.e2e.test.ts`, where the seat's probe scored 0 and recorded it as **未判**: | file | line | what it binds byte-exactly | |:--|--:|:--| | `build-json-failure-warnings.e2e.test.ts` | `:536` `:537` | `const warningsSoFar = () => [` , and the 4-member spread ORDER | | `build-json-failure-conversions.e2e.test.ts` | `:450` | sink declaration + blank line + `try {` adjacency | | `validate-json-failure-warnings.e2e.test.ts` | `:571` `:572` | the same two, 5 members | | `validate-json-failure-conversions.e2e.test.ts` | `:486` | the same adjacency ⇐ **the seat's 0 was 未判, not absent** | **Judgement: named, measured, and left to the seat — deliberately NOT done in this PR.** Against the lane's standing three-rung ruling (claim 5725386686 on objectstack-ai#18520): - **Rung 1** — 「⛔ nightly-only 的 pin 永不绑一个逐 PR 兄弟已经绑着的字节精确拼写。」 Its precondition is measured **FALSE**. Repo-wide, the only other reader of those four list identifiers is `build-json-advisory-parity.e2e.test.ts`, which is itself **nightly-tier** and compares with `new Set(...)` — order-blind by construction. No per-PR sibling binds this order behaviourally or textually. ⇒ rung 1 does not authorise deleting it. - **Rung 2** — 「⭐ nightly-only 的 pin 绑那条性质本身,从源码推导 —— 读出来的计数、分区、下限 —— ⛔ 永不绑一个写死的数。」 It governs frozen **numbers**. The order pin binds a *spelling*. ⇒ rung 2 does not reach it; this PR discharges rung 2 for the counts, which is this card. - **Rung 3** — 「⭐ 一个读原始源码文本的读者,要么能把代码和散文分开,要么就不该对位置/顺序下 断言。」 Already satisfied: PR objectstack-ai#18924 put the shared `maskComments` in place on both files. ⛔ Not re-added here. ⇒ Under the ruling **as written and as measured**, the order pin in these two files is currently compliant and needs no change. What is *not* settled is a rung-1 **extension**: may a nightly-only pin bind a byte-exact spelling when **no** per-PR sibling binds the property at all? That is a new question, not an application of the existing three rungs, and it sits identically on the `validate-json-failure-*` pair, **which has no carrier card**. Widening this PR to answer it would convert half a family under a rule nobody has made yet. Handed to the `domain:cli` seat as a finding with dedupe words. ## Verification Measured on `git rev-parse --short HEAD` = `0eb90c0a91`, in worktree `/home/user/objectstack-issue-18894`, branched from `origin/main` at `f112a740bd`. | what | how | result | |:--|:--|:--| | the two files, BEFORE the edit | `OS_TEST_TIERS=nightly … --project integration` on both files | **27 passed (27)** — the pins were correct, as the card said | | the two files, AFTER the edit | same | **27 passed (27)** | | `packages/cli` WHOLE, default tier | `pnpm --filter @objectstack/cli test` (bare `vitest run`, ⛔ no `--project`) | **267 files / 3485 tests passed** | | `packages/cli` WHOLE, nightly tier | `OS_TEST_TIERS=nightly pnpm --filter @objectstack/cli test` | **68 files / 695 tests passed** — the tier that actually collects these two files | | typecheck | `pnpm --filter @objectstack/cli typecheck` | exit 0 (incl. `check:test-typecheck`) | | dependency closure + package build | `pnpm --filter '@objectstack/cli^...' build` then `pnpm --filter @objectstack/cli build` | exit 0 both — required, several pins refuse at load without it | | gate families | `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`, then `--ran` with exit codes | 47 derived, **46 run green**, **1 NOT MEASURED** | | whole-repo lint | `pnpm lint` (`eslint . --no-inline-config`), NOT narrowed | exit 0 | **NOT MEASURED (1)**: `pnpm check:dual-build-cjs-loads` exits **3** — `PREREQUISITE NOT MET — this gate reads built output, and some package has no dist/`. It needs a whole-repo `pnpm build`; this worktree built only the `@objectstack/cli` closure. ⛔ Recorded as NOT MEASURED, not as a pass and not as a red. CI's `Build Core` job builds the tree and measures it there. `dispatch-gates --ran` classified it from the recorded exit code rather than from a claim. Two derivation caveats stated rather than hidden: `dispatch-gates` printed a **STALE TREE** warning (`origin/main` moved 2 commits under this branch, touching `scripts/check-adr-0087-registration.mjs` and `scripts/check-single-claim-paths.mjs`); the command list was re-derived after `git fetch origin main` and came back **byte-identical**, so the 47 stands. And the tool's own footer is quoted rather than paraphrased: the 47 is not a complete account of CI — 51 artifact-roster families, 11 wide-population families, 13 pending-changeset families and 5 path-scheduled CI jobs are outside it by construction. ## Acceptance notes Noted, not filed — observations from the two files, none of them a reproducible defect, a contract violation, or a metadata-authoring trap: - The `describe` blocks in both files are still titled with their originating card numbers (`objectstack-ai#11772`, `objectstack-ai#12125`) while the assertions inside them now answer objectstack-ai#18894 too. Cosmetic; renaming a `describe` moves every `-t` filter that names it. Carrier: whoever next opens these files for a behavioural change. - `packages/cli/test/build-json-advisory-parity.e2e.test.ts` is nightly-tier and is the only other reader of the four advisory-list identifiers; its `new Set(...)` comparisons are deliberately order-blind, so the family has **no** order coverage in the per-PR tier at all. Recorded as the measurement behind the adjacent-axis position above, not as a defect. Carrier: the `domain:cli` seat, together with the rung-1 extension question. --- _Generated by [Claude Code](https://claude.ai/code/session_01DvvamiacK328idtBYJBxV3)_ 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.
Fixes #18848
Clause-②: no — the diff is two files under
packages/cli/test/, no governed surface (docs/adr/**,.claude/**,skills/**,AGENTS.md,CLAUDE.md). Declared from the diff, and it agrees with the claim comment's declaration from the card.packages/cli/src/commands/validate.tsis untouched — read only, never written. The seventh exit is correct and stays.What was actually wrong
validate.tshas 7await emitJson(exits; two nightly-only pins asserted 6.await emitJson(exits invalidate.tsatb0b5f31cc6:286 :364 :434 :517 :554 :661 :762)095c7f60ae^(pre-#18769)toHaveLength(6)warnings:conversions:⇒ both CONTRACTS these two files exist for still hold. Only the COUNT was stale. Re-measured independently here and the dispatching seat's figures reproduce exactly.
The seventh exit came with #18769 and is legitimate. Its payload carries both keys.
The choice: DERIVED, not
7The claim asked for the option taken and the cost of the rejected one.
Rejected —
toHaveLength(7). It is one character of work and it is wrong for a measurable reason. It re-arms the identical trap for exit eight, and the trap is not theoretical: it just cost a night of redmainand was about to cost a duplicate p1 card. Its cost is not only that it rots, but where it rots — see the tier reading below. And it is strictly weaker: ablation C is avalidate.tswith eight call sites where a pin of7reads green while the file has an exit no assertion in the family covers.Taken — read the count off the source. The extractor must produce one payload literal per
emitJsoncall site the file actually has:Both sides read raw source, which keeps them symmetric: a commented-out
await emitJson(is counted by the extractor and by the pattern alike. The one asymmetric case — prose naming the call with its paren but noawait— reddens, and that is the accepted price for not importing a comment masker into these two files.Nothing is skipped, disabled, quarantined or deleted. The count assertion is still there, the success/failure partition is still there, the contract negative is still there:
toHaveLength(6)→toBeGreaterThanOrEqual(6). The one integer left, demoted from an equality to a floor. Six is the population theos validate --jsondrops advisory lists it has already computed on all five of its failure exits #12047 /os validate --jsonandos build --jsondrop theconversionsfield on every failure exit, the same waywarningswas dropped #12125 rulings were made over, not a count of today; it rots only in the direction that has to be reviewed anyway (exits being removed), and it floors the derived pair away from the single vacuum they share — anemitJsonrenamed out of existence takes both sides to zero and every assertion here with them. I write no7anywhere in this diff.valid: false× 5 →literals.length - 1, besidevalid: true× 1. Derived, and the two together now also assert the PARTITION: an exit carrying neither literal reddens, which the two frozen integers never checked.The tier, measured in BOTH directions
Not inferred from the workflow YAML — collected, on this branch, in
packages/cli:OS_TEST_TIERSnightlyintegrationproject⇒ the pins are not "a red nobody looks at". In the queue population they are not collected at all. No pull request and no merge-queue run could have reddened on this, which is why #18769's own CI was green and correct. That is a measurement for #18520, not a new card — it is in the report for the seat.
Red → green, in the nightly tier itself
Not a substitute: the tier the pins actually live in, reached locally with
OS_TEST_TIERS=nightly.Before (at
b0b5f31cc6, pre-fix):This is also the first runner-level reproduction of this card: the filing seat stated it had no install and relayed the PR run's result instead.
After:
Four files, because the run also carries the two
build-json-failure-*siblings — see acceptance notes.Ablation — four legs, mutation proven on disk, restore proven byte-exact
Run from the committed fix. The mutation is confined to my own two test files (the
SRCseed), driven by env var;validate.tsis never written.trap … EXIT INT TERM, absolute paths, and the restore is verified bygit diff HEADempty andgit hash-objectequal to the HEAD blob hash (non-empty, both files).await, carrying both keys — an honest additionwarnings:expected [ Array(1) ] to deeply equal []awaitan `emitJson(` call site the payload extractor could not read: expected [ …(7) ] to have a length of 8 but got 7expected 5 to be greater than or equal to 6Leg A is the fix doing its job: a hard-coded
7is red here. Leg C is the capability the rejected option does not have at all — the extractor reports 7, sotoHaveLength(7)passes while the file carries an exit no assertion covers. Leg B proves deriving the count weakened nothing: the contract still bites over the added exit, and the two files isolate from each other. Leg D proves the remaining integer is live.A first ablation attempt exited 127 on a wrong vitest path — the mutation landed but nothing ran, so those readings were void and discarded rather than reported. The table above is the re-run.
Changeset
skip-changeset. Measured, not assumed — nothing published moves:packages/clifiles[]is["dist", "README.md", "CHANGELOG.md"];tsconfig.build.jsonhasinclude: ["src"], sotest/is outside the compiled tree entirely.npm pack --dry-run --json: 0 published paths undertest/orsrc/. Instrument lit by the positive controlREADME.md, which is present.dist/positive control was not lit in the worktree where that manifest was taken (no build yet at that point). Theinclude: ["src"]boundary is what carries the negative, and the closure build reading is in the report.Acceptance notes — noted, not filed
test/build-json-failure-warnings.e2e.test.tsandtest/build-json-failure-conversions.e2e.test.tspintoHaveLength(11)/10/1overcompile.ts. Measured:compile.tshas 11 literals, 10success: false, 1success: true— green right now, and one honest exit away from repeating this exact p1, again only at night. ⛔ Deliberately not touched here:compile.tsis a [finding] the per-package de-duplication key is POSITIONAL, so echoes survive it — andcompile.ts's own comment that the survivors are "exactly the set the union could not see" overstates what it keeps #18779 carrier and is fenced for this card, and a p1 with a cron clock is not the place to double the review surface. Offered to [finding] nightly-only e2e pins read their ownsrc/RAW, so a DOCBLOCK can break a pin whose code never moved — and no pull request can ever redden them, because the tier only runs on main #18520 as a measurement rather than as a new card.validate.ts:661carries a comment that the seventh exit made false — it says the ordering site is read by "every one of the six exits" and that "a seventh exit cannot be added with a different member order". A doc nit inside a read-only file; carrier: the next PR that touchesvalidate.ts.An instruction conflict, named rather than quietly resolved
Triage comment
5723031597pinned the dispatch order: land the two-line literal repair first, and take the "does an integer pin belong here at all" question as a second, separate stroke. The claim comment5724808732instead hands the choice to the deliverer and says ⛔ not to reflexively hard-code7.I took the claim's instruction, because the thing triage was protecting against is not in play: the derived form is the same edit in the same assertion slot, measured and proven in this run, and it delays the red
mainby nothing. The design question triage deferred — whether these files belong in the core tier, or the tier's path filter should namevalidate.ts— is untouched here and remains the cli lane's call.Verification
OS_TEST_TIERSmeasured in both directions · red→green in the nightly tier · four ablation legs · gate families derived withscripts/pm/dispatch-gates.mjsand reconciled with--ran. Full readings, including anything that came back NOT MEASURED, are in theos-dev-reportcomment on #18848.Generated by Claude Code