You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
invoked-as.mjs names scripts/check-entry-guard.mjs as its enforcement; that file does not exist, and 27 hand-typed entry guards still carry the spelling it documents as silently inert #6078
Filed unassigned by the dev seat implementing #5793 (branch claude/issue-5793-spec-range-floors, session session_019b5UBNMtTzKbVtZZGvFuxe). Out of that card's scope entirely — noticed while adopting isEntrypoint for a new gate. Recording it, not acting on it.
What was measured
scripts/invoked-as.mjs landed recently (#5984, ported from objectstack). Its header states, as the reason the module exists at all:
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. That gate is what stops a TWELFTH spelling, which is the whole reason this file exists rather than a one-time sweep.
Measured on a1c41c516:
scripts/check-entry-guard.mjsdoes not exist. The string check-entry-guard appears in exactly one place in the whole repository — that sentence in invoked-as.mjs itself. Nothing in package.json or .github/workflows/ runs such a gate.
All 27 use the plain resolve(process.argv[1]) === fileURLToPath(import.meta.url) shape with no realpath leg — which is precisely the spelling invoked-as.mjs's own header documents as the failure that motivated it:
Node resolves symlinks for the module graph but leaves process.argv[1] as the caller typed it. Reach a script through a symlink and the two name different paths, the guard answers false, and the script does NOTHING — with exit 0 and no output.
The silent direction is the one that matters, and invoked-as.mjs argues it better than this issue can: CI wrappers hold result.status only, so an inert child is a green gate. Several of the 27 are blocking checks — check-published-dist-tooling.mjs guards the publish path, check-doc-component-types.mjs and check-action-forward-parity.mjs gate pull requests.
No current invocation goes through a symlink, so nothing is failing today. What is broken now is the claim: a header states a gate enforces the single-spelling rule, that gate is absent, and the sweep it was supposed to protect never happened either. Both halves of the port landed as documentation. That is the same declared≠enforced shape check-spec-symbol-derivation.mjs's header calls "a planted premise for the next session" — an agent reading invoked-as.mjs reasonably concludes the tree is already converted and enforced, and neither is true.
The call to make
Probably two pieces, and they are separable:
Port or write the missing gate, so a twenty-eighth hand-typed spelling cannot land. Without it, converting the 27 is a one-time sweep that starts rotting the day it merges — the explicit argument the header makes.
Convert the 27 call sites to isEntrypoint(import.meta.url). Mechanical, but it is a lot of blocking gates to touch at once and wants its own review; it may be worth doing after (1), since the gate names its own worklist.
If the enforcement is genuinely not wanted here, the alternative is to correct invoked-as.mjs's header so it stops asserting a gate that does not exist — the claim is what makes this expensive, not the spellings.
Refs: #5984 (the port that introduced the module and its one adopter) · #5793 (the card whose seat found it).
{
"issue": 6078,
"status": "done",
"branch": "claude/issue-6078-invoked-as-false-gate-claim",
"pr": "https://github.com/objectstack-ai/objectui/pull/6096",
"premise_still_valid": true,
"summary": "The card's premise holds: scripts/check-entry-guard.mjs does not exist here and the header asserted it as enforcement. Root cause measured beyond the card: #5984 ported invoked-as.mjs out of objectstack with its prose but without the gate or the sweep, so FOUR paths the header names resolve only in objectstack (check-entry-guard.mjs, pm/check-governed-merges.mjs, packages/cli/src/utils/invocation.ts, js-comment-mask.mjs) while all five exist there at 644ad5043. The correction therefore re-attributes four passages rather than deleting one sentence, and replaces the borrowed objectstack symlink example with the same measurement taken on a real objectui blocking gate. Two of the card's figures moved and are corrected: ONE module imports isEntrypoint (not two - the #5793 gate has not landed on main), and 29 hand-typed guards remain (not 27 - check-designer-field-key-parity.mjs landed since a1c41c516). One card claim was simply wrong: the guards are not all one shape, they are NINE textually distinct spellings, one of which (check-node-esm-load.mjs:847) is the percent-encoding failure the header itself warns about. Conversion and the gate port are out of scope per the PM ruling and are filed as #6092. One bounded in-place fix in the same file, named in the PR body: a self-test case reached for js-comment-mask.mjs (objectstack-only), so 'an unrelated existing file is not this module' had silently become a duplicate of the case below it; it now names a real neighbour with an existence assertion so it cannot degrade that way again.",
"tests": "All runs on f726727cd (the final commit; clean tree, verified via git status --porcelain). Verdict lines quoted are the gates' own, not a bare $?.\n\nMEASUREMENTS (each with the command that produced it, on origin/main @ 7c96c9420):\n- Gate absent, with positive control: `ls scripts/check-entry-guard.mjs` -> 'No such file or directory'; `ls scripts/check-control-bytes.mjs` -> exists, 16244 bytes. `git ls-files | grep -c 'check-entry-guard'` -> 0; same for check-control-bytes -> 2. `git grep -n 'check-entry-guard'` -> exactly 1 hit, scripts/invoked-as.mjs:73 (the sentence itself); `git grep -l 'check-control-bytes' | wc -l` -> 16. The single hit is over ALL tracked files, so package.json and .github/workflows/ are covered - nothing runs such a gate.\n- Provenance: the same five paths checked in /home/user/objectstack @ 644ad5043 - all five EXIST there, four are MISSING in objectui. objectstack's check-entry-guard.mjs is 787 lines and wired as `check:entry-guard` in package.json.\n- Hand-typed guards: `git grep -l 'process\\.argv\\[1\\]' -- 'scripts/'` -> 30 files; minus invoked-as.mjs itself -> 29 guards (28 .mjs + scripts/shadcn-sync.js). Card said 27; reconciled by `comm -13` against the same grep at a1c41c516 -> exactly one file added (check-designer-field-key-parity.mjs), none removed.\n- No-realpath-leg shape: 28 of the 29. Only scripts/shadcn-sync.js:1048-1057 carries a realpath leg (`realpathSync(resolved) === __filename`).\n- Distinct spellings: 9 across the 28 .mjs, via `git grep -n ... | cut -d: -f3- | sort | uniq -c` (12x, 5x, 3x, 2x, 2x, 1x, 1x, 1x, 1x). Card implied one shape.\n- isEntrypoint importers: `git grep -l 'isEntrypoint' -- .` -> 2 files = invoked-as.mjs itself + ONE adopter, scripts/pm/check-half-states.mjs:777. Card said two adopters.\n\nSYMLINK INERTNESS - DEMONSTRATED, not inherited. One untracked guide file made deliberately wrong (removed by an EXIT/INT/TERM trap in the same command; `git status --porcelain` empty afterwards), then a real blocking gate run two ways against the identical defective tree:\n node scripts/check-skills-paths.mjs -> exit=1, 696 bytes naming the dead path\n node <scratchpad>/link/check-skills-paths.mjs -> exit=0, 0 bytes\nSo a RED gate reports clean through a symlink. Separately measured, since the header asserts it: the ``import.meta.url === `file://${argv[1]}` `` spelling (check-node-esm-load.mjs:847) goes INERT in a directory named 'a#b c' with no symlink at all - file:///.../a%23b%20c/enc.mjs vs /.../a#b c/enc.mjs. Also checked before asserting and found NOT a bug: regenerate-known-schema-types.mjs:187 omits resolve() on argv[1], but node absolutizes argv[1] itself (measured by invoking a probe relatively).\n\nREVERSE VERIFICATION of the new existence assertion. Predicted direction: red. Mutation proven on disk BEFORE reading any result, by anchored greps in both directions: injected \"'js-comment-mask.mjs');\" count=1, removed \"'check-control-bytes.mjs');\" count=0, `git diff --stat` = 1 file changed, 1 insertion(+), 1 deletion(-). Run: `node scripts/invoked-as.mjs --self-test` -> exit=1, \"1 of 12 case(s) failed\", and the failing case is the new assertion only - the OLD case still passed with the dead path, which is exactly the vacuity being closed. Restored via `git checkout --` (the fix was committed first), restoration proven by the same greps inverted, re-run green 12/12, git status clean. No build is involved: this module is plain .mjs run directly, not resolved through any package dist, so there is no stale-artifact leg to rebuild.\n\nGATES (exit captured before any pipe; verdict lines are the gates' own):\n- node scripts/invoked-as.mjs --self-test -> exit 0, \"invoked-as self-test: 12 cases pass\" (was 11)\n- npx vitest run scripts/__tests__ --maxWorkers=2, from the repo ROOT (never package-scoped) -> exit 0, \"Test Files 65 passed (65)\", \"Tests 1789 passed (1789)\"\n- pnpm check:control-bytes -> exit 0, \"check-control-bytes: OK (scanned 5036 tracked text file(s); skipped 85 binary)\"\n- pnpm check:skills-paths -> exit 0, \"check-skills-paths: OK (93/94 stated path(s) resolve across 18 guide file(s); 1 baselined)\" - also confirms the temp probe file is gone\n- pnpm check:esm-specifiers -> exit 0, \"Specifier leg: no un-ledgered package emits an extensionless relative specifier.\"\n- pnpm check:node-esm-load -> exit 0\n- node scripts/check-changeset-presence.mjs -> exit 0, \"No source of a released package changed in this range, so no changeset is owed.\" Followed the gate's verdict: NO changeset added. objectui has no skip-changeset label mechanism and none was created or applied.\n- grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]' on the changed file -> clean\n\nTWO DECLARED NARROWINGS (both measured, not skipped):\n1. LINT. scripts/ is not a workspace package, so `pnpm lint` (turbo run lint, per-package fan-out) never reaches the changed file - measured, not assumed: pnpm-workspace.yaml globs packages/*, examples/*, apps/*, docs, and of the 47 workspace packages NONE has a directory containing scripts/. Linted directly instead: `npx eslint scripts/invoked-as.mjs --format json` -> exit 0, files linted = 1 (count read from the json), 0 errors, 0 warnings. Population read from eslint's own config: `--print-config` resolves a config for the file, so it is covered rather than merely unmatched. Invariance: eslint.config.js enables no type-aware linting (no projectService, no parserOptions.project, no recommendedTypeChecked), so a one-file diff with no config change cannot move any untouched file's verdict.\n2. pnpm check:published-dist NOT RUN LOCALLY. Its criterion is the file list of every published package's tarball after a real build; it exceeded this container's ~10 minute foreground cap (SIGTERM, exit 143). Sound to narrow for the same measured reason as lint: scripts/ is inside no workspace package, so this diff cannot appear in any package's dist/ or change any tarball's file list. CI runs it regardless.\n\nLIMIT OF THIS VERIFICATION, stated because it is the card's own point: this change is prose. No gate catches a false comment, and none will keep the corrected one true - the original header was false and every gate in this repository stayed green. The durable remedy is the gate tracked in #6092.",
"open_questions": [],
"out_of_scope_findings": [
"filed as #6092: port objectstack's check-entry-guard.mjs (787 lines, two rules, wired as check:entry-guard there) and convert the 29 hand-typed entry guards to isEntrypoint - the conversion half the PM ruled out of scope for this PR, filed unassigned with all measured numbers, the nine-spelling breakdown, and the symlink and percent-encoding demonstrations",
"recorded inside #6092 rather than filed separately, since they are the same worklist: (a) check-node-esm-load.mjs:847 still carries the exact percent-encoding spelling invoked-as.mjs's header warns about, measured inert in a directory named 'a#b c' with no symlink involved; (b) the worklist GROWS while the card sits open - one guard was added between a1c41c516 and 7c96c9420, which is the argument for porting the gate before doing the sweep; (c) scripts/shadcn-sync.js already hand-types the correct two-leg shape, so converting it is a simplification rather than a fix"
]
}
(Supersedes the previous comment on this issue: its leading HTML-comment marker was stripped by GitHub's body sanitizer after the comment was stored, so it is invisible to a marker scan. This one carries the marker as literal text. Content is identical apart from the marker and one path that the same sanitizer ate.)
{
"issue": 6078,
"status": "done",
"branch": "claude/issue-6078-invoked-as-false-gate-claim",
"pr": "https://github.com/objectstack-ai/objectui/pull/6096",
"premise_still_valid": true,
"summary": "The card's premise holds: scripts/check-entry-guard.mjs does not exist here and the header asserted it as enforcement. Root cause measured beyond the card: #5984 ported invoked-as.mjs out of objectstack with its prose but without the gate or the sweep, so FOUR paths the header names resolve only in objectstack (check-entry-guard.mjs, pm/check-governed-merges.mjs, packages/cli/src/utils/invocation.ts, js-comment-mask.mjs) while all five exist there at 644ad5043. The correction therefore re-attributes four passages rather than deleting one sentence, and replaces the borrowed objectstack symlink example with the same measurement taken on a real objectui blocking gate. Two of the card's figures moved and are corrected: ONE module imports isEntrypoint (not two - the #5793 gate has not landed on main), and 29 hand-typed guards remain (not 27 - check-designer-field-key-parity.mjs landed since a1c41c516). One card claim was simply wrong: the guards are not all one shape, they are NINE textually distinct spellings, one of which (check-node-esm-load.mjs:847) is the percent-encoding failure the header itself warns about. Conversion and the gate port are out of scope per the PM ruling and are filed as #6092. One bounded in-place fix in the same file, named in the PR body: a self-test case reached for js-comment-mask.mjs (objectstack-only), so 'an unrelated existing file is not this module' had silently become a duplicate of the case below it; it now names a real neighbour with an existence assertion so it cannot degrade that way again.",
"tests": "All runs on f726727cd (the final commit; clean tree, verified via git status --porcelain). Verdict lines quoted are the gates' own, not a bare $?.\n\nMEASUREMENTS (each with the command that produced it, on origin/main @ 7c96c9420):\n- Gate absent, with positive control: `ls scripts/check-entry-guard.mjs` -> 'No such file or directory'; `ls scripts/check-control-bytes.mjs` -> exists, 16244 bytes. `git ls-files | grep -c 'check-entry-guard'` -> 0; same for check-control-bytes -> 2. `git grep -n 'check-entry-guard'` -> exactly 1 hit, scripts/invoked-as.mjs:73 (the sentence itself); `git grep -l 'check-control-bytes' | wc -l` -> 16. The single hit is over ALL tracked files, so package.json and .github/workflows/ are covered - nothing runs such a gate.\n- Provenance: the same five paths checked in /home/user/objectstack @ 644ad5043 - all five EXIST there, four are MISSING in objectui. objectstack's check-entry-guard.mjs is 787 lines and wired as `check:entry-guard` in package.json.\n- Hand-typed guards: `git grep -l 'process\\.argv\\[1\\]' -- 'scripts/'` -> 30 files; minus invoked-as.mjs itself -> 29 guards (28 .mjs + scripts/shadcn-sync.js). Card said 27; reconciled by `comm -13` against the same grep at a1c41c516 -> exactly one file added (check-designer-field-key-parity.mjs), none removed.\n- No-realpath-leg shape: 28 of the 29. Only scripts/shadcn-sync.js:1048-1057 carries a realpath leg (`realpathSync(resolved) === __filename`).\n- Distinct spellings: 9 across the 28 .mjs, via `git grep -n ... | cut -d: -f3- | sort | uniq -c` (12x, 5x, 3x, 2x, 2x, 1x, 1x, 1x, 1x). Card implied one shape.\n- isEntrypoint importers: `git grep -l 'isEntrypoint' -- .` -> 2 files = invoked-as.mjs itself + ONE adopter, scripts/pm/check-half-states.mjs:777. Card said two adopters.\n\nSYMLINK INERTNESS - DEMONSTRATED, not inherited. One untracked guide file made deliberately wrong (removed by an EXIT/INT/TERM trap in the same command; `git status --porcelain` empty afterwards), then a real blocking gate run two ways against the identical defective tree:\n node scripts/check-skills-paths.mjs -> exit=1, 696 bytes naming the dead path\n node SCRATCHPAD/link/check-skills-paths.mjs (symlink) -> exit=0, 0 bytes\nSo a RED gate reports clean through a symlink. Separately measured, since the header asserts it: the ``import.meta.url === `file://${argv[1]}` `` spelling (check-node-esm-load.mjs:847) goes INERT in a directory named 'a#b c' with no symlink at all - file:///.../a%23b%20c/enc.mjs vs /.../a#b c/enc.mjs. Also checked before asserting and found NOT a bug: regenerate-known-schema-types.mjs:187 omits resolve() on argv[1], but node absolutizes argv[1] itself (measured by invoking a probe relatively).\n\nREVERSE VERIFICATION of the new existence assertion. Predicted direction: red. Mutation proven on disk BEFORE reading any result, by anchored greps in both directions: injected \"'js-comment-mask.mjs');\" count=1, removed \"'check-control-bytes.mjs');\" count=0, `git diff --stat` = 1 file changed, 1 insertion(+), 1 deletion(-). Run: `node scripts/invoked-as.mjs --self-test` -> exit=1, \"1 of 12 case(s) failed\", and the failing case is the new assertion only - the OLD case still passed with the dead path, which is exactly the vacuity being closed. Restored via `git checkout --` (the fix was committed first), restoration proven by the same greps inverted, re-run green 12/12, git status clean. No build is involved: this module is plain .mjs run directly, not resolved through any package dist, so there is no stale-artifact leg to rebuild.\n\nGATES (exit captured before any pipe; verdict lines are the gates' own):\n- node scripts/invoked-as.mjs --self-test -> exit 0, \"invoked-as self-test: 12 cases pass\" (was 11)\n- npx vitest run scripts/__tests__ --maxWorkers=2, from the repo ROOT (never package-scoped) -> exit 0, \"Test Files 65 passed (65)\", \"Tests 1789 passed (1789)\"\n- pnpm check:control-bytes -> exit 0, \"check-control-bytes: OK (scanned 5036 tracked text file(s); skipped 85 binary)\"\n- pnpm check:skills-paths -> exit 0, \"check-skills-paths: OK (93/94 stated path(s) resolve across 18 guide file(s); 1 baselined)\" - also confirms the temp probe file is gone\n- pnpm check:esm-specifiers -> exit 0, \"Specifier leg: no un-ledgered package emits an extensionless relative specifier.\"\n- pnpm check:node-esm-load -> exit 0\n- node scripts/check-changeset-presence.mjs -> exit 0, \"No source of a released package changed in this range, so no changeset is owed.\" Followed the gate's verdict: NO changeset added. objectui has no skip-changeset label mechanism and none was created or applied.\n- grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]' on the changed file -> clean\n\nTWO DECLARED NARROWINGS (both measured, not skipped):\n1. LINT. scripts/ is not a workspace package, so `pnpm lint` (turbo run lint, per-package fan-out) never reaches the changed file - measured, not assumed: pnpm-workspace.yaml globs packages/*, examples/*, apps/*, docs, and of the 47 workspace packages NONE has a directory containing scripts/. Linted directly instead: `npx eslint scripts/invoked-as.mjs --format json` -> exit 0, files linted = 1 (count read from the json), 0 errors, 0 warnings. Population read from eslint's own config: `--print-config` resolves a config for the file, so it is covered rather than merely unmatched. Invariance: eslint.config.js enables no type-aware linting (no projectService, no parserOptions.project, no recommendedTypeChecked), so a one-file diff with no config change cannot move any untouched file's verdict.\n2. pnpm check:published-dist NOT RUN LOCALLY. Its criterion is the file list of every published package's tarball after a real build; it exceeded this container's ~10 minute foreground cap (SIGTERM, exit 143). Sound to narrow for the same measured reason as lint: scripts/ is inside no workspace package, so this diff cannot appear in any package's dist/ or change any tarball's file list. CI runs it regardless.\n\nLIMIT OF THIS VERIFICATION, stated because it is the card's own point: this change is prose. No gate catches a false comment, and none will keep the corrected one true - the original header was false and every gate in this repository stayed green. The durable remedy is the gate tracked in #6092.",
"open_questions": [],
"out_of_scope_findings": [
"filed as #6092: port objectstack's check-entry-guard.mjs (787 lines, two rules, wired as check:entry-guard there) and convert the 29 hand-typed entry guards to isEntrypoint - the conversion half the PM ruled out of scope for this PR, filed unassigned with all measured numbers, the nine-spelling breakdown, and the symlink and percent-encoding demonstrations",
"recorded inside #6092 rather than filed separately, since they are the same worklist: (a) check-node-esm-load.mjs:847 still carries the exact percent-encoding spelling invoked-as.mjs's header warns about, measured inert in a directory named 'a#b c' with no symlink involved; (b) the worklist GROWS while the card sits open - one guard was added between a1c41c516 and 7c96c9420, which is the argument for porting the gate before doing the sweep; (c) scripts/shadcn-sync.js already hand-types the correct two-leg shape, so converting it is a simplification rather than a fix"
]
}
Activity
yinlianghui-tw commentedon Aug 24, 2026
{ "issue": 6078, "status": "done", "branch": "claude/issue-6078-invoked-as-false-gate-claim", "pr": "https://github.com/objectstack-ai/objectui/pull/6096", "premise_still_valid": true, "summary": "The card's premise holds: scripts/check-entry-guard.mjs does not exist here and the header asserted it as enforcement. Root cause measured beyond the card: #5984 ported invoked-as.mjs out of objectstack with its prose but without the gate or the sweep, so FOUR paths the header names resolve only in objectstack (check-entry-guard.mjs, pm/check-governed-merges.mjs, packages/cli/src/utils/invocation.ts, js-comment-mask.mjs) while all five exist there at 644ad5043. The correction therefore re-attributes four passages rather than deleting one sentence, and replaces the borrowed objectstack symlink example with the same measurement taken on a real objectui blocking gate. Two of the card's figures moved and are corrected: ONE module imports isEntrypoint (not two - the #5793 gate has not landed on main), and 29 hand-typed guards remain (not 27 - check-designer-field-key-parity.mjs landed since a1c41c516). One card claim was simply wrong: the guards are not all one shape, they are NINE textually distinct spellings, one of which (check-node-esm-load.mjs:847) is the percent-encoding failure the header itself warns about. Conversion and the gate port are out of scope per the PM ruling and are filed as #6092. One bounded in-place fix in the same file, named in the PR body: a self-test case reached for js-comment-mask.mjs (objectstack-only), so 'an unrelated existing file is not this module' had silently become a duplicate of the case below it; it now names a real neighbour with an existence assertion so it cannot degrade that way again.", "tests": "All runs on f726727cd (the final commit; clean tree, verified via git status --porcelain). Verdict lines quoted are the gates' own, not a bare $?.\n\nMEASUREMENTS (each with the command that produced it, on origin/main @ 7c96c9420):\n- Gate absent, with positive control: `ls scripts/check-entry-guard.mjs` -> 'No such file or directory'; `ls scripts/check-control-bytes.mjs` -> exists, 16244 bytes. `git ls-files | grep -c 'check-entry-guard'` -> 0; same for check-control-bytes -> 2. `git grep -n 'check-entry-guard'` -> exactly 1 hit, scripts/invoked-as.mjs:73 (the sentence itself); `git grep -l 'check-control-bytes' | wc -l` -> 16. The single hit is over ALL tracked files, so package.json and .github/workflows/ are covered - nothing runs such a gate.\n- Provenance: the same five paths checked in /home/user/objectstack @ 644ad5043 - all five EXIST there, four are MISSING in objectui. objectstack's check-entry-guard.mjs is 787 lines and wired as `check:entry-guard` in package.json.\n- Hand-typed guards: `git grep -l 'process\\.argv\\[1\\]' -- 'scripts/'` -> 30 files; minus invoked-as.mjs itself -> 29 guards (28 .mjs + scripts/shadcn-sync.js). Card said 27; reconciled by `comm -13` against the same grep at a1c41c516 -> exactly one file added (check-designer-field-key-parity.mjs), none removed.\n- No-realpath-leg shape: 28 of the 29. Only scripts/shadcn-sync.js:1048-1057 carries a realpath leg (`realpathSync(resolved) === __filename`).\n- Distinct spellings: 9 across the 28 .mjs, via `git grep -n ... | cut -d: -f3- | sort | uniq -c` (12x, 5x, 3x, 2x, 2x, 1x, 1x, 1x, 1x). Card implied one shape.\n- isEntrypoint importers: `git grep -l 'isEntrypoint' -- .` -> 2 files = invoked-as.mjs itself + ONE adopter, scripts/pm/check-half-states.mjs:777. Card said two adopters.\n\nSYMLINK INERTNESS - DEMONSTRATED, not inherited. One untracked guide file made deliberately wrong (removed by an EXIT/INT/TERM trap in the same command; `git status --porcelain` empty afterwards), then a real blocking gate run two ways against the identical defective tree:\n node scripts/check-skills-paths.mjs -> exit=1, 696 bytes naming the dead path\n node <scratchpad>/link/check-skills-paths.mjs -> exit=0, 0 bytes\nSo a RED gate reports clean through a symlink. Separately measured, since the header asserts it: the ``import.meta.url === `file://${argv[1]}` `` spelling (check-node-esm-load.mjs:847) goes INERT in a directory named 'a#b c' with no symlink at all - file:///.../a%23b%20c/enc.mjs vs /.../a#b c/enc.mjs. Also checked before asserting and found NOT a bug: regenerate-known-schema-types.mjs:187 omits resolve() on argv[1], but node absolutizes argv[1] itself (measured by invoking a probe relatively).\n\nREVERSE VERIFICATION of the new existence assertion. Predicted direction: red. Mutation proven on disk BEFORE reading any result, by anchored greps in both directions: injected \"'js-comment-mask.mjs');\" count=1, removed \"'check-control-bytes.mjs');\" count=0, `git diff --stat` = 1 file changed, 1 insertion(+), 1 deletion(-). Run: `node scripts/invoked-as.mjs --self-test` -> exit=1, \"1 of 12 case(s) failed\", and the failing case is the new assertion only - the OLD case still passed with the dead path, which is exactly the vacuity being closed. Restored via `git checkout --` (the fix was committed first), restoration proven by the same greps inverted, re-run green 12/12, git status clean. No build is involved: this module is plain .mjs run directly, not resolved through any package dist, so there is no stale-artifact leg to rebuild.\n\nGATES (exit captured before any pipe; verdict lines are the gates' own):\n- node scripts/invoked-as.mjs --self-test -> exit 0, \"invoked-as self-test: 12 cases pass\" (was 11)\n- npx vitest run scripts/__tests__ --maxWorkers=2, from the repo ROOT (never package-scoped) -> exit 0, \"Test Files 65 passed (65)\", \"Tests 1789 passed (1789)\"\n- pnpm check:control-bytes -> exit 0, \"check-control-bytes: OK (scanned 5036 tracked text file(s); skipped 85 binary)\"\n- pnpm check:skills-paths -> exit 0, \"check-skills-paths: OK (93/94 stated path(s) resolve across 18 guide file(s); 1 baselined)\" - also confirms the temp probe file is gone\n- pnpm check:esm-specifiers -> exit 0, \"Specifier leg: no un-ledgered package emits an extensionless relative specifier.\"\n- pnpm check:node-esm-load -> exit 0\n- node scripts/check-changeset-presence.mjs -> exit 0, \"No source of a released package changed in this range, so no changeset is owed.\" Followed the gate's verdict: NO changeset added. objectui has no skip-changeset label mechanism and none was created or applied.\n- grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]' on the changed file -> clean\n\nTWO DECLARED NARROWINGS (both measured, not skipped):\n1. LINT. scripts/ is not a workspace package, so `pnpm lint` (turbo run lint, per-package fan-out) never reaches the changed file - measured, not assumed: pnpm-workspace.yaml globs packages/*, examples/*, apps/*, docs, and of the 47 workspace packages NONE has a directory containing scripts/. Linted directly instead: `npx eslint scripts/invoked-as.mjs --format json` -> exit 0, files linted = 1 (count read from the json), 0 errors, 0 warnings. Population read from eslint's own config: `--print-config` resolves a config for the file, so it is covered rather than merely unmatched. Invariance: eslint.config.js enables no type-aware linting (no projectService, no parserOptions.project, no recommendedTypeChecked), so a one-file diff with no config change cannot move any untouched file's verdict.\n2. pnpm check:published-dist NOT RUN LOCALLY. Its criterion is the file list of every published package's tarball after a real build; it exceeded this container's ~10 minute foreground cap (SIGTERM, exit 143). Sound to narrow for the same measured reason as lint: scripts/ is inside no workspace package, so this diff cannot appear in any package's dist/ or change any tarball's file list. CI runs it regardless.\n\nLIMIT OF THIS VERIFICATION, stated because it is the card's own point: this change is prose. No gate catches a false comment, and none will keep the corrected one true - the original header was false and every gate in this repository stayed green. The durable remedy is the gate tracked in #6092.", "open_questions": [], "out_of_scope_findings": [ "filed as #6092: port objectstack's check-entry-guard.mjs (787 lines, two rules, wired as check:entry-guard there) and convert the 29 hand-typed entry guards to isEntrypoint - the conversion half the PM ruled out of scope for this PR, filed unassigned with all measured numbers, the nine-spelling breakdown, and the symlink and percent-encoding demonstrations", "recorded inside #6092 rather than filed separately, since they are the same worklist: (a) check-node-esm-load.mjs:847 still carries the exact percent-encoding spelling invoked-as.mjs's header warns about, measured inert in a directory named 'a#b c' with no symlink involved; (b) the worklist GROWS while the card sits open - one guard was added between a1c41c516 and 7c96c9420, which is the argument for porting the gate before doing the sweep; (c) scripts/shadcn-sync.js already hand-types the correct two-leg shape, so converting it is a simplification rather than a fix" ] }Generated by Claude Code
yinlianghui-tw commentedon Aug 24, 2026
os-dev-report
(Supersedes the previous comment on this issue: its leading HTML-comment marker was stripped by GitHub's body sanitizer after the comment was stored, so it is invisible to a marker scan. This one carries the marker as literal text. Content is identical apart from the marker and one path that the same sanitizer ate.)
{ "issue": 6078, "status": "done", "branch": "claude/issue-6078-invoked-as-false-gate-claim", "pr": "https://github.com/objectstack-ai/objectui/pull/6096", "premise_still_valid": true, "summary": "The card's premise holds: scripts/check-entry-guard.mjs does not exist here and the header asserted it as enforcement. Root cause measured beyond the card: #5984 ported invoked-as.mjs out of objectstack with its prose but without the gate or the sweep, so FOUR paths the header names resolve only in objectstack (check-entry-guard.mjs, pm/check-governed-merges.mjs, packages/cli/src/utils/invocation.ts, js-comment-mask.mjs) while all five exist there at 644ad5043. The correction therefore re-attributes four passages rather than deleting one sentence, and replaces the borrowed objectstack symlink example with the same measurement taken on a real objectui blocking gate. Two of the card's figures moved and are corrected: ONE module imports isEntrypoint (not two - the #5793 gate has not landed on main), and 29 hand-typed guards remain (not 27 - check-designer-field-key-parity.mjs landed since a1c41c516). One card claim was simply wrong: the guards are not all one shape, they are NINE textually distinct spellings, one of which (check-node-esm-load.mjs:847) is the percent-encoding failure the header itself warns about. Conversion and the gate port are out of scope per the PM ruling and are filed as #6092. One bounded in-place fix in the same file, named in the PR body: a self-test case reached for js-comment-mask.mjs (objectstack-only), so 'an unrelated existing file is not this module' had silently become a duplicate of the case below it; it now names a real neighbour with an existence assertion so it cannot degrade that way again.", "tests": "All runs on f726727cd (the final commit; clean tree, verified via git status --porcelain). Verdict lines quoted are the gates' own, not a bare $?.\n\nMEASUREMENTS (each with the command that produced it, on origin/main @ 7c96c9420):\n- Gate absent, with positive control: `ls scripts/check-entry-guard.mjs` -> 'No such file or directory'; `ls scripts/check-control-bytes.mjs` -> exists, 16244 bytes. `git ls-files | grep -c 'check-entry-guard'` -> 0; same for check-control-bytes -> 2. `git grep -n 'check-entry-guard'` -> exactly 1 hit, scripts/invoked-as.mjs:73 (the sentence itself); `git grep -l 'check-control-bytes' | wc -l` -> 16. The single hit is over ALL tracked files, so package.json and .github/workflows/ are covered - nothing runs such a gate.\n- Provenance: the same five paths checked in /home/user/objectstack @ 644ad5043 - all five EXIST there, four are MISSING in objectui. objectstack's check-entry-guard.mjs is 787 lines and wired as `check:entry-guard` in package.json.\n- Hand-typed guards: `git grep -l 'process\\.argv\\[1\\]' -- 'scripts/'` -> 30 files; minus invoked-as.mjs itself -> 29 guards (28 .mjs + scripts/shadcn-sync.js). Card said 27; reconciled by `comm -13` against the same grep at a1c41c516 -> exactly one file added (check-designer-field-key-parity.mjs), none removed.\n- No-realpath-leg shape: 28 of the 29. Only scripts/shadcn-sync.js:1048-1057 carries a realpath leg (`realpathSync(resolved) === __filename`).\n- Distinct spellings: 9 across the 28 .mjs, via `git grep -n ... | cut -d: -f3- | sort | uniq -c` (12x, 5x, 3x, 2x, 2x, 1x, 1x, 1x, 1x). Card implied one shape.\n- isEntrypoint importers: `git grep -l 'isEntrypoint' -- .` -> 2 files = invoked-as.mjs itself + ONE adopter, scripts/pm/check-half-states.mjs:777. Card said two adopters.\n\nSYMLINK INERTNESS - DEMONSTRATED, not inherited. One untracked guide file made deliberately wrong (removed by an EXIT/INT/TERM trap in the same command; `git status --porcelain` empty afterwards), then a real blocking gate run two ways against the identical defective tree:\n node scripts/check-skills-paths.mjs -> exit=1, 696 bytes naming the dead path\n node SCRATCHPAD/link/check-skills-paths.mjs (symlink) -> exit=0, 0 bytes\nSo a RED gate reports clean through a symlink. Separately measured, since the header asserts it: the ``import.meta.url === `file://${argv[1]}` `` spelling (check-node-esm-load.mjs:847) goes INERT in a directory named 'a#b c' with no symlink at all - file:///.../a%23b%20c/enc.mjs vs /.../a#b c/enc.mjs. Also checked before asserting and found NOT a bug: regenerate-known-schema-types.mjs:187 omits resolve() on argv[1], but node absolutizes argv[1] itself (measured by invoking a probe relatively).\n\nREVERSE VERIFICATION of the new existence assertion. Predicted direction: red. Mutation proven on disk BEFORE reading any result, by anchored greps in both directions: injected \"'js-comment-mask.mjs');\" count=1, removed \"'check-control-bytes.mjs');\" count=0, `git diff --stat` = 1 file changed, 1 insertion(+), 1 deletion(-). Run: `node scripts/invoked-as.mjs --self-test` -> exit=1, \"1 of 12 case(s) failed\", and the failing case is the new assertion only - the OLD case still passed with the dead path, which is exactly the vacuity being closed. Restored via `git checkout --` (the fix was committed first), restoration proven by the same greps inverted, re-run green 12/12, git status clean. No build is involved: this module is plain .mjs run directly, not resolved through any package dist, so there is no stale-artifact leg to rebuild.\n\nGATES (exit captured before any pipe; verdict lines are the gates' own):\n- node scripts/invoked-as.mjs --self-test -> exit 0, \"invoked-as self-test: 12 cases pass\" (was 11)\n- npx vitest run scripts/__tests__ --maxWorkers=2, from the repo ROOT (never package-scoped) -> exit 0, \"Test Files 65 passed (65)\", \"Tests 1789 passed (1789)\"\n- pnpm check:control-bytes -> exit 0, \"check-control-bytes: OK (scanned 5036 tracked text file(s); skipped 85 binary)\"\n- pnpm check:skills-paths -> exit 0, \"check-skills-paths: OK (93/94 stated path(s) resolve across 18 guide file(s); 1 baselined)\" - also confirms the temp probe file is gone\n- pnpm check:esm-specifiers -> exit 0, \"Specifier leg: no un-ledgered package emits an extensionless relative specifier.\"\n- pnpm check:node-esm-load -> exit 0\n- node scripts/check-changeset-presence.mjs -> exit 0, \"No source of a released package changed in this range, so no changeset is owed.\" Followed the gate's verdict: NO changeset added. objectui has no skip-changeset label mechanism and none was created or applied.\n- grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]' on the changed file -> clean\n\nTWO DECLARED NARROWINGS (both measured, not skipped):\n1. LINT. scripts/ is not a workspace package, so `pnpm lint` (turbo run lint, per-package fan-out) never reaches the changed file - measured, not assumed: pnpm-workspace.yaml globs packages/*, examples/*, apps/*, docs, and of the 47 workspace packages NONE has a directory containing scripts/. Linted directly instead: `npx eslint scripts/invoked-as.mjs --format json` -> exit 0, files linted = 1 (count read from the json), 0 errors, 0 warnings. Population read from eslint's own config: `--print-config` resolves a config for the file, so it is covered rather than merely unmatched. Invariance: eslint.config.js enables no type-aware linting (no projectService, no parserOptions.project, no recommendedTypeChecked), so a one-file diff with no config change cannot move any untouched file's verdict.\n2. pnpm check:published-dist NOT RUN LOCALLY. Its criterion is the file list of every published package's tarball after a real build; it exceeded this container's ~10 minute foreground cap (SIGTERM, exit 143). Sound to narrow for the same measured reason as lint: scripts/ is inside no workspace package, so this diff cannot appear in any package's dist/ or change any tarball's file list. CI runs it regardless.\n\nLIMIT OF THIS VERIFICATION, stated because it is the card's own point: this change is prose. No gate catches a false comment, and none will keep the corrected one true - the original header was false and every gate in this repository stayed green. The durable remedy is the gate tracked in #6092.", "open_questions": [], "out_of_scope_findings": [ "filed as #6092: port objectstack's check-entry-guard.mjs (787 lines, two rules, wired as check:entry-guard there) and convert the 29 hand-typed entry guards to isEntrypoint - the conversion half the PM ruled out of scope for this PR, filed unassigned with all measured numbers, the nine-spelling breakdown, and the symlink and percent-encoding demonstrations", "recorded inside #6092 rather than filed separately, since they are the same worklist: (a) check-node-esm-load.mjs:847 still carries the exact percent-encoding spelling invoked-as.mjs's header warns about, measured inert in a directory named 'a#b c' with no symlink involved; (b) the worklist GROWS while the card sits open - one guard was added between a1c41c516 and 7c96c9420, which is the argument for porting the gate before doing the sweep; (c) scripts/shadcn-sync.js already hand-types the correct two-leg shape, so converting it is a simplification rather than a fix" ] }Generated by Claude Code