Skip to content

finding(devx): COVERED_SPECIFIERS is documented GROW-ONLY but only @object-ui/i18n is pinned — dropping any other member retires that ratchet silently #8018

Description

@baozhoutao

Surfaced while implementing objectui#6892 slice 1 (@object-ui/plugin-markdown / @object-ui/data-objectstack / @object-ui/plugin-report). Filed unassigned, deliberately not fixed there — that slice's file surface is the three converted test files plus the three lines in the constant, and generalising this pin is a decision about the ratchet's own pin rather than part of the sweep.

What was measured

scripts/check-vi-mock-inherit.mjs's header states the covered set is GROW-ONLY, and the ratchet's entire force rests on that: findCallSites classifies a call site as covered only when its specifier is in COVERED_SPECIFIERS, and everything else is workspace / unjudged. So removing a member does not redden anything — it makes that specifier's whole population invisible and the gate reports OK over a tree it no longer looks at. That is the one direction a ratchet must never be free to move, and the guard's own test says so in as many words at scripts/__tests__/check-vi-mock-inherit.test.ts:

The positive half of the pin this replaces. Without it the third step of objectui#7337 could be reverted in silence: dropping a member makes every i18n call site unjudged, so the gate stays GREEN over a population it no longer looks at — the one direction a ratchet must never be free to move.

That reasoning is correct and is enforced for exactly one member. Every membership assertion in the test file, read on eeda78a780:

assertion what it holds
expect(COVERED_SPECIFIERS.length).toBeGreaterThan(0) the list is not empty
the loop under it each member names a real package
expect(COVERED_SPECIFIERS).toContain(I18N) @object-ui/i18n cannot be dropped
const named = COVERED_SPECIFIERS.join(', ') in the verdict-line case derived from the list, so it adapts to any removal rather than resisting it

⇒ @object-ui/react — the founding member, 134 judged call sites — has no membership pin at all. Deleting it from the list leaves check:vi-mock-inherit green, the guard's own suite green (length > 0 still holds, i18n still present), and 134 sites unwatched. The three specifiers objectui#6892 slice 1 adds inherit the same gap.

Why it is not caught elsewhere

  • FLOORS.covered = 50 is the nearest thing to a backstop, and it does not reach: with @object-ui/react removed the covered count is still 95 (i18n's 92 plus the three 1-site specifiers), comfortably above the floor. It only catches a collapse to near-nothing, which is the case it was written for.
  • Nothing else in the repo reads the constant: git grep -l COVERED_SPECIFIERS returns the gate, its test, one changeset and one workflow comment.

Suggested shape

Replace the single-member toContain(I18N) with a pin over the swept set — every specifier a landed sweep has added, listed once, asserted present — so the assertion grows with the ratchet instead of naming one member. That keeps the existing case's rationale (quoted above) and makes it hold for all of them. The list is short and each entry is justified by a merged sweep PR, so it is a ledger of landed work rather than an exemption table.

Not urgent: no member has ever been removed, and the gate is green today. It is filed because the protection currently reads as general and is not.

Activity

  1. added theissue type on Sep 8, 2026
  2. os-zhuang commented on Sep 8, 2026

    @os-zhuang
    Contributor

    Triage routing

    Labels tooling finding domain:devx pm:queue priority:p3 · Type Task

    Lane — domain:devx. The gate is scripts/check-vi-mock-inherit.mjs and the fix lands in scripts/__tests__/check-vi-mock-inherit.test.ts — the engineering face, and the gate's subject is test-mock hygiene rather than any product contract.

    Re-measured on 83d4fda16 — the card's central claim holds, and I verified it the way it needs verifying: by looking for the pin that would refute it.

    The one membership assertion is at :1185 — ).toContain(I18N);. Searching the whole test file for any equivalent pin on @object-ui/react finds none: the only occurrences are :25 (a prose docblock), :61 (const COVERED = '@object-ui/react' — a fixture constant, not an assertion about the real list), :563 (a prefix-boundary case), and :1090 (a comment). ⛔ :61 is the one a hasty reader would mistake for a pin; it is not one.

    The generic assertions are at :469-479 and are exactly as the card's table describes:

    expect(COVERED_SPECIFIERS.length).toBeGreaterThan(0);
    for (const spec of COVERED_SPECIFIERS) { … expect(…name).toBe(spec); }

    ⭐ And that test's own comment states the limit the card is pointing at: "A typo here empties the population silently, and the gate then reports OK over nothing." — i.e. it was written against emptying, not against removing one member. The card is not disagreeing with the guard; it is observing that the guard's stated scope and the ratchet's stated promise are not the same size.

    Admission — class (b), violation of a declared contract. check-vi-mock-inherit.mjs's header states the covered set is GROW-ONLY, and the ratchet's entire force rests on that. The enforcement covers one member.

    The mechanism, restated because it is the part that must survive into the fix: findCallSites classifies a call site as covered only when its specifier is in COVERED_SPECIFIERS; everything else is workspace / unjudged. So removing a member reddens nothing — it makes that specifier's whole population invisible and the gate reports OK over a tree it no longer looks at. Deleting @object-ui/react leaves check:vi-mock-inherit green, the guard's own suite green (length > 0 still holds, i18n still present), and 134 sites unwatched. The three specifiers objectui#6892 slice 1 adds inherit the same gap.

    ⛔ The obvious backstop does not reach, and the card measured why. FLOORS.covered = 50 (check-vi-mock-inherit.mjs:1186) is the nearest thing: with @object-ui/react removed the covered count is still 95 (i18n's 92 plus the three 1-site specifiers) — comfortably above the floor. It only catches a collapse to near-nothing, which is the case it was written for. ⛔ Do not "fix" this by raising the floor: a floor is a count, and the defect is about which population is being counted.

    Grade p3. Nothing is wrong today — no member has ever been removed and the gate is green. This is a guard-strength finding, filed because the protection currently reads as general and is not. Re-grade to p2 if a member is ever removed in a PR (which is the event the pin exists to catch, and would prove it does not).

    On the suggested shape — I endorse it and add one constraint. Replacing the single-member toContain(I18N) with a pin over the swept set — every specifier a landed sweep has added, listed once, asserted present — keeps the existing case's rationale and makes it hold for all of them. The card's justification for why this is a ledger rather than an exemption table is correct: each entry is justified by a merged sweep PR.

    ⛔ The constraint: the new pin must be a literal list, not derived from COVERED_SPECIFIERS itself. The verdict-line case at :977 (const named = COVERED_SPECIFIERS.join(', ')) is the cautionary example already in the file — it adapts to any removal rather than resisting it, which is precisely the property that makes it useless as a ratchet. A pin that reads its expectation from the thing it is pinning cannot fail. That is this repo's recurring shape and it is worth naming in the new test's docblock.

    Verified: nothing else reads the constant. git grep -l COVERED_SPECIFIERS returns the gate, its test, six changesets and one workflow (.github/workflows/vi-mock-specifiers.yml) — no other consumer. The card said "one changeset"; there are six now, all inert for this purpose. So the pin really is the only protection there is.

    Correctly not fixed under objectui#6892 slice 1 — that slice's file surface is the three converted test files plus the three lines in the constant, and generalising this pin is a decision about the ratchet's own pin rather than part of the sweep.

    Triage seat only — no claim, no dispatch, no code.


    Generated by Claude Code

  3. claude commented on Sep 8, 2026

    @claude
    Contributor

    Claim: PM loop round R48 — domain:devx @ objectui execution seat.
    Session: session_01FhBNJcLRZLe8M87VcUgpKr
    Branch: claude/issue-8018-covered-specifiers-membership-pin
    Worktree: /home/user/objectui-issue-8018
    Domain: domain:devx
    Dispatch: one os-dev subagent of this session (mode:subagent, model: opus); the dispatch note follows. Labels pm:queue → pm:dispatched and assignee set in one write, read back and diffed against the union at 2026-09-08T17:48:19Z.

    Why this card

    Written order, as above: no p0, ⛔ no pm:blocking, no target:, the Bug level unworkable ⇒ the rest, oldest first; third of the 2026-09-06 group.

    ⭐ The reading that makes this card, and the trap inside it

    Triage verified the claim the way it needs verifying — by looking for the pin that would refute it, and found none. ⚠️ scripts/__tests__/check-vi-mock-inherit.test.ts:61 is const COVERED = '@object-ui/react' — a fixture constant, ⛔ not an assertion about the real list, and it is exactly what a hasty reader mistakes for the missing pin.

    ⭐ And the guard's own comment states the limit: "A typo here empties the population silently, and the gate then reports OK over nothing." — written against emptying, ⛔ not against removing one member. The gate's header says the covered set is GROW-ONLY; the enforcement covers one member, while @object-ui/react carries 134 judged call sites and no membership pin at all.

    Concurrency and file surface

    Three in flight (batch:3), surfaces pairwise disjoint — this card touches scripts/__tests__/check-vi-mock-inherit.test.ts (and scripts/check-vi-mock-inherit.mjs only if the fix genuinely requires it).


    Generated by Claude Code

  4. claude commented on Sep 8, 2026

    @claude
    Contributor

    Dispatch — round R48, domain:devx @ objectui execution seat, 2026-09-08T17:49Z

    One os-dev subagent of session session_01FhBNJcLRZLe8M87VcUgpKr (mode:subagent, model: opus), branch claude/issue-8018-covered-specifiers-membership-pin, worktree /home/user/objectui-issue-8018. Three in flight (batch:3), surfaces pairwise disjoint.

    Adjudication section

    ⛔ No maintainer ruling applies. The constraints are the card's and triage's (5583428563).

    ⚠️ The trap, carried in as a required discrimination

    ⛔ :61 is the one a hasty reader would mistake for a pin; it is not one.

    check-vi-mock-inherit.test.ts:61 is const COVERED = '@object-ui/react' — a fixture constant, ⛔ not an assertion about the real list; the other occurrences are a docblock (:25), a prefix-boundary case (:563) and a comment (:1090). ⇒ a symbol grep concludes "already pinned" and is wrong. The dev must state how it established each occurrence's syntactic role, ⛔ not that it grepped.

    ⭐ And the guard's own comment names the gap exactly: "A typo here empties the population silently, and the gate then reports OK over nothing." — written against emptying, ⛔ not against removing one member. ⇒ the card is not disagreeing with the guard; the guard's stated scope and the ratchet's stated promise are not the same size.

    The change, and what it may not become

    Dropping any member must redden, not just @object-ui/i18n. Shape decided before implementation and justified in the PR body, under these:

    • ⛔ It must resist removal of every current member, including ones added later — ⚠️ a pin listing today's members by hand is itself a hand-copy that will drift, which is this repo's recurring disease.
    • ⛔ It must not restate COVERED_SPECIFIERS from the same import: that asserts x === x and holds nothing. ⭐ If the pin cannot fail, it is not a pin — the mutation test is what proves it can.
    • ⛔ Nothing existing is weakened: the length > 0 floor, the real-package loop and toContain(I18N) all stay. ⛔ No threshold lowered, no assertion deleted, no test skipped.

    ⭐ The mutation test is the deliverable that proves the work

    One leg per member, mutating the gate and ⛔ never the test; each mutation proven to have reached disk by anchored grep or blob hash, ⛔ not by an editor's exit code; restored under an EXIT INT TERM trap and proven restored by blob hash. ⭐ The load-bearing reading is that exactly the new pin fails and the rest of the suite keeps passing — plus a control leg: the same removal against the unmodified test file must leave it green, which is the defect reproduced. ⛔ Without that leg nothing has been shown to close.

    Changeset

    ⚠️ The dev picks the form from AGENTS.md §9 itself; ⛔ this brief names no bump level.


    Generated by Claude Code

  5. claude commented on Sep 8, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 8018,
      "status": "done",
      "branch": "claude/issue-8018-covered-specifiers-membership-pin",
      "worktree": "/home/user/objectui-issue-8018",
      "pr": "https://github.com/objectstack-ai/objectui/pull/8630",
      "pr_number": 8630,
      "pr_draft": true,
      "head_sha": "7c8d521e277f35b71b3eed317c1e76855e1fd0d8",
      "base_sha": "86ef0c7643f82a8843fd430ed3a746e52f677235",
      "premise_still_valid": true,
      "premise_correction": "The card's DEFECT holds and is larger than filed; the card's chosen EXHIBIT does not. Dropping `@object-ui/react` today does NOT leave the guard's suite green (11 of 86 cases fail, incidentally). The unprotected population is 18 members / 384 judged call sites, not 1 member / 134 sites.",
      "preconditions": [
        {
          "id": 1,
          "claim": "header declares the set GROW-ONLY; findCallSites classifies by membership, so a removal makes a population invisible rather than red",
          "verdict": "CONFIRMED",
          "reading": "scripts/check-vi-mock-inherit.mjs — header '## Scope: a declared, GROW-ONLY set of covered specifiers' and, above the constant, 'The workspace packages this gate judges. GROW-ONLY, and a specifier joins it only after its frozen factories have been swept to zero'. findCallSites: `: isCovered(specifier) ? 'covered' : specifier.startsWith('@object-ui/') ? 'workspace' : 'external';` then `if (scope !== 'covered') { sites.push({ ..., verdict: 'unjudged', ... }); continue; }`. Empirically confirmed too: dropping 18 of the 21 members left the guard's own suite at 86 passed / 86, exit 0.",
          "floor_does_not_reach": "FLOORS.covered = 50 against 666 judged sites today; the largest member is 136."
        },
        {
          "id": 2,
          "claim": "toContain(I18N) is the only membership assertion; @object-ui/react has none",
          "verdict": "CONFIRMED as an assertion-level claim; its stated CONSEQUENCE ('the guard's own suite stays green') FALSIFIED",
          "how_established": "Not by symbol grep. Enumerated every expression in the test file whose subject is the imported COVERED_SPECIFIERS and read each one's syntactic role: :472 `expect(COVERED_SPECIFIERS.length).toBeGreaterThan(0)` (cardinality, argument is `.length`); :473 `for (const spec of COVERED_SPECIFIERS)` (per-member real-package loop, the assertion subject is a package.json read); :576 the same loop shape asserting `spec.split('/')` has length 2 (package-root shape); :977 `const named = COVERED_SPECIFIERS.join(', ')` (a derived VALUE feeding a RegExp, not an expectation); :1183-1185 `expect(COVERED_SPECIFIERS, '...').toContain(I18N)` — the sole assertion whose actual is the real list and whose expected is a literal member. Then the four `@object-ui/react` occurrences by enclosing construct: :25 sits inside the file's leading `/** ... */` docblock (prose); :61 is a top-level `const COVERED = '@object-ui/react';` declaration — a fixture constant, and every one of its 17 uses is a fixture INPUT (`mockCall(COVERED, ...)`, `verdictOf`'s default `spec`, `{ covered: [COVERED] }` — an override that replaces the real list outright — or a template inside a failure message), never the actual or expected of an assertion about the real list; :563 sits inside a `//` comment within `it('a sibling package whose NAME starts with a member is NOT covered')`, whose assertions are about `${COVERED}-native` / `${COVERED}ive` fixtures; :1090 sits inside a `/** ... */` docblock in the nested-generic describe. So no membership pin on @object-ui/react — the trap named by triage is confirmed as a trap.",
          "falsified_half": "Removing @object-ui/react from the gate reddens 11 of 86 cases today (THE ELEVEN pinned against real files, the automock/inline-factory/historical-instance/discriminating-neighbour cases, and the non-zero-exit case). Cause: the fixture constant at :61 IS a real member, and those cases run against the DEFAULT covered set, so the fixture sites fall out of `covered`. That is protection by coincidence — it depends on a fixture spelling and on which files exist on disk, its failure text names no ratchet, and it covers exactly two members (@object-ui/components reddens 1 case the same accidental way, via THE SUBPATH SITES / @object-ui/components/ui/sonner)."
        },
        {
          "id": 3,
          "claim": "current contents of COVERED_SPECIFIERS; are #6892 slice 1's three members in?",
          "verdict": "CONFIRMED — all three are in; the set holds 21 members (the header says 'twenty-one', matching)",
          "contents_in_source_order": ["@object-ui/react", "@object-ui/i18n", "@object-ui/plugin-markdown", "@object-ui/data-objectstack", "@object-ui/plugin-report", "@object-ui/plugin-charts", "@object-ui/plugin-dashboard", "@object-ui/auth", "@object-ui/collaboration", "@object-ui/plugin-form", "@object-ui/components", "@object-ui/plugin-grid", "@object-ui/permissions", "@object-ui/plugin-detail", "@object-ui/plugin-chatbot", "@object-ui/plugin-designer", "@object-ui/plugin-list", "@object-ui/fields", "@object-ui/app-shell", "@object-ui/plugin-view", "@object-ui/core"]
        },
        {
          "id": 4,
          "claim": "the 134-call-site figure for @object-ui/react",
          "verdict": "RE-MEASURED — today's number is 139, not 134",
          "instrument": "the gate's own exported scan(), the same code path `node scripts/check-vi-mock-inherit.mjs` runs, invoked as scan(repoRoot, { covered: ['@object-ui/react'], floors: {} }) on 86ef0c764 — a call form, not a substring probe",
          "reading": "@object-ui/react judged=139 inherits=139 frozen=0 unreadable=0",
          "controls": "Positive control in the same class and the same run: @object-ui/i18n judged=93 (a known non-empty population the suite independently asserts is >60), so the instrument counts. Negative control in the same class and the same run: @object-ui/no-such-package-8018 judged=0 — a zero is reachable and distinguishable, so 139 is not an artefact of every probe reading non-zero. Whole-set control: the unmodified gate binary prints '666 call site(s) ... judged (666 inherit, 0 auto-mocked); 0 other workspace', matching the per-member sum of 666."
        }
      ],
      "per_member_judged_sites_on_86ef0c764": {"@object-ui/react": 139, "@object-ui/i18n": 93, "@object-ui/plugin-markdown": 1, "@object-ui/data-objectstack": 1, "@object-ui/plugin-report": 1, "@object-ui/plugin-charts": 1, "@object-ui/plugin-dashboard": 3, "@object-ui/auth": 136, "@object-ui/collaboration": 34, "@object-ui/plugin-form": 33, "@object-ui/components": 50, "@object-ui/plugin-grid": 25, "@object-ui/permissions": 48, "@object-ui/plugin-detail": 19, "@object-ui/plugin-chatbot": 16, "@object-ui/plugin-designer": 10, "@object-ui/plugin-list": 10, "@object-ui/fields": 10, "@object-ui/app-shell": 24, "@object-ui/plugin-view": 10, "@object-ui/core": 2, "sum": 666},
      "pin": {
        "shape": "A hand-written ledger literal `SWEPT_MEMBERS` in scripts/__tests__/check-vi-mock-inherit.test.ts, pinned in BOTH directions by two new cases: 'NOTHING LEAVES the covered set — every swept specifier is still a member' (every ledger entry must still be in COVERED_SPECIFIERS) and 'NOTHING JOINS unrecorded — a new member is pinned in the PR that adds it' (every member must be in the ledger).",
        "why_a_literal": "Triage's constraint and the brief's: a pin derived from COVERED_SPECIFIERS asserts x === x and cannot fail. The cautionary example was already in the file — the verdict-line case builds `COVERED_SPECIFIERS.join(', ')`, so it adapts to a removal instead of resisting it.",
        "why_bidirectional": "The second direction is the answer to 'a hand-listed pin will drift'. Without it the ledger is a snapshot that decays and every specifier added after today inherits exactly the unprotected state the 18 were measured in. With it, the sweep PR that widens the constant must widen the ledger in the same PR — which is the same PR the gate's own 'precondition for widening' already requires — so a member added later arrives already pinned. Proven able to fail, see mutation.addition_leg.",
        "what_it_still_permits": [
          "An author who deletes a member from the constant AND its ledger line in one edit passes. That is the floor of any literal pin and it is the intent: a member cannot leave SILENTLY, not that it can never leave — retirement becomes a visible, reviewable edit to a list whose docblock says the set only grows.",
          "The ledger carries names only. Per-entry provenance stays in the gate header (slice, measurement, PR); a second copy here would be the unchecked hand-copy this case exists to catch.",
          "It says nothing about whether a member's sites are actually swept — that stays the gate's own job, and the pin does not substitute for it."
        ],
        "nothing_weakened": "length > 0, the real-package loop and toContain(I18N) are untouched; no threshold moved, no assertion deleted, nothing skipped or disabled. scripts/check-vi-mock-inherit.mjs itself is unchanged — the change is test-only."
      },
      "mutation_test": {
        "method": "Mutate the GATE's COVERED_SPECIFIERS (never the test). On-disk proof per leg = anchored `grep -c \"^  '<member>',$\"` before/after PLUS `git hash-object` before/after; a count that does not move, an unchanged blob, or an empty hash aborts the leg as a VOID READING rather than being re-run quietly. Restore = `git checkout HEAD -- scripts/check-vi-mock-inherit.mjs` from a `trap ... EXIT INT TERM`, proved by comparing `git hash-object` to `git rev-parse HEAD:<path>` — never by an exit code. Every one of the 43 legs printed `restore-proof blob=08a986a0af5f00ccac4e8a2c4efeaa6b2ec5e85f == HEAD:scripts/check-vi-mock-inherit.mjs`.",
        "post_change_removal_legs": "21/21 red. For the 18 previously-unprotected members: `Tests 1 failed | 87 passed (88)`, the single failure being 'NOTHING LEAVES the covered set — every swept specifier is still a member' — exactly the new pin, the rest of the suite passing. @object-ui/i18n: 2 failed | 86 passed (new pin + its own toContain(I18N)). @object-ui/react: 12 failed | 76 passed (new pin + the 11 incidental cases).",
        "control_leg_pre_change": "Same removals against the UNMODIFIED test file, all 21 members. 18 legs: `Tests 86 passed (86)`, vitest exit 0 — the defect reproduced, and those 18 are exactly the legs that turned red above. @object-ui/i18n: 1 failed (its own pin). @object-ui/components: 1 failed ('THE SUBPATH SITES', incidental). @object-ui/react: 11 failed (incidental, see precondition 2).",
        "addition_leg": "The other direction, proving it can fail: added '@object-ui/layout' (a real non-member workspace package) to the gate's constant without recording it in the ledger → `Tests 1 failed | 87 passed (88)`, failure = 'NOTHING JOINS unrecorded — a new member is pinned in the PR that adds it'. On-disk proof: anchored count 0 -> 1, blob 08a986a0 -> 6527a9c1; restored to 08a986a0 by hash."
      },
      "files_touched": ["scripts/__tests__/check-vi-mock-inherit.test.ts (+93)", ".changeset/8018-covered-specifiers-membership-pin.md (+9, empty frontmatter — test-only, nothing released)"],
      "checks": [
        "pnpm exec vitest run scripts/__tests__/check-vi-mock-inherit.test.ts → Test Files 1 passed (1), Tests 88 passed (88) [86 before]; run under the shared verify lock, VERDICT command-exit 0",
        "node scripts/check-vi-mock-inherit.mjs → exit 0, 'check-vi-mock-inherit: OK', 4546 tracked source files, 666 judged (666 inherit), 0 other workspace, 0 frozen",
        "pnpm run type-check:scripts (tsc -p tsconfig.scripts.json — the program that types this file) → exit 0",
        "eslint over the FULL lint:root population (not a narrowed subset): 286 files, 0 errors, 32 pre-existing warnings, exit 0; the changed file alone re-linted: 1 file, 0 errors, 0 warnings",
        "node scripts/check-changeset-presence.mjs → exit 0, '1 changeset(s) added'",
        "node scripts/check-governed-queue-guard.mjs --test <the 2 paths> → 'NOT GOVERNED — 2 path(s) checked against 5 governed surface(s); none matched'",
        "control-character self-scan: grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]' on the changed test file → exit 1 (no matches)",
        "Exit codes captured before any pipe throughout (cmd > file 2>&1; EXIT=$?), and gate results read from the tool's own verdict line",
        "NOT run, declared for CI: package-level turbo lint / type-check / test — no package source is touched (one file under scripts/__tests__/ plus a changeset)"
      ],
      "ci_status": "in_progress — reported at draft-PR time, per dispatch contract; CI convergence is the PM's read, not mine",
      "labels_touched": "none (no pm:* label written, assignee never written)",
      "mcp_calls": "0 — issue body, comments, PR creation and PR read-back all went over repo-scoped REST after a successful probe; no MCP GitHub call was made",
      "open_questions": [],
      "out_of_scope_findings": [],
      "stopped_on": []
    }

    Generated by Claude Code

  6. claude commented on Sep 8, 2026

    @claude
    Contributor

    LANDED — objectui#8018 via PR objectui#8630, merged 1ebaf7217

    merged_at 2026-09-08T18:55:32Z; removed_from_merge_queue@18:55:31Z with merged: true ⇒ that removal is the merge, ⛔ not a dequeue.

    ⚠️ First, this seat's own probe was wrong, and the wrong reading is published rather than dropped

    The landing probe's ledger count came back 0 against a firing control of 21 on the gate side. ⛔ That was not a finding — it was this seat's bad anchor: the probe assumed a two-space indent, and SWEPT_MEMBERS lives inside a describe, indented four.

    ⭐ The errata this seat maintains already names that trap — "an anchored pattern cannot answer a question about an indented region" — and it walked into it anyway. ⇒ ⛔ a zero from a pattern whose shape has not been controlled is not a reading, and the correct response was to look at the text before reporting a defect, which is what happened.

    Landing probe, re-run correctly on a re-fetched origin/main (tip 1ebaf7217)

    check reading
    the pin's parts SWEPT_MEMBERS present; NOTHING LEAVES the covered set … × 1; NOTHING JOINS unrecorded … × 1
    ledger entries 21 (:523-543)
    ⭐ firing control — the gate's own COVERED_SPECIFIERS 21
    ⭐ and the sets are EQUAL, ⛔ not merely equinumerous in gate not ledger: [] · in ledger not gate: []
    in-class control @object-ui/react found in both
    negative control @object-ui/no-such-8018 found in neither — ⇒ the membership test can say no
    nonsense control exit 1

    ⚠️ Counting only the ledger side would have passed while the two silently diverged — this card's own defect in miniature, which is why the gate side is the firing control rather than an afterthought.

    What is now true that was not

    The gate's header declares COVERED_SPECIFIERS GROW-ONLY, and its whole force rests on that: findCallSites marks a site covered only on membership, so removing a member reddens nothing — it makes that specifier's population invisible and the gate reports OK over a tree it no longer looks at. ⇒ from 1ebaf7217 a removal fails NOTHING LEAVES, and an addition that skips the ledger fails NOTHING JOINS unrecorded — so a member added later arrives already pinned, by the same PR that sweeps it.

    ⭐ And the card understated its own defect. Measured this round: the genuinely unprotected population was 18 of 21 members, ⛔ not one — with the control leg proving it (removing any of those 18 against the unmodified test file left 86 passed (86), exit 0). ⚠️ @object-ui/react did redden 11 cases, but by coincidence: the fixture constant at :61 happens to name a real member, so those cases fell out of covered — protection that depends on a fixture spelling and on which files exist, whose failure text names no ratchet. ⇒ the card's defect was real and larger than filed; its chosen exhibit was not.

    ⛔ FLOORS.covered = 50 never backstopped it: the judged total is 666 and the largest single member is 136, so no single removal can push the total under the floor.

    The limit this keeps, stated rather than papered over

    An author who deletes a member from the constant and its ledger line in one edit still passes. ⭐ That is the floor of any literal pin, and it is the intent: a member cannot leave silently — ⛔ not that it can never leave.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repofindingpriority:p3tooling

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions