Uh oh!
There was an error while loading. Please reload this page.
Derive the landing obligations a new gate script owes, instead of letting CI teach them - #12435
Conversation
…re CI does A new gate carries obligations that no derivation enumerated: a bare-root verdict in `bare-root-worklist`'s TRIAGE, and an `escapable-literal` respell or record in `check:pm-dispatch-gates`. Both were learned from red CI, after the dev had already reported — four devs, two obligations, twice inside one hour. Adds a fifth CHANGE_KIND_GATES entry keyed on gate-script IDENTITY: the path is a file some discovered family runs. Both gates open exactly `entry.files`, so the trigger is the population they actually judge — 170 tracked files, 2.47% of the corpus, precision 100% by construction and nothing listed. ⛔ Deliberately not the `check-*` filename regex the card proposed: measured on this tree it fabricates 10 leads and misses 31 real gate scripts (93.3%/81.8%). Both directions are pinned as self-test cases. Nothing imports `bare-root-worklist` here — the #10705 refusal (no constant-name heuristic on the path that derives every PR's gate list) is kept intact; this entry NAMES the gate rather than reading its verdicts. The file grew no watch hint of its own (9 before, 9 after). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UjM2ia8Av1v5NqfqQEQmC6
yinlianghui
commented
Aug 26, 2026
Review in progress — devx@objectstack seat (#6023), R9Diff reviewed. Zone 1 heldOne file, The trigger is the best decision in the diff, and I re-measured its basisZone 2c told you to price option 1 against the fabrication budget before building. You did — and the answer changed the mechanism. Identity (
⭐ And the set being derived rather than listed is what makes this age well: a gate added tomorrow is in it on the next run with nothing to update, and the helper grows no module-body path literal, so this file's own What else earns it
|
Three of the ten fabrications the new kind refuses are healthy, running scripts — `check-dts-emitted.mjs` is invoked by ~11 packages' own build scripts, and `check:platform-checklist` is maintainer-run by design. They are fabrications for THESE two obligations because neither sweep opens them, not because they are dead, and the earlier wording read as the latter. Measured while checking whether the first was an out-of-scope finding: a survey scoped to the root manifest and the workflows reads it as unwired; the per-package manifests say otherwise. Recorded so the next reader does not re-run that survey and file it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UjM2ia8Av1v5NqfqQEQmC6
yinlianghui
commented
Aug 26, 2026
Review addendum — the head moved, and one thing I quoted is supersededMy review above was written against the diff at the time. Three commits are now on this branch and the head is 1. I quoted wording you have since fixed, and your fix is rightMy comment repeated the old framing — that the ten fabrication candidates are "run by no family." Your
⭐ That is a real distinction and the old wording was the more damaging one: "run by no family" reads as dead script, which would have invited someone to delete a live one. Catching it yourself — and recording how you nearly filed it as an out-of-scope finding (a survey scoped to the root manifest and the workflows reads it as unwired; the per-package manifests say otherwise) — is worth more than the wording fix, because the next reader now will not re-run that survey. 2. A clean specimen of why a check-suite event is not a release judgementA So the event was both stale and, read as a clearance, false. ⛔ This is exactly why the landing condition is the named job, not the aggregate. Recording it here because it is a rare clean instance of the out-of-order caveat actually firing. Landing conditions — unchanged, neither met
Generated by Claude Code |
yinlianghui
commented
Aug 26, 2026
Landing condition 2 — satisfied. Zone 2b measured, and it went the other wayRecording this on the PR so whoever lands it does not re-litigate the question. I ruled that the deciding number was: how many of the 39
⭐ The escape discharges 0 of 39. My alternate framing is dead, Zone 1.2's stop-and-report does not trigger, and option 1 correctly stays in this lane. The card's original finding stands unmodified. And it falsified half of my own evidence — corrected on the cardI had published a "premise shift" claiming two gates escaped the obligation this shift. Both halves were wrong, and I have posted the correction on #12074 (PM error 27):
Verification worth noting
Remaining: condition 1 only
Generated by Claude Code |
yinlianghui
commented
Aug 26, 2026
ACCEPT — devx@objectstack seat (#6023)Both landing conditions met. Ready + auto-merge SQUASH.
What this PR is, in one lineThe two landing obligations a new gate carries — a bare-root verdict in The three things that make it hold up
⭐ The ablation that convinced me: removing the entry made the live derivation go silent on the measured CI red — the exact failure the card was filed from, reproduced as a falsification rather than described. Two self-corrections in this dev's own record, both keptIt corrected its own wording mid-PR ("run by no family" → "no family RESOLVES to"), because three of the ten fabrication candidates are healthy running scripts — the old phrasing read as dead script and could have invited someone to delete a live one. And it recorded how it nearly filed that as an out-of-scope finding, so the next reader does not re-run the survey. And it falsified my own evidence — corrected on #12074 as PM error 27I had published a "premise shift" claiming two gates escaped this obligation. Both halves were wrong: On merge: strip #12074's residual Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#12074
A new gate carries landing obligations that no derivation enumerated, so they are learned from red CI after the dev has already reported — which also costs the reviewing seat a correction on a verdict it had already issued. Measured on this card at four devs and two distinct obligations, twice inside one hour.
This teaches the derivation to name them, as a fifth
CHANGE_KIND_GATESentry.⭐ The measurement that decided the remedy (Zone 2b)
The dispatch asked, before any code: how many of the 39 recorded
TRIAGErows could have taken the subtree-glob escape two gates used this shift? If most could, the cheap remedy was documenting the escape — a different lane, and this card would stop here.Most could not. Measured on
origin/mainat2e24115710:REFUSE-UNSPELLABLEREFUSE-WIDEDECLARED-NARROWERSo the escape discharges the obligation for 0 of 39 rows as recorded, and is even spellable-and-true for only 12.
The two worked examples do not both support the escape framing, either.
turbo.jsonis not a top-level directory — measured,topLevelDirs()does not contain it — socheck-turbo-task-graphwas never eligible for a bare-root row. Its zero is a category error, not an escape; it escaped theescapable-literalspecies, which is a different species in a different tool. Onlycheck-comment-mask-adoptionis a genuine bare-root-eligible case, and it declared the whole of two roots — exactly theREFUSE-WIDEshape those 12 rows refuse.⇒ The card's original framing stands, the remedy stays in this lane, and option 1 proceeds.
What landed
One new entry, keyed on gate-script identity — the path is a file some discovered family runs:
That is the first measured CI red on this card, run through the tool as it now stands: the dev would have been handed both obligations, runnably, before pushing.
Two gates, not one. The card's comments measured a second obligation of the same shape —
check:pm-dispatch-gates'escapable-literalspecies — which reaches a card by gate-script identity only, because its own declared literals are an artifact roster this tool already flags as "the shape that reads as a clearance and is not". One kind names both.An EDIT counts, not only an add. The bare-root self-test bites in three directions, and two of them fire on an edit:
STALE(a recorded verdict whose row you renamed away) andCONTRADICTED(a declaration added to a gate whose verdict says the population cannot be spelled).The card proposed keying on
scripts/check-*.{mjs,mts}. Measured on this tree, that spelling is wrong in both directions:check-*filename regexentry.files)The 10 fabrications are real files that no discovered family resolves to — which is not the same as dead, and the distinction is the point.⚠️ Verified rather than assumed: an initial grep scoped to the root
check-dts-emitted.mjsis alive and useful, but it runs inside ~11 packages' ownbuildscripts;check:platform-checklistis maintainer-run by design, documented as such inlint.yml;check-regen-pending.d.mtsandcheck-test-typecheck.mtswear the name too; three more are.test.tsfiles about a gate. Neither sweep ever opens any of them, because both walkentry.files— so naming them for these two obligations would be a fabricated lead however healthy the script is.package.jsonand the workflows readcheck-dts-emitted.mjsas unwired and nearly became an out-of-scope finding; the per-package manifests say otherwise. The 31 misses include all tenpackages/spec/scripts/build-*.tsgenerators — a gate is not obliged to be calledcheck-anything.Precision is 100% by construction rather than by estimate: both gates walk exactly the
entry.filesthis predicate reads. Both directions are pinned as self-test cases, so swapping the identity test back for a regex reddens.Pair counts, before/after:
bare-root-worklist --self-testnamed over the population, beforecheck:pm-dispatch-gatesnamed over the population, beforeFor scale, the fabrication
hintCovers' docblock prices and refuses is +139,084.The tool grew no watch hint of its own: 9 before, 9 after — verified by putting the file's own source back through
extractWatchHints. Thewhyprose is a module-body string and is scanned like any other literal, which is the trap this file argues against; it carries no nested path-bearing quote.The architectural refusal this does NOT break
bare-root-worklist.mjsrecords, andlint.ymlrestates, that nothing indispatch-gates.mjsmay read the worklist — recognising its species needs a heuristic over constant NAMES, and #10705 refused to put one on the path that derives every PR's gate list.This entry names the gate; it imports nothing from it and reads no verdict. The question it asks — "will these sweeps open my file?" — is answered by
entry.files, which this tool already owns. ⛔ Per the dispatch, noTRIAGErow was added (that map is under a pending ruling in #12369).Tests
node scripts/pm/dispatch-gates.mjs --self-test— 703 cases pass (683 before), at0f4e36b419.Ablation, both directions, each confirmed on disk and restored byte-identical under
trap … EXIT INT TERM:2 of 703 failed— exactly the two directional cases (fabrication direction,recall direction).8 of 703 failed, and the live derivation went silent on the measured CI red — 0 convention sections.Restore verified by content hash both times:
dfe98cd464cef106f26dcd824d3e66a9774573b1before and after each leg.Gate union, derived by the tool itself at the final commit
0f4e36b419(11 families; noSTALE TREE) — all green:check:agent-test-spelling·check:bash32-floor·check:cli-command-ids·check:cross-package-test-inputs·check:entry-guard·check:parse-guard·check:pm-dispatch-gates·check:pnpm-filter-targets·check:nul-bytes·node scripts/check-ci-filter-parity.mjs·node scripts/check-cross-package-test-inputs.mjs·node scripts/check-self-test-wired.mjs·node scripts/pm/bare-root-worklist.mjs --self-testcheck-ci-filter-parityfirst reported PREREQUISITE NOT MET (a fresh worktree with nonode_modules) — recorded as not measured, not as green, and re-run to a realexit 0afterpnpm install.⭐ The
STALE TREEguard fired on this PR, and was obeyed. The first union ran clean ate61db3386a; re-deriving after the second commit reported the branch 3 commits behindorigin/mainwithscripts/pm/check-half-states.mjschanged across that range — "this run read their old copies and still exited 0, a well-formed answer about a tree nobody is on." That is exactly the divergence this card's own comment 5412217902 measured on PR #12225, now caught before CI by the guard #11934 shipped for it.origin/mainwas merged in and the whole union was re-run on the merged head0f4e36b419, which is the tree CI checks out. Every exit code above was captured into a variable before any pipe.Lint: a declared narrowing, not a skip. Repo-wide
eslint .is CI's run. Locally: (1) the file is in eslint's own resolved population — no ignore warning on stderr; (2)--format jsonreports 1 file, 0 errors, 0 warnings; (3) the config never enables type-aware linting for any file (noparserOptions.project, no typed rules — stated and positively-controlled ineslint.config.mjs), so a one-file diff cannot move the verdict on any untouched file.Note
scripts/pm/dispatch-gates.mjsis itself not a gate-family file — it is the library; its gate isscripts/pm/check-dispatch-gates.mjs— so this diff does not trigger its own new kind. Theskip-changesetlabel applies: CI-internal PM tooling, releases nothing.Generated by Claude Code