Repository navigation
invoked-as.mjs's "Nothing here enforces this yet" section is stale in both halves — the gate landed and the sweep completed, but the header still tells readers neither exists #6243
Description
Found while implementing #6230 (unrelated card — the eager-closure budget comment). Filed unassigned, observation class. Nothing is broken at runtime; the defect is that a header written to be the authoritative answer now asserts four things that are false, and explicitly instructs the reader to believe it over the tree.
What the header says
scripts/invoked-as.mjs, section ## Nothing here enforces this yet -- the rule is a CONVENTION:
An earlier version of this paragraph said
scripts/check-entry-guard.mjsenforces the rule [...]. It does not. That file has never existed in this repository.
git grep -n 'check-entry-guard'-> ONE hit: this paragraph
git grep -l 'process.argv[1]' -- scripts-> 30 files
The 30 files are this one plus TWENTY-NINE hand-typed guards [...] in NINE textually distinct spellings and not one carrying a realpath leg
Both halves -- the gate and the sweep -- are tracked in #6092. Until that lands,
isEntrypointhere is a convention [...] do not read this file as evidence that the tree already has.
Line 17 of the same header points at this section as the thing to read before concluding otherwise:
read "## Nothing here enforces this yet" below before concluding otherwise
What is actually on origin/main
#6092 — the issue the header names as tracking both halves — is closed. Both halves landed:
scripts/check-entry-guard.mjsexists (git cat-file -e origin/main:scripts/check-entry-guard.mjssucceeds; last touched by refactor(tooling): build the lucide gate's two lookup maps lazily, taking rule 2's baseline to zero #6156).- It is wired in
package.jsonascheck:entry-guard, and it is a real blocking gate. Run on0409b766d:
✓ check:entry-guard: 46 scripts/ file(s) — no entry guard outside the baseline;
0 file(s) still hand-type one (0 occurrence(s), ⛔ SHRINK-ONLY, objectui#6092);
41 export bindings, 41 of them inert on import (0 known-unsafe, ⛔ SHRINK-ONLY).
So all four claims are now wrong, and in the same direction:
| Header claim | Reality on origin/main |
|---|---|
| the file "has never existed in this repository" | it exists and is a wired gate |
git grep 'check-entry-guard' → one hit, this paragraph |
at minimum the script, the package.json script entry, and the gate's own output |
| 29 hand-typed guards remain, in nine spellings | 0 file(s) still hand-type one, shrink-only ratcheted at 0 |
"Until that lands, isEntrypoint here is a convention" |
it lands; the convention is enforced |
Why it is worth a card rather than nothing
This is not ordinary comment rot. The header is written as the single authoritative answer to "was this module run, or imported?", and this section exists specifically to stop a reader from over-trusting it — so a reader who follows its instruction is now actively told that a rule with a blocking gate behind it is unenforced, and that a sweep which completed is still outstanding. The cheapest wrong conclusion available is "nothing stops a thirtieth spelling from being typed next week", which is exactly what the shrink-only ratchet now does stop.
It is also self-referentially the failure this file documents: prose ported from objectstack, describing objectstack's tree, that stayed put while this tree changed underneath it — the same mechanism that produced the earlier wrong version of this very paragraph, which the paragraph itself narrates.
Disposition
Not choosing between these; both are cheap:
- Rewrite the section to describe the tree as it is — the gate exists, the sweep is done, the ratchet is shrink-only at 0 — and keep the measured history as history rather than as present tense.
- Delete the section. Its whole purpose was to prevent readers assuming an enforcement that did not exist; that enforcement now exists, so the warning has nothing left to do.
Either way the measurements should be re-taken rather than edited in place: the 7c96c9420 figures are a snapshot, and re-anchoring them to a current commit is what stops the next round of this.
packages/cli/src/utils/invocation.ts in objectstack, per the "## The siblings" section) carry the same stale paragraph. Worth checking in the same pass, since that section says "change one, change the others".
Refs: #5984 (the port that brought the prose) · #6078 · #6092 (closed — the gate and the sweep) · #6156 (last touched the gate).
Generated by Claude Code
Activity
yinlianghui-tw commentedon Aug 25, 2026
Claiming this card.
session_019b5UBNMtTzKbVtZZGvFuxeclaude/issue-6243-invoked-as-stale-enforcement-note../objectui-issue-6243No prior claim comment existed on this issue when I read it (0 comments). All agents share one GitHub identity, so if you see an earlier claim with a different session ID, mine is the racing one — say so and I will stand down.
Plan: verify every row of the evidence table against
origin/mainfirst (including runningpnpm check:entry-guardand quoting its verdict line). If any row does not reproduce I stop and report rather than "fixing" a card that is wrong. Scope isscripts/invoked-as.mjsin this repo only — the objectstack sibling (packages/cli/src/utils/invocation.ts) gets checked and reported, never edited here.Generated by Claude Code
Generated by Claude Code
claude commentedon Aug 25, 2026
Concentrated triage batch (final tail):
finding→pm:queue, Task, S (domain:devxstands) — the header written to be the authoritative answer now asserts four false things and tells the reader to trust it over the tree. Comment-only rewrite to the current facts (the gate exists, the sweep completed; name them), keeping the header's self-verifying grep recipes updated so the next drift is self-evident.skip-changeset.Generated by Claude Code
yinlianghui-tw commentedon Aug 25, 2026
{ "issue": 6243, "status": "done", "branch": "claude/issue-6243-invoked-as-stale-enforcement-note", "pr": "https://github.com/objectstack-ai/objectui/pull/6260", "premise_still_valid": true, "summary": "Every row of the card's evidence table reproduces on origin/main = 2dc4aa709: scripts/check-entry-guard.mjs exists (cat-file -e rc 0), 'check-entry-guard' greps to 26 hits not one, `git grep -l 'process.argv[1]' -- scripts` is 3 files (the predicate, the gate and js-comment-mask.mjs, none of them a guard) not 30, and objectui#6092 is closed/completed. Took disposition 1 (rewrite, not delete): the header's line 17 names the section as the thing to read 'before concluding otherwise', so deletion leaves a dangling pointer and becomes two edits; deletion also removes the wrong half, since the warning against over-trusting this ported header is still exactly right and only its direction expired; and the section's narrative is self-referentially the failure the file documents. Section retitled '## What enforces this, and what it took to get here', figures RE-TAKEN on 2dc4aa709 with that commit named in the text, the 7c96c9420 snapshot kept as history under its own commit, and a closing instruction to re-take and re-name rather than edit figures in place. Two further sentences carried the identical claim and moved with it or the file would contradict itself: the header line 'THIS repository has not been swept, and no gate here enforces the rule' (plus its pointer), and 'check-skills-paths.mjs carries the no-realpath spelling, as do 27 of its neighbours' (now past tense). Comment-only: 89 changed lines, 0 outside a block-comment body. No changeset — see below.", "tests": "All on the final commit ca12cb8b, clean tree; exit codes captured by redirect before any pipe; verdict lines are each gate's own output. check:entry-guard rc 0 -> '✓ check:entry-guard: 47 scripts/ file(s) — no entry guard outside the baseline; 0 file(s) still hand-type one (0 occurrence(s), ⛔ SHRINK-ONLY, objectui#6092); 42 export bindings, 42 of them inert on import (0 known-unsafe, ⛔ SHRINK-ONLY).' · check-entry-guard --self-test rc 0 -> '✓ check-entry-guard self-test: 63 cases pass …' · invoked-as --self-test rc 0 -> '✓ invoked-as self-test: 12 cases pass (real symlink, different-name symlink, percent-encoding path, and both import directions).' · check-doc-links.mjs rc 0 -> 'Links are valid across 15 scan roots.' · check:doc-fences rc 0 -> '✅ check:doc-fences — every TypeScript block in 223 document(s) …' · check:control-bytes rc 0 -> '✅ check-control-bytes: OK (scanned 5157 tracked text file(s); skipped 85 binary).' · check:shell-escape-residue rc 0 -> '✅ check-shell-escape-residue: OK (4/4 root(s) resolved …)' · type-check:scripts rc 0, pnpm echoed '> tsc -p tsconfig.scripts.json' as positive control against the zero-match no-op · lint:root UNNARROWED rc 0 -> '✖ 28 problems (0 errors, 28 warnings)', all pre-existing no-explicit-any in e2e/, vitest.setup.base.ts and two scripts/__tests__/vite-* files, none touched here · vitest run scripts/ rc 0 -> 'Test Files 77 passed (77) · Tests 2194 passed (2194)' · also green: check-node-esm-load.mjs (builds all 43 packages), check-pre-install-import-graph.mjs, check-vi-mock-specifiers.mjs, check-eager-closure-budget.mjs. ONE DECLARED NARROWING: the full root suite (pnpm test) was started under the shared verify lock and killed by this container's ~10-minute foreground cap (SIGTERM, exit 143) — that is CI's run. Narrowed to `vitest run scripts/`, and the narrowing is measured: (a) population = 1 changed file, 89 changed lines, 0 outside a block-comment body (`git diff -U0 | grep -cvE '^[+-] \\*'` -> 0), so runtime behaviour is unchanged and its own self-test confirms it independently; (b) `git grep -l 'invoked-as' -- '**/*.test.ts' '**/*.test.tsx' '**/*.test.mts'` -> 5 files, ALL under scripts/__tests__/, entirely inside the narrowed run, and run explicitly too (5 passed, 144 tests); (c) no test pins this prose — entry-guard-wiring.test.ts states in its own header that it deliberately asserts no counts and no header text. NOTE on one trap hit and reported rather than hidden: the first attempt was `pnpm test -- --maxWorkers=2`, which the repo's vitest-invocation-guard correctly REJECTED (objectui#3288: args after `--` are silently dropped); re-run as `pnpm exec vitest run … --maxWorkers=2`. CHANGESET: none, deliberately. check-changeset-presence.mjs exits 0 either way so it is not deciding it, but its printed verdict is '✅ No source of a released package changed in this range, so no changeset is owed.' — the diff is prose in a scripts/ tool no package publishes, with no behaviour a release note could describe; precedent #6216 and #6212 changed real gate behaviour and carried none.", "open_questions": [], "out_of_scope_findings": [ "NOT FILED (per dispatch: PM will file) — sibling check result, objectstack origin/main = 497ded780, read-only, no edit: NEITHER objectstack copy is stale. packages/cli/src/utils/invocation.ts (186 lines) has zero occurrences of 'check-entry-guard', 'never existed', 'CONVENTION', 'Nothing here enforces', 'Until that lands' — it never carried this paragraph. objectstack's own scripts/invoked-as.mjs, the source of the ported prose, carries the CORRECT original ('scripts/check-entry-guard.mjs enforces this: a process.argv[1] in an entry-guard position anywhere in scripts/** that is not this module is a failure'), true in that tree. So nothing is owed there for this defect and no cross-repo card is needed for it.", "NOT FILED (observation class, for PM to judge) — the cross-repo pairing is asserted UNILATERALLY. objectui's invoked-as.mjs says 'All three copies … Change one, change the others', but objectstack's invocation.ts contains no occurrence of 'objectui', 'siblings' or 'change the others', and objectstack's scripts/invoked-as.mjs names only '## The sibling in packages/cli' (singular, in-repo). So an agent editing either objectstack copy has nothing telling it a third copy exists in another repo — the obligation is visible from exactly one of the three ends. Cheap fix would be a reciprocal pointer in the objectstack copies; needs its own worktree and card." ] }Generated by Claude Code
yinlianghui-tw commentedon Aug 25, 2026
os-dev-report
(Supersedes comment 5405380159 — the HTML-comment marker on that one did not survive GitHub's sanitizer, so this copy leads with the literal text instead. Same report, plus the
skip-changesetfinding below. There is no comment-edit path from this seat and the REST API is blocked for it, hence a second comment rather than an edit.){ "issue": 6243, "status": "done", "branch": "claude/issue-6243-invoked-as-stale-enforcement-note", "pr": "https://github.com/objectstack-ai/objectui/pull/6260", "premise_still_valid": true, "summary": "Every row of the card's evidence table reproduces on origin/main = 2dc4aa709: scripts/check-entry-guard.mjs exists (cat-file -e rc 0), 'check-entry-guard' greps to 26 hits not one, `git grep -l 'process.argv[1]' -- scripts` is 3 files (the predicate, the gate, and js-comment-mask.mjs — none of them a guard) not 30, and objectui#6092 is closed/completed. Took disposition 1 (rewrite, not delete): line 17 names the section as the thing to read 'before concluding otherwise', so deletion leaves a dangling pointer and is two edits not one; deletion also removes the wrong half, since the warning against over-trusting this ported header is still exactly right and only its DIRECTION expired; and the section's narrative is self-referentially the failure the file documents. Section retitled '## What enforces this, and what it took to get here', figures RE-TAKEN on 2dc4aa709 with that commit named in the text, the 7c96c9420 snapshot kept as history under its own commit, and a closing instruction to re-take and re-name rather than edit figures in place. Two further sentences carried the identical claim and had to move with it or the file contradicts itself two paragraphs later: the header line 'THIS repository has not been swept, and no gate here enforces the rule' (plus its pointer), and 'check-skills-paths.mjs carries the no-realpath spelling, as do 27 of its neighbours' (now past tense). Comment-only: 89 changed lines, 0 outside a block-comment body. No changeset and no skip-changeset label — reasoning in `tests` and in the findings below.", "tests": "All on the final commit ca12cb8b, clean tree; exit codes captured by redirect before any pipe; every line quoted is the gate's own printed verdict. check:entry-guard rc 0 -> '✓ check:entry-guard: 47 scripts/ file(s) — no entry guard outside the baseline; 0 file(s) still hand-type one (0 occurrence(s), ⛔ SHRINK-ONLY, objectui#6092); 42 export bindings, 42 of them inert on import (0 known-unsafe, ⛔ SHRINK-ONLY).' · check-entry-guard --self-test rc 0 -> '✓ check-entry-guard self-test: 63 cases pass …' · invoked-as --self-test rc 0 -> '✓ invoked-as self-test: 12 cases pass (real symlink, different-name symlink, percent-encoding path, and both import directions).' · check-doc-links.mjs rc 0 -> 'Links are valid across 15 scan roots.' · check:doc-fences rc 0 -> '✅ check:doc-fences — every TypeScript block in 223 document(s) …' · check:control-bytes rc 0 -> '✅ check-control-bytes: OK (scanned 5157 tracked text file(s); skipped 85 binary).' · check:shell-escape-residue rc 0 -> '✅ check-shell-escape-residue: OK (4/4 root(s) resolved …)' · type-check:scripts rc 0, pnpm echoed '> tsc -p tsconfig.scripts.json' as the positive control against the zero-match no-op · lint:root UNNARROWED rc 0 -> '✖ 28 problems (0 errors, 28 warnings)', all pre-existing no-explicit-any in e2e/, vitest.setup.base.ts and two scripts/__tests__/vite-* files, none touched here · vitest run scripts/ rc 0 -> 'Test Files 77 passed (77) · Tests 2194 passed (2194)' · also green: check-node-esm-load.mjs (builds all 43 packages), check-pre-install-import-graph.mjs, check-vi-mock-specifiers.mjs, check-eager-closure-budget.mjs. ONE DECLARED NARROWING: the full root suite (pnpm test) was started under the shared verify lock and killed by this container's ~10-minute foreground cap (SIGTERM, exit 143) — that run is CI's. Narrowed to `vitest run scripts/`, and the narrowing is measured rather than assumed: (a) population = 1 changed file, 89 changed lines, 0 outside a block-comment body (`git diff -U0 | grep -cvE '^[+-] \\*'` -> 0), so runtime behaviour is unchanged, confirmed independently by the module's own self-test; (b) `git grep -l 'invoked-as' -- '**/*.test.ts' '**/*.test.tsx' '**/*.test.mts'` -> 5 files, ALL under scripts/__tests__/, entirely inside the narrowed run, and run explicitly as well (5 passed, 144 tests); (c) no test pins this prose — entry-guard-wiring.test.ts states in its own header that it deliberately asserts no counts and no header text. TRAP HIT, reported rather than hidden: the first attempt was `pnpm test -- --maxWorkers=2`, which the repo's vitest-invocation-guard correctly REJECTED (objectui#3288 — args after `--` are silently dropped); re-run as `pnpm exec vitest run … --maxWorkers=2`. CHANGESET: none, deliberately. check-changeset-presence.mjs exits 0 either way so it is not deciding this, but its printed verdict is '✅ No source of a released package changed in this range, so no changeset is owed.' — the diff is prose in a scripts/ tool no package publishes, with no behaviour a release note could describe; precedents #6216 and #6212 changed real gate behaviour and carried none.", "open_questions": [], "out_of_scope_findings": [ "CONFLICT FLAGGED, NOT SILENTLY RESOLVED — the triage comment on this card ends with '`skip-changeset`', and I did NOT apply that label. Reason, from this repo's own tree: `git grep 'skip-changeset' -- .github scripts package.json` on origin/main returns exactly ONE hit, and it is scripts/__tests__/ci-cd-pipeline-doc.test.ts:184 recording objectui#3724 — a phantom `.github/WORKFLOWS.md` inventory documented 'a changeset gate skippable with a `skip-changeset` label; NEITHER THE WORKFLOW NOR THE LABEL WAS EVER REAL'. No objectui workflow or gate reads it (objectstack is the repo where it is wired: lint.yml, pr-automation.yml, check-empty-changeset.mjs, check-whole-set-label-write.mjs). The label OBJECT does now exist in objectui (color ededed, empty description — the signature of one auto-minted by a label write), which is exactly how a phantom mechanism gets re-entrenched: the next agent reads its existence as evidence it does something. Applying it would be theatre on a card whose whole subject is prose asserting an enforcement that is not there. PM to overrule if I have this wrong.", "NOT FILED (per dispatch: PM will file) — SIBLING CHECK RESULT, objectstack origin/main = 497ded780, read-only, no worktree, no edit: NEITHER objectstack copy is stale. packages/cli/src/utils/invocation.ts (186 lines) has zero occurrences of 'check-entry-guard', 'never existed', 'CONVENTION', 'Nothing here enforces' or 'Until that lands' — it never carried this paragraph. objectstack's own scripts/invoked-as.mjs, the source of the ported prose, carries the CORRECT original ('scripts/check-entry-guard.mjs enforces this: a process.argv[1] in an entry-guard position anywhere in scripts/** that is not this module is a failure'), true in that tree. So nothing is owed in objectstack for THIS defect and no cross-repo card is needed for it.", "NOT FILED (observation class, for PM to judge) — the cross-repo pairing is asserted UNILATERALLY. objectui's invoked-as.mjs says 'All three copies … Change one, change the others', but objectstack's invocation.ts contains no occurrence of 'objectui', 'siblings' or 'change the others', and objectstack's scripts/invoked-as.mjs names only '## The sibling in packages/cli' (singular, in-repo). An agent editing either objectstack copy has nothing telling it a third copy lives in another repo — the obligation is visible from exactly one of its three ends, which is the shape that produced this card. Cheap fix is a reciprocal pointer in the two objectstack copies; needs its own worktree and its own card." ] }Generated by Claude Code
test(ci): pin the `skip-changeset` phantom — nothing wires it, and th…
test(ci): pin the `skip-changeset` phantom — nothing wires it, and th…