Repository navigation
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
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]);
});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
workflowstoworkflows + 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.
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
os-try-charles commentedon Sep 17, 2026
Claim: PM loop round R67
Session:
session_015h79niBMyoB1xcaQje3uizBranch:
claude/issue-9693-live-reading-lock-populationWorktree:
objectui-issue-9693Domain:
domain:devxPriority:
p2File surface:
scripts/__tests__/check-lockfile-dedupe.test.ts— held by 0 of 13 open PRsContainer & model:
M,mode:subagent,model: the seat's default judgement tier— objectui has noscripts/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}/filesfully paginated, 1775 filenames; ⭐ positive control.github/workflows/ci.yml -> PR #9584⇒ the membership test discriminates.Why⚠️ If your repair somehow has to exempt something to stay green, that is the opposite direction and it flips to
Clause-②: no— widening a lock's population makes it catch more, which tightens an acceptance set rather than relaxing one, and publishes nothing.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
mainat29a8a95261,scripts/__tests__/check-lockfile-dedupe.test.tscontains:Its comment says "if a required job ever grows a
pnpm dedupeof 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 inworkflows.node scripts/check-lockfile-dedupe.mjspnpmArgvcontrolpnpm dedupe --checkdirectlyRow 3 is objectui#9562's own shape.
⭐ Re-check FIRST, before you change anything
Add to any file under
scripts/__tests__/other thancheck-lockfile-dedupe.test.ts: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.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.mjsgoverns paths rooted atprocess.cwd()and says nothing aboutos.tmpdir(). If you need a temp dir, use the repo's normal spelling.⛔ Hard constraints
Testaggregator becomes the required test context, shards 4 -> 8, dist pins get their own job #9584 holds.github/workflows/ci.yml,lint.ymlandscripts/dependabot-merge-gate.mjs— every place one could go — and it is blocked on a human. If your fix needs one, stop and report.git push --force/--force-with-lease, and never rewrite pushed history.AGENTS.md:316is 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.Co-authored-by: Claude <noreply@anthropic.com>+ theClaude-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.
scripts/__tests__/check-lockfile-dedupe.test.tsis held by no open PR (13 PRs, 1775 filenames, control fires).Clause-②: no.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.Generated by Claude Code
os-try-charles commentedon Sep 17, 2026
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
os-try-charles commentedon Sep 17, 2026
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 backMATCHES.⛔⛔ 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:282setstestTimeout: 15000, and the live registry reading takes ~25–32 s.Corrected recipe — give the probe an explicit timeout so the lock, not the clock, decides:
Then on the pre-fix tree it passes (the gap), and on
dd871fc080or 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^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 from29a8a95261(PR #9690, this lane's own previous landing).⛔ The trap:
GET /pulls/9696reportsbase.sha=bbe57fdd52…— identical toM^. Comparing the two reads "the parent IS the base, so 62b did not fire", which is false. The API'sbase.shais 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:
Here:
merge-base(head, M^)=29a8a95261, soM^is not an ancestor of the head ⇒ fired.The probe, pre-validated against base→head BEFORE the merge
M^MmaskCommentsFLOORS'and not on prose'(the control test)SCRIPT = 'scripts/check-lockfile-dedupe.mjs'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:
const dedupe = new Set<string>()— an ordinary identifier that would otherwise be a standing false positive in this repo.pnpm dedupeitself. ⛔ No such invocation exists in the tree today (measured), so there is nothing to file.Generated by Claude Code
test(ci): widen the live-reading lock to what required jobs RUN, not …