Skip to content

Commit 287334a

Browse files
committed
fix(devx): give check-release-page-status.mjs a main() so its verdict stops running inside importers
The file exports eleven predicates, and check-release-section-coverage.mjs is a real reader of that surface — it inherits this gate's scope floor and pins the two equal in its own self-test. Unguarded, importing any one of those predicates ran the entire release-page gate and printed its verdict, so a caller's output carried another gate's OK line above its own. The run block becomes main(); it and the self-test dispatch now sit behind isEntrypoint(import.meta.url). Byte-for-byte against the pristine base tree on both paths, plus both paths of check-release-section-coverage.mjs — the sibling that reads this module — all cmp-clean on stdout, stderr and exit code. Import probe with clean argv: sentinel only, empty stderr, exit 0. check:entry-guard named it STALE first; ledger 8 -> 7.
1 parent 0c26629 commit 287334a

2 files changed

Lines changed: 48 additions & 38 deletions

File tree

‎scripts/check-entry-guard.mjs‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,6 @@ const KNOWN_IMPORT_UNSAFE = new Set([
462462
'scripts/check-empty-changeset.mjs',
463463
'scripts/check-error-status-conformance.mjs',
464464
'scripts/check-query-options-erasure-ratchet.mjs',
465-
'scripts/check-release-page-status.mjs',
466465
'scripts/objectui-range.mjs',
467466
'scripts/qa/qa-rollup.mjs',
468467
'scripts/ts-parse.mjs',

‎scripts/check-release-page-status.mjs‎

Lines changed: 48 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
// shipped, and the two corrected ones that replaced them.
100100
import { execFileSync } from 'node:child_process';
101101
import { readFileSync, existsSync } from 'node:fs';
102+
import { isEntrypoint } from './invoked-as.mjs';
102103

103104
const SPEC_CHANGELOG = 'packages/spec/CHANGELOG.md';
104105
const SPEC_PKG = 'packages/spec/package.json';
@@ -837,51 +838,61 @@ function renderOk(checked, tagCorroborations) {
837838

838839
// ── Run ──────────────────────────────────────────────────────────────────────
839840

840-
if (process.argv.includes('--self-test')) selfTest();
841+
function main() {
841842

842-
const changelogText = readFileSync(SPEC_CHANGELOG, 'utf8');
843-
const gaMajorList = gaMajors(changelogText);
844-
const specVersion = JSON.parse(readFileSync(SPEC_PKG, 'utf8')).version;
845-
const tagMajorList = readGaTagMajors();
843+
const changelogText = readFileSync(SPEC_CHANGELOG, 'utf8');
844+
const gaMajorList = gaMajors(changelogText);
845+
const specVersion = JSON.parse(readFileSync(SPEC_PKG, 'utf8')).version;
846+
const tagMajorList = readGaTagMajors();
846847

847-
const problems = instrumentProblems({ gaMajorList, specVersion, tagMajorList });
848+
const problems = instrumentProblems({ gaMajorList, specVersion, tagMajorList });
848849

849-
const checked = gaMajorList.filter(inScope);
850-
if (problems.length === 0 && checked.length === 0) {
851-
problems.push(
852-
`no GA major at or above v${SCOPE_FLOOR_MAJOR} was found in ${SPEC_CHANGELOG}, so this gate `
853-
+ 'checked ZERO pages. v16 and v17 have both shipped and majors only go up, so this cannot be a '
854-
+ 'true reading — a gate that silently checks nothing is worse than no gate. Fix the parse.',
855-
);
856-
}
857-
858-
if (problems.length === 0) {
859-
const indexText = existsSync(INDEX_PATH) ? readFileSync(INDEX_PATH, 'utf8') : null;
860-
if (indexText === null) {
861-
problems.push(`${INDEX_PATH} is missing — there is no releases index to check entries against.`);
850+
const checked = gaMajorList.filter(inScope);
851+
if (problems.length === 0 && checked.length === 0) {
852+
problems.push(
853+
`no GA major at or above v${SCOPE_FLOOR_MAJOR} was found in ${SPEC_CHANGELOG}, so this gate `
854+
+ 'checked ZERO pages. v16 and v17 have both shipped and majors only go up, so this cannot be a '
855+
+ 'true reading — a gate that silently checks nothing is worse than no gate. Fix the parse.',
856+
);
862857
}
863-
for (const major of checked) {
864-
const pagePath = `${RELEASES_DIR}/v${major}.mdx`;
865-
if (!existsSync(pagePath)) {
858+
859+
if (problems.length === 0) {
860+
const indexText = existsSync(INDEX_PATH) ? readFileSync(INDEX_PATH, 'utf8') : null;
861+
if (indexText === null) {
862+
problems.push(`${INDEX_PATH} is missing — there is no releases index to check entries against.`);
863+
}
864+
for (const major of checked) {
865+
const pagePath = `${RELEASES_DIR}/v${major}.mdx`;
866+
if (!existsSync(pagePath)) {
867+
problems.push(
868+
`${pagePath} is missing — @objectstack/spec ${major}.x is GA but there is no release page to `
869+
+ 'check. (check:release-notes is the gate that owns page existence; this one owns what the '
870+
+ 'page SAYS.)',
871+
);
872+
continue;
873+
}
866874
problems.push(
867-
`${pagePath} is missing — @objectstack/spec ${major}.x is GA but there is no release page to `
868-
+ 'check. (check:release-notes is the gate that owns page existence; this one owns what the '
869-
+ 'page SAYS.)',
875+
...pageStatusProblems(major, pagePath, statusBlockquote(readFileSync(pagePath, 'utf8'))),
870876
);
871-
continue;
872-
}
873-
problems.push(
874-
...pageStatusProblems(major, pagePath, statusBlockquote(readFileSync(pagePath, 'utf8'))),
875-
);
876-
if (indexText !== null) {
877-
problems.push(...indexStatusProblems(major, indexEntryLine(indexText, major)));
877+
if (indexText !== null) {
878+
problems.push(...indexStatusProblems(major, indexEntryLine(indexText, major)));
879+
}
878880
}
879881
}
880-
}
881882

882-
if (problems.length > 0) {
883-
console.error(renderFailure(problems));
884-
process.exit(1);
883+
if (problems.length > 0) {
884+
console.error(renderFailure(problems));
885+
process.exit(1);
886+
}
887+
888+
console.log(renderOk(checked, tagMajorList.filter(inScope).length));
885889
}
886890

887-
console.log(renderOk(checked, tagMajorList.filter(inScope).length));
891+
// Guarded: this module exports its predicates (`gaMajors`, `pageStatusProblems`,
892+
// `indexStatusProblems` — check-release-section-coverage.mjs inherits the same
893+
// scope floor from it), and unguarded the whole gate ran inside any importer,
894+
// printing its verdict over theirs.
895+
if (isEntrypoint(import.meta.url)) {
896+
if (process.argv.includes('--self-test')) selfTest();
897+
main();
898+
}

0 commit comments

Comments
 (0)