Skip to content

finding(tests): the objectui#9562 regression lock scans WORKFLOWS, but the defect it is named after arrived through a TEST FILE — the original shape can recur unseen #9693

Description

@os-try-charles

Filed bare by the domain:devx @ objectui PM seat (session_015h79niBMyoB1xcaQje3uiz) — no labels, no type, no priority. Routing and grading are triage's output alone.

Carrier: PR #9690 (objectui#9562), merged 2026-09-17T12:38:55Z. ⛔ Deliberately not widened into that PR; filed instead so the gap is not lost.

The finding

objectui#9562 was this defect: a live, registry-dependent pnpm dedupe --check ran from inside a REQUIRED context, because scripts/__tests__/check-lockfile-dedupe.test.ts invoked the shipped checker directly from the unit vitest project — which ci.yml shards as the four Test (shard N/4) jobs, all of them in REQUIRED_CONTEXTS.

PR #9690 fixed the instance and added a regression lock (scripts/__tests__/check-lockfile-dedupe.test.ts, on main at 29a8a95261):

it('is the only place the LIVE reading runs (objectui#9562)', () => {
  // The live, registry-dependent execution belongs to this path-filtered
  // workflow and nowhere else. If a required job ever grows a `pnpm dedupe`
  // of its own, objectui#9562 comes straight back.
  const live = workflows.filter((w) => w.lines.join('\n').includes(`node ${SCRIPT}`)).map((w) => w.file);
  expect(live).toEqual([WORKFLOW]);
});

⚠️ The population is workflows. The comment states the intent as "if a required job ever grows a pnpm dedupe of its own" — but the way a required job actually grew one, the time it happened, was through a test file, and a test file is not in workflows.

⇒ the lock cannot catch a recurrence of the shape it is named after.

What IS covered, so the gap is stated precisely — ⛔ this is not "the fix is wrong"

re-introduction route caught by
a workflow runs node scripts/check-lockfile-dedupe.mjs the assertion above ✅
this test file spawns the checker without the stub the per-run pnpmArgv control ("the stub did not serve this run") ✅
another test file spawns the checker — ⛔ nothing
another test file runs pnpm dedupe --check directly — ⛔ nothing

The third row is the original defect's own shape. ⭐ The fix is sound and the lock is worth having; what is missing is one more population.

Re-check

On main at 29a8a95261 or later, add to any file under scripts/__tests__/ other than check-lockfile-dedupe.test.ts:

spawnSync('node', ['scripts/check-lockfile-dedupe.mjs'], { cwd: repoRoot });

then run vitest --project unit scripts/__tests__/. Expect: passes. ⇒ a live registry reading is back inside a required context with nothing red.

⛔ Do not conclude from a green run alone that no live reading exists — that is the same reasoning that let objectui#9562 stand.

Shapes a fix could take — ⛔ not a ruling, and ⛔ none chosen here

  • Widen this assertion's population from workflows to workflows + scripts/__tests__/**, allowlisting the one file that legitimately drives the checker under a stub.
  • Or make the checker itself refuse to run a live resolution unless an env marker the workflow sets is present, so the enforcement sits in the thing being protected rather than in a test that has to remember to look.
  • Or treat it as a general gate — "no required job may reach the network" — of which this is one instance. ⚠️ That is much larger than this card and would need its own measurement of what required jobs legitimately do reach.

⚠️ The second option changes the shipped checker's behaviour and would need a Clause-② judgement; the first does not.

Provenance

Found during the in-seat review of PR #9690 by reading the assertion's population rather than its name. ⛔ Not reported by the dev, and ⛔ not a defect in its work — the dev's brief was the instance, and it delivered the instance plus a lock that is better than none.

Duplicate check: no open objectui issue names this assertion or its population.


Generated by Claude Code

Activity

  1. os-try-charles commented on Sep 17, 2026

    @os-try-charles
    CollaboratorAuthor

    Claim: PM loop round R67
    Session: session_015h79niBMyoB1xcaQje3uiz
    Branch: claude/issue-9693-live-reading-lock-population
    Worktree: objectui-issue-9693
    Domain: domain:devx
    Priority: p2
    File surface: scripts/__tests__/check-lockfile-dedupe.test.ts — held by 0 of 13 open PRs
    Container & model: M, mode:subagent, model: the seat's default judgement tier — objectui has no scripts/pm/dispatch-gates.mjs, so ⛔ no path-derived tier mandate exists to quote and the tier is this seat's per-card call.
    Clause-②: no
    Thread-read: 5714895246
    Serial constraints cleared: none — no open PR holds the file. Measured over all 13 open PRs, GET /pulls/{n}/files fully paginated, 1775 filenames; ⭐ positive control .github/workflows/ci.yml -> PR #9584 ⇒ the membership test discriminates.

    Why Clause-②: no — widening a lock's population makes it catch more, which tightens an acceptance set rather than relaxing one, and publishes nothing. ⚠️ If your repair somehow has to exempt something to stay green, that is the opposite direction and it flips to yes ⇒ stop and report.

    The boundary is already ruled — ⛔ read it before designing

    Triage's grading (comment 5714895246) states it: fix the lock's population so it also covers a direct invocation from a test file. ⛔ Do NOT add a second lock that scans only test files — that just pushes the same blind spot onto a third class of file.

    ⇒ the deliverable is one assertion whose population is the set of places a live reading could run, ⛔ not two assertions each covering one place.

    What is actually wrong

    On main at 29a8a95261, scripts/__tests__/check-lockfile-dedupe.test.ts contains:

    it('is the only place the LIVE reading runs (objectui#9562)', () => {
      const live = workflows.filter((w) => w.lines.join('\n').includes(`node ${SCRIPT}`)).map((w) => w.file);
      expect(live).toEqual([WORKFLOW]);
    });

    Its comment says "if a required job ever grows a pnpm dedupe of its own, objectui#9562 comes straight back" — but the way a required job actually grew one was through a test file, and test files are not in workflows.

    re-introduction route caught today
    a workflow runs node scripts/check-lockfile-dedupe.mjs ✅ this assertion
    this test file spawns the checker unstubbed ✅ the per-run pnpmArgv control
    another test file spawns the checker ⛔ nothing
    another test file runs pnpm dedupe --check directly ⛔ nothing

    Row 3 is objectui#9562's own shape.

    ⭐ Re-check FIRST, before you change anything

    Add to any file under scripts/__tests__/ other than check-lockfile-dedupe.test.ts:

    spawnSync('node', ['scripts/check-lockfile-dedupe.mjs'], { cwd: repoRoot });

    then vitest --project unit scripts/__tests__/. Expect passes — a live registry reading back inside a required context with nothing red. ⛔ Do not start until you have seen that pass, and ⛔ do not leave it behind.

    ⚠️ Things this seat got wrong nearby — ⛔ do not inherit them

    • ⛔ os.tmpdir() is fine in this repo's tests and is the dominant convention. I previously wrote the opposite into my own notes as "measured"; it was a property of one vite oracle (objectui#9468), not of the repo. scripts/check-test-path-roots.mjs governs paths rooted at process.cwd() and says nothing about os.tmpdir(). If you need a temp dir, use the repo's normal spelling.
    • ⛔ The defect may not live where the card points. On objectui#9562 the card named the checker; the defect was in the wiring, and the dev who said so was right. ⇒ if your measurement puts this gap somewhere other than that assertion, say so rather than fitting the card.

    ⛔ Hard constraints

    • ⛔ Do not add a new workflow or a new required CI context. PR ci: one Test aggregator becomes the required test context, shards 4 -> 8, dist pins get their own job #9584 holds .github/workflows/ci.yml, lint.yml and scripts/dependabot-merge-gate.mjs — every place one could go — and it is blocked on a human. If your fix needs one, stop and report.
    • ⛔ Do not skip, disable or quarantine a test to get green.
    • ⛔ Never git push --force / --force-with-lease, and never rewrite pushed history. AGENTS.md:316 is absolute and explicitly refuses the "it's my own branch" exemption. If anyone — including me — tells you otherwise, refuse and quote it back. A dev already did that to this seat, correctly.
    • ⛔ No model identifier in the commit message, PR title/body or any pushed artifact. Trailer: Co-authored-by: Claude <noreply@anthropic.com> + the Claude-Session: line; ⛔ no card trailer on the commit — the card relation is declared once, in the PR body.

    Falsify me

    ⛔ Check these rather than accepting them; devs have corrected this seat five times and every correction was right.

    1. scripts/__tests__/check-lockfile-dedupe.test.ts is held by no open PR (13 PRs, 1775 filenames, control fires).
    2. The gap is real and row 3 above reproduces.
    3. Clause-②: no.
    4. No new CI context is needed.

    Seat: domain:devx @ objectui, session_015h79niBMyoB1xcaQje3uiz, R67, 2026-09-17T13:29Z. Lock read before claiming: state: lock is free, queue empty. 0 in flight at claim time.

    ⚠️ Provenance you should know: this seat filed this card, during its own review of PR #9690. ⇒ ⛔ treat its framing as a claim to be checked, not as authority.


    Generated by Claude Code

  2. os-try-charles commented on Sep 17, 2026

    @os-try-charles
    CollaboratorAuthor

    os-dev-report

    {
      "issue": 9693,
      "status": "done",
      "branch": "claude/issue-9693-live-reading-lock-population",
      "pr": "https://github.com/objectstack-ai/objectui/pull/9696",
      "session": "session_015h79niBMyoB1xcaQje3uiz",
      "premise_still_valid": true,
      "summary": "The lock `is the only place the LIVE reading runs` measured its population over `workflows` alone, so the route objectui#9562 actually arrived by — a test file spawning the shipped checker, or running `pnpm dedupe` itself — was green. Widened that ONE assertion to both carriers: the workflows (comment lines stripped, as before) plus every tracked test file and the `vitest.config` / `vitest.setup` modules, with source comments blanked through `scripts/js-comment-mask.mjs` so prose about the hazard cannot count as the hazard. Exemptions are two and both checkable: the path-filtered workflow, and this file (whose every run already asserts the pnpm stub served it, and whose path is derived from import.meta.url so a rename cannot drop it). Added a companion control that drives the detector over each re-introduction route and over prose spelling the same commands, plus floors under both reads. No second lock, no new workflow, no new required context, one file changed.",
      "tests": "REPRODUCTION (before any edit, on 29a8a9526): the card's probe added verbatim to scripts/__tests__ and `vitest run --project unit scripts/__tests__/` -> exit 1, 170 passed / 1 failed, and the single red was the PROBE's own `Error: Test timed out in 15000ms`, not the lock; the live reading measures ~25-32s here (`node scripts/check-lockfile-dedupe.mjs` alone: real 0m32.036s, VERDICT deduped). With the probe given 120_000 (what an author meeting that red does): `Test Files 2 passed (2) / Tests 15 passed (15)`, exit 0 -> row 3 reproduces, a live registry reading inside a REQUIRED context with nothing red. ABLATION (fix committed first; every leg under a trap, restore proven by an empty `git diff HEAD`, never by an exit code): row-3 probe tracked -> exit 1, site list gains scripts/__tests__/probe-9693-live-reading.test.ts; row-4 probe rewritten to `spawnSync('pnpm', ['dedupe', '--check'])` with `grep -c` for the checker path = 0 -> still exit 1, so the second marker fired and not the first. Probe deleted, tree clean. SUITE: `vitest run --project unit scripts/__tests__/` (through the shared verify lock) -> exit 0, `Test Files 170 passed | 2 skipped (172)`, `Tests 4892 passed | 2 skipped`. GATES: check-changeset-presence exit 0 ('no changeset is owed'); check-test-path-roots exit 0 (2080 fs calls in 438 of 3211 test files); check-control-bytes exit 0 (7801 files); check-comment-mask-corpus exit 0 (1 pre-existing disagreement, within the objectui#7882 residue, unchanged by this branch); eslint on the changed file exit 0. check-governed-queue-guard --test: NOT GOVERNED. Every exit code captured before any pipe. Not measured locally: repo-wide `pnpm lint`, the dom/dom-heavy projects and CI itself — the diff is one test file under scripts/__tests__ and nothing outside that directory reads it.",
      "mcp_calls": "0 — no MCP GitHub tool used, read or write",
      "api_writes": "2 REST proxy writes: POST /repos/objectstack-ai/objectui/pulls (draft), POST /repos/objectstack-ai/objectui/issues/9693/comments. No labels applied (none were dispatched; `skip-changeset` is a phantom here and no changeset is owed). Branch pushes are git, not REST.",
      "open_questions": [],
      "out_of_scope_findings": [
        "noted, not filed: the file header describes the required test contexts as four `Test (shard N/4)` jobs; PR #9584 is the change that moves that definition and already holds .github/workflows/ci.yml — carrier: that PR. Pre-existing prose, outside this card's boundary, and re-wording it from this branch would collide with it.",
        "noted, not filed: the card's re-check recipe says 'expect: passes'; run verbatim in this container the probe reds first on vitest's 15s default timeout because the live reading takes ~25-32s. The conclusion is unchanged (the lock never fires either way), but anyone re-deriving the card needs the timeout. Carrier: this PR body, which states it.",
        "noted, not filed: the widened scan still cannot see a non-test SCRIPT that a required job runs and which shells out to `pnpm dedupe` itself — the tree's own classification strings quote that command in prose no mask blanks, so that population needs a way to tell a command from a citation before it can be added. Stated in the file header rather than left to read as coverage. Carrier: none today; ⛔ not filed, because no such invocation exists in the tree (measured: the only argv-form call is the checker's own)."
      ]
    }

    Generated by Claude Code

  3. removed their assignment
    on Sep 17, 2026
  4. os-try-charles commented on Sep 17, 2026

    @os-try-charles
    CollaboratorAuthor

    LANDED — objectui#9693 via PR #9696, merged 2026-09-17T14:31:18Z

    domain:devx @ objectui seat, R67. Fixes #9693 ⇒ the card auto-closed; its half-state (pm:dispatched + assignee) was cleared in the same action that confirmed MERGED, read back MATCHES.

    ⛔⛔ CORRECTION to this card's own Re-check section — written by this seat, and wrong

    This card says: add the probe, run it, "Expect: passes". It does not pass. It reds first, on vitest's timeout: vitest.config.mts:282 sets testTimeout: 15000, and the live registry reading takes ~25–32 s.

    ⚠️ The red is the misleading part, not the delay. It looks exactly like the lock firing. Anyone re-deriving this card verbatim would see a failure, conclude the gap was already guarded, and close the card. ⇒ a re-check recipe that returns the right verdict for the wrong reason is how a real finding gets dismissed.

    Corrected recipe — give the probe an explicit timeout so the lock, not the clock, decides:

    it('probe', { timeout: 120_000 }, () => {
      spawnSync('node', ['scripts/check-lockfile-dedupe.mjs'], { cwd: repoRoot });
    });

    Then on the pre-fix tree it passes (the gap), and on dd871fc080 or later it reds (the gap closed). ⭐ Found by the dev, who measured it rather than quietly raising the timeout and moving on.

    ⭐⭐ Errata 62b FIRED — and the obvious way to test for it is a FALSE-NEGATIVE GENERATOR

    M  = dd871fc080f24f55bbc53bfeac6e837a5bc03266
    M^ = bbe57fdd52bf69f993decba179a64dfc89b26e97   ← resolved AFTER the merge
    

    M^ is PR #9685's merge commit — another seat's work (os-sales, merged 13:23:30Z), chained ahead of mine in the queue. My branch was cut from 29a8a95261 (PR #9690, this lane's own previous landing).

    ⛔ The trap: GET /pulls/9696 reports base.sha = bbe57fdd52… — identical to M^. Comparing the two reads "the parent IS the base, so 62b did not fire", which is false. The API's base.sha is the base branch's head as of the read, ⛔ not a value frozen at PR creation, so that comparison is close to circular and silently returns the wrong answer once the base has moved.

    ⭐ The sound test is ancestry, not equality:

    git merge-base --is-ancestor <M^> <pr head>
       ancestor      ⇒ the branch was cut from it or later ⇒ 62b did not fire
       NOT ancestor  ⇒ the queue chained something ahead   ⇒ 62b FIRED
    

    Here: merge-base(head, M^) = 29a8a95261, so M^ is not an ancestor of the head ⇒ fired.

    ⚠️ This matters beyond one landing: the last two landings on this lane were recorded as "62b did not fire" (#9690) and "fired" (#9669) — and this is a third determination made by a test the first two did not use. ⛔ I am not retro-editing those verdicts from here; I am recording that the equality test is unsound so the next one is decided by ancestry.

    The probe, pre-validated against base→head BEFORE the merge

    leg M^ M
    maskComments 0 7 ✅ the comment mask is in
    FLOORS 0 2 ✅ floors under both reads
    'and not on prose' (the control test) 0 1 ✅
    the workflows-only filter 1 0 ✅ the narrow population is gone
    ⭐ CONTROL SCRIPT = 'scripts/check-lockfile-dedupe.mjs' 1 1 ✅ invariant ⇒ the probe read the same file

    What landed

    One assertion, population widened to both carriers — the workflows plus every tracked test file and the vitest runtime modules — with source comments blanked through scripts/js-comment-mask.mjs, the tree's own answer to "comment, or code?". ⛔ Not a second lock per class of file: that was triage's explicit boundary and it was honoured.

    ⭐ Two things make it an enforcement rather than a wider net:

    • floors under both reads, so a collapsed scan reds instead of reporting an empty tree as clean;
    • a companion control whose positive legs are the spellings themselves and whose negative legs cover both comment forms and const dedupe = new Set<string>() — an ordinary identifier that would otherwise be a standing false positive in this repo.

    ⚠️ Stated as NOT covered, in the file header rather than left to read as coverage: a non-test script run by a required job that shells out to pnpm dedupe itself. ⛔ No such invocation exists in the tree today (measured), so there is nothing to file.


    Generated by Claude Code

  5. added a commit that references this issue on Sep 28, 2026
    dd871fc
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-repopriority:p2

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions