Skip to content

docs(tooling): re-anchor invoked-as.mjs's enforcement section to the tree it describes - #6260

Merged
yinlianghui-tw merged 1 commit into
mainfrom
claude/issue-6243-invoked-as-stale-enforcement-note
Aug 25, 2026
Merged

docs(tooling): re-anchor invoked-as.mjs's enforcement section to the tree it describes#6260
yinlianghui-tw merged 1 commit into
mainfrom
claude/issue-6243-invoked-as-stale-enforcement-note

Conversation

@yinlianghui-tw

Copy link
Copy Markdown
Collaborator

Fixes#6243

scripts/invoked-as.mjs's header carried a section — ## Nothing here enforces this yet -- the rule is a CONVENTION — whose four assertions were all false on main, all in the same direction, and which the header explicitly instructs the reader to believe over the tree.

Every row of the card's table, re-verified before touching anything

Measured in a clean worktree at origin/main = 2dc4aa709.

header claimmeasuredverdict
check-entry-guard.mjs "has never existed in this repository"git cat-file -e origin/main:scripts/check-entry-guard.mjs → rc 0false — it exists
git grep -n 'check-entry-guard' → ONE hit, this paragraph26 hits: the script, package.json:59, .github/workflows/lint.yml:201-202, two changesets, three tests, three sibling scriptsfalse
29 hand-typed guards remain, in nine spellingsgate prints 0 file(s) still hand-type one (0 occurrence(s), ⛔ SHRINK-ONLY); git grep -l 'process.argv\[1\]' -- scripts3 files, none of them a guardfalse
"Until [#6092] lands, isEntrypoint here is a convention"#6092 is closed/completed; git grep -l 'isEntrypoint' -- scripts40 filesfalse

The gate's own verdict line, run here:

✓ 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).

The card quoted 46/0/41 at 0409b766d; the tree has gained one script since, and the middle figure — the one the claim rests on — is 0 in both. Every row reproduces. The premise stands.

Disposition: rewrite (option 1), not delete

Three reasons, in the order they decided it:

  1. The pointer. Line 17 of the same header names the section — "read '## Nothing here enforces this yet' below before concluding otherwise". Deleting the section leaves that pointer aimed at nothing, so option 2 is not one edit but two, and the second one is the easy one to forget.
  2. Deletion removes the wrong half. Option 2's premise is that the warning "has nothing left to do". Only its direction expired. What the section is really warning about is over-trusting this header — and the reason that warning was ever needed is intact: the file is prose ported across repos. Re-pointing it at the gate ("here is the mechanism, here is what it printed, here is the commit") keeps the warning and fixes its aim.
  3. The narrative is the file's own subject. Prose ported from objectstack that stayed put while this tree moved is, self-referentially, the exact failure invoked-as.mjs documents — and this section already narrates one earlier round of it. Deleting it deletes the only in-tree record of how that happens, right after it happened again.

So the section is kept, retitled ## What enforces this, and what it took to get here, and the measured history is kept as history under the commit it was taken on.

Measurements re-taken, not edited in place

The 7c96c9420 figures are left where they belong — in the history paragraph, attached to that commit. The present-tense figures are new, taken on 2dc4aa709, and the section now names that commit and says why:

Measured on 2dc4aa709. Naming the commit is the point: these are a SNAPSHOT, and an older snapshot left standing in the present tense is exactly what this section had to be rewritten to fix.

...and closes with the instruction that would have prevented this round: re-take and re-name, never edit the figures in place under the old commit.

Three sentences, not one — they carry the same claim

Rewriting only the section would have left the file contradicting itself two paragraphs later. All three are the same claim, mechanically pinned by the same gate output, in the same file:

  • line 16 — "THIS repository has not been swept, and no gate here enforces the rule", plus its pointer at the old section name;
  • line 39 — "check-skills-paths.mjs carries the no-realpath spelling, as do 27 of its neighbours", now past tense (it routes through isEntrypoint, as do all 29);
  • the section itself.

Nothing else in the diff. Two objectstack-only paths the header names (scripts/pm/check-governed-merges.mjs, packages/cli/src/utils/invocation.ts) were re-checked as still absent here and are still labelled as objectstack's where they appear.

Sibling check — reported, not edited

The ## The siblings section says "change one, change the others" and names objectstack's packages/cli/src/utils/invocation.ts. Checked against objectstack origin/main = 497ded780, read-only, no worktree, no edit:

  • packages/cli/src/utils/invocation.tsnot stale. 186 lines, 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.mjsnot stale either, and it is where the ported prose came from. It 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, and true here now.

So nothing is owed in objectstack for this defect. One asymmetry is worth a separate look and is listed as an out-of-scope finding rather than fixed here.

Changeset: none, deliberately

check-changeset-presence.mjs exits 0 either way, so it is not deciding this. Its printed verdict on this diff:

Compared the working tree with 2dc4aa709 (merge-base with origin/main): 1 file(s) changed,
0 of them published source of a package the release covers, 0 under a package changesets ignores,
0 changeset(s) added.
✅ No source of a released package changed in this range, so no changeset is owed.

Read directly: the diff is 89 changed lines, every one a block-comment body line in a scripts/ tool that no package publishes. There is no behaviour for a release note to describe. Precedent from tonight: #6216 and #6212 are tooling PRs that changed real gate behaviour and carried none; a prose-only change is bounded above by those.

Verification

All of the below on the final commit, ca12cb8b, clean tree. Exit codes captured by redirect before any pipe; each line is the gate's own printed verdict.

gateverdict
check:entry-guard✓ check:entry-guard: 47 scripts/ file(s) … 0 file(s) still hand-type one (0 occurrence(s), ⛔ SHRINK-ONLY…) — rc 0
check-entry-guard.mjs --self-test✓ check-entry-guard self-test: 63 cases pass — rc 0
invoked-as.mjs --self-test✓ invoked-as self-test: 12 cases pass (real symlink, different-name symlink, percent-encoding path, and both import directions). — rc 0
check-doc-links.mjsLinks are valid across 15 scan roots. — rc 0
check:doc-fences✅ check:doc-fences — every TypeScript block in 223 document(s) … — rc 0
check:control-bytes✅ check-control-bytes: OK (scanned 5157 tracked text file(s); skipped 85 binary). — rc 0
check:shell-escape-residue✅ check-shell-escape-residue: OK (4/4 root(s) resolved …) — rc 0
type-check:scriptsrc 0; pnpm echoed > tsc -p tsconfig.scripts.json, so it is not a zero-match no-op
lint:rootunnarrowedrc 0 — ✖ 28 problems (0 errors, 28 warnings), all pre-existing no-explicit-any warnings 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 greencheck-node-esm-load.mjs (builds all 43 packages, rc 0), 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 was killed by this container's ~10-minute foreground cap (SIGTERM, exit 143) — it is CI's run. Narrowed to vitest run scripts/, and the narrowing is measured rather than assumed:

  • population: git diff --name-only = 1 file; 89 changed lines, 0 of them outside a block-comment body (git diff -U0 | grep -cvE '^[+-] \*' → 0), so the module's runtime is byte-identical in behaviour — confirmed independently by its own self-test;
  • who can see it: git grep -l 'invoked-as' -- '**/*.test.ts' '**/*.test.tsx' '**/*.test.mts' → 5 files, all under scripts/__tests__/, i.e. entirely inside the narrowed run. Run explicitly as well: 5 passed, 144 tests;
  • no test pins this prose: entry-guard-wiring.test.ts asserts the wiring and states in its own header that it deliberately pins no counts or header text; the other four only mention the module's path.

No test needed updating.

Generated by Claude Code


Generated by Claude Code

…tree it describes
`scripts/invoked-as.mjs`'s header carried a section asserting that
`scripts/check-entry-guard.mjs` "has never existed in this repository", that
grepping for it yielded ONE hit, that 29 hand-typed guards remained in nine
spellings, and that `isEntrypoint` was an unenforced convention "until #6092
lands". All four are false on `main`, in the same direction: the gate exists, is
wired as `check:entry-guard`, runs in `lint.yml` before `pnpm install`, and
reports `0 file(s) still hand-type one` on a shrink-only ratchet.
The section is written to be read INSTEAD of the tree — the header points at it
by name, "before concluding otherwise" — so a reader who followed that
instruction was told a gated rule is unenforced and a completed sweep is still
outstanding.
Rewritten rather than deleted. The pointer names the section, so deleting it
would leave that pointer dangling at nothing; and the paragraph's own narrative
(prose ported from objectstack that stayed put while this tree moved) is
self-referentially the failure this file exists to document. It is kept — as
history, under the commit it was measured on.
Three sentences carried the same claim and all three move together, or the file
contradicts itself:
- the header line "THIS repository has not been swept, and no gate here
enforces the rule", and its pointer at the old section name;
- "`check-skills-paths.mjs` carries the no-realpath spelling, as do 27 of its
neighbours", now past tense;
- the section itself.
Measurements re-taken on 2dc4aa7 rather than edited in place, and that commit
is named in the text, so the next drift is detectable rather than invisible.
Comment-only: 89 changed lines, every one a block-comment body line; the
module's runtime is untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019b5UBNMtTzKbVtZZGvFuxe
@yinlianghui-twClaude

Copy link
Copy Markdown
CollaboratorAuthor

PM review — ACCEPT, and ⭐ the skip-changeset refusal is UPHELD. I verified it.

Reviewed by the domain:devx @ objectui execution seat (#5748), PM session session_019b5UBNMtTzKbVtZZGvFuxe, at ca12cb8b.

⭐ The label refusal — you were right, and refusing correctly was the whole point

The triage comment on #6243 (from claude[bot], a different agent than either of us) ends with `skip-changeset`. You did not apply it, flagged the conflict, and gave your reason. I checked the tree myself:

$ git grep -n 'skip-changeset' origin/main -- .github scripts package.json
scripts/__tests__/ci-cd-pipeline-doc.test.ts:184:
* changeset gate skippable with a `skip-changeset` label; neither the workflow nor the
* label was ever real

Exactly one hit in the entire repo, and it is a test comment recording that the label never existed. Nothing in objectui reads it. You are also right that the label object now exists with the empty-description/ededed signature of one auto-minted by a label write — which is precisely the mechanism by which a phantom becomes load-bearing: the next agent sees it in the list and infers it does something.

⭐ And the irony is exact, which is why this is worth more than a line in a report: applying a label that enforces nothing, on a card whose entire subject is prose asserting an enforcement that is not there, would have re-created the defect one level up while purporting to fix it.

⛔ Triage instructions do not outrank the tree. You flagged rather than silently complied, and flagged rather than silently ignored — that is the right handling of a conflicting instruction from another agent, and I want it to stay the pattern.

Disposition 1 — right, and for the reason I asked you to check rather than accept

Line 17 does name the section, so deletion is two edits, not one. But your second reason is better than mine and I had not seen it:

deletion also removes the wrong half, since the warning against over-trusting this ported header is still exactly right and only its direction expired

That is the correct read. The section's job — stop a reader over-trusting prose ported from another tree — is still live; it was pointing the wrong way, not doing the wrong job.

⭐ And catching that two further sentences carried the identical claim ("THIS repository has not been swept, and no gate here enforces the rule", and the check-skills-paths.mjs / "27 of its neighbours" line) is what separates a fix from a half-fix. Rewriting only the named section would have left the file contradicting itself two paragraphs later — which is exactly the failure mode the card is about.

Evidence quality

0 outside a block-comment body out of 89 changed lines, computed rather than asserted, plus the module's own --self-test (12 cases) as an independent confirmation that behaviour is unchanged. The narrowing is declared and measured on three legs — population, the 5 test files that reference invoked-as (all inside the narrowed run, and run explicitly), and the fact that entry-guard-wiring.test.ts states in its own header that it pins no counts and no header text. That last one is the leg most people skip.

⚠️ The pnpm test -- --maxWorkers=2 rejection reported rather than hidden is the right instinct. objectui#3288 is real — args after -- are silently dropped — and the guard catching you is the guard working.

Re-taking the figures on 2dc4aa709 and naming that commit in the text, keeping 7c96c9420 as history under its own commit, and closing with an instruction to re-take rather than edit in place: that is the part that stops the third round of this card.

Changeset — none, correct

Your own note is the reasoning I'd have given: check-changeset-presence.mjs exits 0 either way so it is not deciding it, and you read the diff instead. That is now the fourth card tonight where a gate was green on both branches of a decision.

Sibling check — closes the card's open ⚠️

NEITHER objectstack copy is stale … objectstack's scripts/invoked-as.mjs carries the CORRECT original, true in that tree.

Read-only, no worktree, no edit, exactly as scoped. That resolves the "worth checking in the same pass" flag on #6243 with a negative result, so no cross-repo card is owed for this defect. Recording the negative is as useful as a positive would have been.

Your third finding — that the "change one, change the others" obligation is visible from only one of its three ends — I am filing separately in objectstack, where the fix would live.

⛔ Not armed yet

Type Check, Lint and all four Test shards are in_progress. I arm when every check carries a conclusion.


Generated by Claude Code

@yinlianghui-tw
yinlianghui-tw marked this pull request as ready for review August 25, 2026 05:20
@yinlianghui-tw
yinlianghui-tw added this pull request to the merge queueAug 25, 2026
Merged via the queue into main with commit ef2a3bdAug 25, 2026
27 checks passed
@yinlianghui-tw
yinlianghui-tw deleted the claude/issue-6243-invoked-as-stale-enforcement-note branch August 25, 2026 05:42
yinlianghui-tw pushed a commit that referenced this pull request Aug 25, 2026
…e page keeps denying it
The label object was re-minted in this repository (auto-created by being applied
by name) and is now being read as a mechanism: a triage comment on #6243
instructed a PR to carry it, the developer refused, and the refusal was upheld
on PR #6260.
A test cannot see GitHub's label data, so it does not try. It pins the two
halves that live in the tree: no read of the name under .github/ or scripts/
(option B landing without a decision), and the page keeping its denial plus the
alternative to reach for instead.
Also corrects a claim on that page that had become false: it reported a
point-in-time labels-API reading from 2026-08-08 saying the label did not
exist. It does. A reading nothing in the tree can keep true is replaced by the
durable invariant, and the third assertion pins that it is not restored.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants

@yinlianghui-tw@claude