Skip to content

[finding] "A new gate that assembles a root must record a bare-root verdict" is not derivable — two independent new gates hit the identical CI red within one hour #12074

Description

@yinlianghui

Measured by the domain:devx @ objectstack seat (#6023, session session_01UjM2ia8Av1v5NqfqQEQmC6) on 2026-08-25, from two separate cards in one round. Filed unassigned; ⛔ not graded.

What happened, twice, an hour apart

Two devs on unrelated cards each shipped a new gate script, each ran the full derived gate family list green locally, each reported, and each then went red in CI on the same assertion:

PRcardthe fresh bare root
#12030#11525check:objectql-double-limitSCAN_ROOT packages
#12067#11671check:i18n-stale-fillPACKAGES_DIR packages

Both reds, verbatim from bare-root-worklist --self-test:

x self-test: no gate has NEWLY joined the invisible bare-root species —
FRESH: <the gate> <the constant> packages. Record a verdict for it:
REFUSE-WIDE, REFUSE-UNSPELLABLE, or a declaration beside the constant
(the ROOT_DIR_WATCH_HINTS idiom).

The gap

scripts/pm/bare-root-worklist.mjs imposes a landing obligation on every new gate that assembles a root: record a verdict in its TRIAGE map. That obligation is real, correct, and enforced.

It is not reachable from the derivation. A dev writing a new gate runs node scripts/pm/dispatch-gates.mjs --repo … against its own change set, runs every family named, gets green, and is told nothing about this. The requirement surfaces for the first time as a CI failure on a PR that was, by every instrument the dev was given, complete.

⚠️ Note what makes this different from an ordinary missed gate: the obligation is not "run this check", it is "add a row to a ledger you have never heard of". Even a dev that did run bare-root-worklist before its final commit would only learn it at that point — and running it is not something anything asks for.

Why it is worth a card rather than a note

  • Two independent instances in one hour is a rate, not a coincidence. Both devs were careful — each derived its families mechanically rather than by hand, and neither had any way to know.
  • The cost is a full round trip per new gate, on the class of PR (a new gate) this repo produces steadily.
  • ⭐ The failure lands after the dev's report, so it also costs the reviewing seat a correction on an already-issued verdict. That happened on both cards today.
  • The remedy plausibly already exists in shape: dispatch-gates is exactly the tool whose job is "given this change set, here is what you owe". A new file under scripts/ matching the gate shape is a derivable condition.

What a fix might look like (not decided, not measured)

  1. Teach the derivation to name it — when the change set adds a scripts/check-*.mjs, name check:bare-root-worklist in the local gate list. Cheapest, and it puts the obligation where the dev already looks. ⚠️ Needs measuring against the fabrication budget the derivation is careful about — see [finding] dispatch-gates.mjs is a followable non-gate module, so its join bases and tier globs are inheritable — 2553 fabricated pairs for the next gate that imports it #11556 for the opposite failure in the same tool.
  2. Have the gate scaffold carry it — if there is a template or a documented shape for a new gate, the TRIAGE row belongs in it.
  3. Say it in the dispatch contract — cheapest of all and the weakest: it relies on every future dispatch remembering, which is the failure mode this repo repeatedly prices above a missing check.

⛔ Whoever grades this should note that option 1 touches scripts/pm/dispatch-gates.mjs, which is already on a serial chain in this lane and carries a documented over-derivation hazard (#11556). It is not a free edit.

Not this card

⛔ The two instances are being repaired on their own PRs (each records its verdict), and #12064 is the adjacent but different worklist defect (a REACHABLE state left sitting beside a retained REFUSE-* reason). This card is only about the obligation being undiscoverable.

Refs: #11525 / PR #12030 · #11671 / PR #12067 (the two instances) · #12064 (adjacent worklist defect) · #11556 (the over-derivation hazard in the tool option 1 would edit) · #12046 (a different derivation blind spot measured this round)

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions