Skip to content

Port check-entry-guard.mjs and convert the 29 hand-typed entry guards to isEntrypoint (nine distinct spellings, 28 with no realpath leg) #6092

Description

@yinlianghui-tw

Split out of #6078 by the dev seat correcting that card's header claim. #6078 fixes the claim only — the false "a gate enforces this" sentence in scripts/invoked-as.mjs. This card is the other half: the work the claim was describing, which never happened here.

What was measured

All figures on origin/main @ 7c96c9420, in /home/user/objectui-6078.

scripts/invoked-as.mjs was ported from objectstack (#5984) without the gate or the sweep that made its header true. Five paths that header names, checked in both trees:

pathobjectui 7c96c9420objectstack 644ad5043
scripts/invoked-as.mjsEXISTSEXISTS
scripts/check-entry-guard.mjsMISSINGEXISTS (787 lines, wired check:entry-guard)
scripts/pm/check-governed-merges.mjsMISSINGEXISTS
packages/cli/src/utils/invocation.tsMISSINGEXISTS
scripts/js-comment-mask.mjsMISSINGEXISTS

So the header is a faithful description of objectstack's tree, sitting in objectui.

The adoption count.git grep -l 'isEntrypoint' -- . → exactly two files: scripts/invoked-as.mjs and one adopter, scripts/pm/check-half-states.mjs:777. #6078's body said two adopters; the second (the gate from #5793) has not landed on main.

The worklist.git grep -l 'process\.argv\[1\]' -- 'scripts/' → 30 files. Minus invoked-as.mjs itself → 29 hand-typed entry guards: 28 .mjs plus scripts/shadcn-sync.js.

#6078 measured 27 at a1c41c516; that reconciles — scripts/check-designer-field-key-parity.mjs has landed since, adding a 28th .mjs guard (comm -13 on the two file sets, one file added, none removed). The worklist grows while this sits open — which is the argument for doing the gate first.

The realpath leg. 28 of the 29 have none. The single exception is scripts/shadcn-sync.js:1048-1057, whose invokedAsCli() hand-types the correct two-leg shape.

The drift is real, not one spelling.#6078 said all of them use one shape; they do not. Nine textually distinct expressions across the 28 .mjs, by git grep -n 'process\.argv\[1\]' -- 'scripts/' | cut -d: -f3- | sort | uniq -c:

  • 12× argv[1] && resolve(argv[1]) === resolve(fileURLToPath(import.meta.url))
  • argv[1] && resolve(argv[1]) === fileURLToPath(import.meta.url)
  • argv[1] && path.resolve(argv[1]) === fileURLToPath(import.meta.url)
  • argv[1] && pathToFileURL(argv[1]).href === import.meta.url
  • argv[1] && import.meta.url === pathToFileURL(argv[1]).href
  • resolve(argv[1] ?? "") === resolve(fileURLToPath(import.meta.url))
  • argv[1] && fileURLToPath(import.meta.url) === argv[1] (regenerate-known-schema-types.mjs:187)
  • import.meta.url === pathToFileURL(argv[1] ?? '').href
  • import.meta.url === `file://${argv[1]}` (check-node-esm-load.mjs:847)

The last one is the percent-encoding failure invoked-as.mjs's own header documents, verbatim, still in the tree. Measured with that exact expression in a directory named a#b c:

INERT file:///…/a%23b%20c/enc.mjs vs /…/a#b c/enc.mjs

No symlink needed. regenerate-known-schema-types.mjs's missing resolve() is not a live bug — node absolutizes argv[1] itself (measured: invoking node argvprobe.mjs relatively prints an absolute path) — but it is a tenth thing a reader has to re-derive.

The hazard, measured on a real gate in THIS repo

#6078 quoted the header's "exit 0, no output" claim. It is measured now. One guide file made deliberately wrong (untracked, removed immediately), then the same blocking gate run two ways:

node scripts/check-skills-paths.mjs direct : exit=1, 696 bytes naming the dead path
node /…/link/check-skills-paths.mjs (symlink) symlink : exit=0, 0 bytes

Same tree, same defect, same gate. Through the symlink a red gate reports clean, and CI wrappers that hold result.status cannot tell that apart from a pass. check-skills-paths.mjs is one of the 28 no-realpath guards; check-published-dist-tooling.mjs (publish path), check-doc-component-types.mjs and check-action-forward-parity.mjs (per-PR lanes) carry the same shape.

Nothing is failing today — no current invocation goes through a symlink. This is a latent-hazard card, not an outage.

The work, in the order it should happen

  1. Port the gate. objectstack's scripts/check-entry-guard.mjs is 787 lines and carries two rules — the spelling rule, and a second one about a file that exports but has no guard at all. It is not a copy-paste: it needs objectui's script inventory, its own baseline, and a wiring decision (objectstack runs it as check:entry-guard in package.json). Landing it first means it names its own worklist and stops a 30th spelling.
  2. Convert the 29 call sites to isEntrypoint(import.meta.url). Mechanical per site, but it touches blocking gates on the publish path and per-PR lanes, so it wants reverse-verification per lane, not a bulk sed. shadcn-sync.js is the one that already behaves correctly — converting it is a simplification, not a fix.

Splitting 1 and 2 into separate PRs is reasonable; doing 2 without 1 is the "one-time sweep that rots on merge day" the header itself argues against.

Refs: #6078 (the claim, corrected there) · #5984 (the port) · #5793 (the card whose seat found it).


Generated by Claude Code

Metadata

Metadata

Labels

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

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions