Skip to content

scripts/pm/check-governed-merges.mjs runs its --self-test at module scope — a second instance of #9757's class, now with a real importer that it can mask #9839

Description

@os-warren

Measured while implementing #9525 (the governed-surface prose pin). Not repaired there: different defect class, and #9757 already owns the class plus the "pick one guard spelling" cleanup. Filed unassigned, severity for triage.

Facts

scripts/pm/check-governed-merges.mjs ends with an unguarded, argv-reading dispatch at module scope:

if(process.argv.includes('--self-test')){selfTest();}

selfTest() calls process.exit(1) on failure. There is no entry-point guard, so the branch is taken by any importer whose own argv contains --self-test — the flag every sibling gate in this family uses, by convention (check:pm-skill-ratchet, check:pm-skill-id-lint, check:pm-governed-merges itself all spell it that way in package.json).

Measured on origin/main at 152bff8fc, from the first real importer (scripts/pm/check-governed-prose.mjs, which imports GOVERNED_SURFACES) before the workaround went in:

✓ check-governed-merges --self-test: 77 assertions (the unified governed predicate + near misses, ...)
✓ check-governed-prose self-test: 24 cases pass.

Two self-tests ran; only one was asked for.

Why it matters — the masking direction

The noise is cosmetic. The consequence is not: on the failure path the imported module calls process.exit(1)during the import, before a single case of the importer's own self-test reports. The importer's gate would then go red under another script's name, with the importer's own result never produced. That is the silent-success shape's mirror — a gate whose verdict is replaced by a neighbour's — and it is reachable in exactly the situation where the importer's self-test matters most.

Unlike #9757 this module is not merely unimportable in principle: GOVERNED_SURFACES is the register the whole governed-surface regime reads, so importing it is the correct and intended thing to do, and #9525 now does. The re-export is live and load-bearing.

Current state — worked around, not fixed

scripts/pm/check-governed-prose.mjs withholds the flag for the duration of the import:

constrealArgv=process.argv;process.argv=realArgv.filter((arg)=>arg!=='--self-test');const{GOVERNED_SURFACES}=awaitimport('./check-governed-merges.mjs');process.argv=realArgv;

That is a consumer-side accommodation for a producer-side defect — the shape Prime Directive #12 says to fix at the producer. It is documented in place with this issue's reasoning, and it should be deleted when the guard lands.

Relation to #9757

Same class, sibling file. #9757 records the defect in scripts/pm/dispatch-gates.mjs, names the precedent (#6566 → PR #6695 on check-adr-0087-registration.mjs), and already carries the "the tree spells this guard four different ways" cleanup. This is a fifth spelling site and a fifth file; whoever settles the spelling there should sweep this one in the same pass. Filed as a sub-issue of #9757 rather than standalone for that reason.

Dedupe

search_issues for "check-governed-merges.mjs self-test runs on import entry-point guard argv" returns #9757 (open, the class), #6566/#8528/#9651 (closed, other scripts), and no card about this file's import semantics.


Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions