Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 167 additions & 3 deletions scripts/import-prerequisite.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -79,8 +79,8 @@
*/
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { dirname, join, relative, resolve, sep } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { WORKSPACE_SCOPE, workspaceBuildFix } from './cli-build-prerequisite.mjs';
import { isEntrypoint } from './invoked-as.mjs';

Expand DownExpand Up@@ -253,6 +253,70 @@ function isWholePackage(pkg, fromDir) {
return Boolean(dir) && entryPointOnDisk(dir).present === true;
}

/**
* The repo root at or above a directory: the nearest ancestor holding
* `pnpm-workspace.yaml`. '' when none does.
*
* ⚠️ The marker is the workspace manifest and NOT `.git`, which looks like the
* more obvious choice and is wrong for the exact checkout shape `CLAUDE.md`
* mandates. In a linked worktree — `git worktree add ../objectstack-<task>` —
* `.git` is a FILE containing a `gitdir:` pointer, not a directory (measured
* here: 70 bytes, ASCII). A walk testing `statSync('.git').isDirectory()`
* therefore steps straight PAST the worktree root, finds nothing above it, and
* reports no root at all — in the one tree every agent actually works in.
* `existsSync` on `.git` would survive that, but the workspace manifest is the
* marker this repo already publishes for "repo root" (AGENTS.md names
* `findUp(existsSync(join(dir, 'pnpm-workspace.yaml')))` as the spelling), so
* it is the one used here rather than a second convention.
*
* NEAREST wins, as node and pnpm resolve. The tree holds a second
* `pnpm-workspace.yaml`, under `packages/create-objectstack/src/templates/blank/`
* — a scaffold template, containing no gate and importing nothing, so no
* importer resolves through it. A "highest wins" walk would be the riskier rule:
* it can climb OUT of the repo when the checkout sits inside another workspace.
*/
export function repoRootFrom(dir) {
let d = resolve(dir);
for (;;) {
if (existsSync(join(d, 'pnpm-workspace.yaml'))) return d;
const parent = dirname(d);
if (parent === d) return '';
d = parent;
}
}

/**
* The importer spelled the way the reader can actually RUN it.
*
* The gate NAME is a basename and is correct as one (it is what the headline
* says, and what the gate is called). The COMMAND is not a name, it is a path,
* and interpolating the basename into a hard-coded `scripts/` directory was
* right for the 42 importers under `scripts/**` and wrong for the three under
* `packages/lint/scripts/**`: it printed `node scripts/check-doc-formula-
* expressions.mjs`, which does not exist. Copy-pasting it answered
* `Cannot find module` at exit 1 — so a banner whose whole purpose is to stop a
* reader misreading an exit code handed them a THIRD failure, wearing a
* finding's exit code, one level down from the defect this module removes.
*
* Falls back to the ABSOLUTE path when no root is found, never to the old
* basename guess. An absolute path always runs; a relative path invented
* against a root that was never located is the confident wrong answer this
* module exists to refuse.
*
* Emitted with POSIX separators: the result is a shell command, not a path for
* this process to open.
*/
export function importerCommandPath(importerUrl) {
const file = fileURLToPath(importerUrl);
const root = repoRootFrom(dirname(file));
if (!root) return file;
const rel = relative(root, file);
// A path that climbs out of the root is not repo-relative in any useful
// sense; print the absolute one rather than a `../..` chain.
if (!rel || rel.startsWith('..')) return file;
return rel.split(sep).join('/');
}

/**
* The package node says it could not find, read out of its own error text.
*
Expand DownExpand Up@@ -493,6 +557,13 @@ export function reportPrerequisiteNotMet(importerUrl, verdict, measures) {
*/
function prerequisiteNotMetText(importerUrl, verdict, measures) {
const gate = fileURLToPath(importerUrl).split('/').pop().replace(/\.mjs$/, '');
// The path to RUN and the name to CALL IT BY are two different strings, and
// only the first moves. ⛔ The `/tmp/${gate}.log` sink below keeps the
// BASENAME on purpose: a repo-relative path there would spell
// `/tmp/packages/lint/scripts/….log`, whose parent directories do not exist,
// so the redirect fails and the reader is handed a broken command again —
// the same defect, relocated one token to the right.
const command = importerCommandPath(importerUrl);
const subject = measures ? `whether ${measures}` : `what it gates`;
return (
`\n${gate}: PREREQUISITE NOT MET — ${verdict.headline}\n\n` +
Expand All@@ -502,7 +573,7 @@ function prerequisiteNotMetText(importerUrl, verdict, measures) {
` result says NOTHING about ${subject}. It is NOT a finding, and it is not\n` +
` evidence that anything in the tree is wrong.\n` +
` (Exit code ${EXIT_PREREQUISITE_NOT_MET}, distinct from a finding's ${EXIT_FINDINGS} — capture it BEFORE any pipe:\n` +
` \`node scripts/${gate}.mjs > /tmp/${gate}.log 2>&1; echo "EXIT=$?"\`.\n` +
` \`node ${command} > /tmp/${gate}.log 2>&1; echo "EXIT=$?"\`.\n` +
` Piped, \`$?\` is the LAST command's status, and \`head\`/\`tail\` essentially never fail — that\n` +
` is the false green, and no pipe shape repairs it. \`\${PIPESTATUS[0]}\`/\`pipefail\` do recover\n` +
` this gate's own code: \`| tail\` reads to EOF and forwards it, while \`| head -N\` closes the\n` +
Expand DownExpand Up@@ -682,6 +753,87 @@ export function selfTest() {
findPackageDir('whole-fixture', deep) === join(nm, 'whole-fixture'));
t('a package that is nowhere on the path is not found',
findPackageDir('totally-absent-fixture', deep) === '');

// ── the printed COMMAND: a path the reader can run, not a name ──────────
//
// A REAL tree again, for this module's standing reason: the derivation
// turns on files being on disk, and a model would agree with an
// implementation that never looked.
//
// The fixture is shaped like the checkout every agent actually works in —
// a LINKED WORKTREE, whose `.git` is a FILE holding a `gitdir:` pointer.
// That shape is the whole reason the marker is the workspace manifest, and
// the negative control below is what turns that from a preference into a
// measurement.
const wt = join(dir, 'objectstack-issue-fixture');
mkdirSync(join(wt, 'scripts'), { recursive: true });
mkdirSync(join(wt, 'packages', 'lint', 'scripts'), { recursive: true });
writeFileSync(join(wt, 'pnpm-workspace.yaml'), "packages:\n - 'packages/*'\n");
writeFileSync(join(wt, '.git'), `gitdir: ${join(dir, 'common', 'worktrees', 'wt')}\n`);

const advisoryFor = (abs) =>
prerequisiteNotMetText(pathToFileURL(abs).href, { headline: 'h', detail: ['d'], fix: 'f' }, undefined);
const lintGate = join(wt, 'packages', 'lint', 'scripts', 'check-doc-formula-expressions.mjs');
const rootGate = join(wt, 'scripts', 'check-ci-filter-parity.mjs');

// (a) THE DEFECT, in both directions. The negative is the load-bearing
// one: `node scripts/check-doc-formula-expressions.mjs` is the exact string
// this card exists to stop printing, and it names a file that has never
// existed.
t('a packages/lint/scripts importer prints its REAL repo-relative path',
advisoryFor(lintGate).includes('`node packages/lint/scripts/check-doc-formula-expressions.mjs > '),
advisoryFor(lintGate));
t('⛔ and NEVER the `scripts/` basename guess, which names no file on disk',
!advisoryFor(lintGate).includes('node scripts/check-doc-formula-expressions.mjs'));

// (b) The 42 importers under `scripts/**` inherit this line verbatim, so
// the spelling is pinned WHOLE — command, log sink and the `echo` that
// captures the code before any pipe.
t('a scripts/** importer still prints `scripts/NAME.mjs`, spelling unchanged',
advisoryFor(rootGate).includes(
'`node scripts/check-ci-filter-parity.mjs > /tmp/check-ci-filter-parity.log 2>&1; echo "EXIT=$?"`'),
advisoryFor(rootGate));

// (c) The marker choice, as a paired measurement rather than an assertion.
const gitIsDirectoryWalk = (from) => {
let d = resolve(from);
for (;;) {
try {
if (statSync(join(d, '.git')).isDirectory()) return d;
} catch { /* absent here; keep walking */ }
const parent = dirname(d);
if (parent === d) return '';
d = parent;
}
};
t('the workspace-manifest walk finds the worktree root',
repoRootFrom(join(wt, 'packages', 'lint', 'scripts')) === wt);
t('NEGATIVE CONTROL: a `.git`-isDirectory walk finds NO root in a worktree shape',
gitIsDirectoryWalk(join(wt, 'packages', 'lint', 'scripts')) === '' && statSync(join(wt, '.git')).isFile());

// (d) No locatable root: absolute, which always runs. ⛔ Never a relative
// path invented against a root that was never found.
const orphanGate = join(dir, 'no-marker', 'scripts', 'check-orphan-fixture.mjs');
mkdirSync(dirname(orphanGate), { recursive: true });
t('an importer with no locatable root prints an ABSOLUTE path, always runnable',
importerCommandPath(pathToFileURL(orphanGate).href) === orphanGate,
importerCommandPath(pathToFileURL(orphanGate).href));
t('⛔ and never a relative path invented against a root that was not found',
!advisoryFor(orphanGate).includes('`node scripts/check-orphan-fixture.mjs'));

// (e) Triage's explicit boundary on this card: the HEADLINE gate name is a
// basename and is CORRECT as one. Only the command was wrong.
t('the headline still names the gate by BASENAME, never by path',
advisoryFor(lintGate).includes('\ncheck-doc-formula-expressions: PREREQUISITE NOT MET')
&& !advisoryFor(lintGate).includes('packages/lint/scripts/check-doc-formula-expressions: PREREQUISITE'),
advisoryFor(lintGate));

// (f) The log sink keeps the basename too — `/tmp/packages/lint/scripts/
// ….log` names directories that do not exist, so a blanket substitution
// would hand back a broken command one token to the right.
t('the /tmp log sink keeps the BASENAME — a repo-relative one names absent directories',
advisoryFor(lintGate).includes('> /tmp/check-doc-formula-expressions.log 2>&1')
&& !advisoryFor(lintGate).includes('/tmp/packages/lint'));
} finally {
rmSync(dir, { recursive: true, force: true });
}
Expand DownExpand Up@@ -738,6 +890,18 @@ export function selfTest() {
t('NEGATIVE CONTROL: the literal-exit pin can still fail', hardcodesExitCall(controlHardcodedExit));
t('NEGATIVE CONTROL: the literal-advisory pin can still fail', spellsALiteralCode(controlLiteralAdvisory));

// The same shape for the directory. The regression that costs something here
// is not a mistyped path: it is an author interpolating the gate NAME back
// into a hard-coded `scripts/` because the headline beside it does exactly
// that. It would read correct, stay green for the 42 gates under `scripts/`,
// and be wrong only for the three that are the whole point of this pin.
const hardcodesScriptsDir = (fn) => /`node scripts\//.test(fn.toString());
const controlHardcodedScriptsDir = () => ` \`node scripts/${'gate'}.mjs > /tmp/x.log\``;
t('the advisory INTERPOLATES the importer path rather than hard-coding `scripts/`',
!hardcodesScriptsDir(prerequisiteNotMetText));
t('NEGATIVE CONTROL: the hard-coded-directory pin can still fail',
hardcodesScriptsDir(controlHardcodedScriptsDir));

t('the refusal class is 3 — the code four sibling gates answer these words with',
EXIT_PREREQUISITE_NOT_MET === 3, String(EXIT_PREREQUISITE_NOT_MET));
t('the refusal class is distinct from a finding and from a pass',
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 167 additions & 3 deletions scripts/import-prerequisite.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -79,8 +79,8 @@
*/
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { dirname, join, relative, resolve, sep } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { WORKSPACE_SCOPE, workspaceBuildFix } from './cli-build-prerequisite.mjs';
import { isEntrypoint } from './invoked-as.mjs';

Expand DownExpand Up@@ -253,6 +253,70 @@ function isWholePackage(pkg, fromDir) {
return Boolean(dir) && entryPointOnDisk(dir).present === true;
}

/**
* The repo root at or above a directory: the nearest ancestor holding
* `pnpm-workspace.yaml`. '' when none does.
*
* ⚠️ The marker is the workspace manifest and NOT `.git`, which looks like the
* more obvious choice and is wrong for the exact checkout shape `CLAUDE.md`
* mandates. In a linked worktree — `git worktree add ../objectstack-<task>` —
* `.git` is a FILE containing a `gitdir:` pointer, not a directory (measured
* here: 70 bytes, ASCII). A walk testing `statSync('.git').isDirectory()`
* therefore steps straight PAST the worktree root, finds nothing above it, and
* reports no root at all — in the one tree every agent actually works in.
* `existsSync` on `.git` would survive that, but the workspace manifest is the
* marker this repo already publishes for "repo root" (AGENTS.md names
* `findUp(existsSync(join(dir, 'pnpm-workspace.yaml')))` as the spelling), so
* it is the one used here rather than a second convention.
*
* NEAREST wins, as node and pnpm resolve. The tree holds a second
* `pnpm-workspace.yaml`, under `packages/create-objectstack/src/templates/blank/`
* — a scaffold template, containing no gate and importing nothing, so no
* importer resolves through it. A "highest wins" walk would be the riskier rule:
* it can climb OUT of the repo when the checkout sits inside another workspace.
*/
export function repoRootFrom(dir) {
let d = resolve(dir);
for (;;) {
if (existsSync(join(d, 'pnpm-workspace.yaml'))) return d;
const parent = dirname(d);
if (parent === d) return '';
d = parent;
}
}

/**
* The importer spelled the way the reader can actually RUN it.
*
* The gate NAME is a basename and is correct as one (it is what the headline
* says, and what the gate is called). The COMMAND is not a name, it is a path,
* and interpolating the basename into a hard-coded `scripts/` directory was
* right for the 42 importers under `scripts/**` and wrong for the three under
* `packages/lint/scripts/**`: it printed `node scripts/check-doc-formula-
* expressions.mjs`, which does not exist. Copy-pasting it answered
* `Cannot find module` at exit 1 — so a banner whose whole purpose is to stop a
* reader misreading an exit code handed them a THIRD failure, wearing a
* finding's exit code, one level down from the defect this module removes.
*
* Falls back to the ABSOLUTE path when no root is found, never to the old
* basename guess. An absolute path always runs; a relative path invented
* against a root that was never located is the confident wrong answer this
* module exists to refuse.
*
* Emitted with POSIX separators: the result is a shell command, not a path for
* this process to open.
*/
export function importerCommandPath(importerUrl) {
const file = fileURLToPath(importerUrl);
const root = repoRootFrom(dirname(file));
if (!root) return file;
const rel = relative(root, file);
// A path that climbs out of the root is not repo-relative in any useful
// sense; print the absolute one rather than a `../..` chain.
if (!rel || rel.startsWith('..')) return file;
return rel.split(sep).join('/');
}

/**
* The package node says it could not find, read out of its own error text.
*
Expand DownExpand Up@@ -493,6 +557,13 @@ export function reportPrerequisiteNotMet(importerUrl, verdict, measures) {
*/
function prerequisiteNotMetText(importerUrl, verdict, measures) {
const gate = fileURLToPath(importerUrl).split('/').pop().replace(/\.mjs$/, '');
// The path to RUN and the name to CALL IT BY are two different strings, and
// only the first moves. ⛔ The `/tmp/${gate}.log` sink below keeps the
// BASENAME on purpose: a repo-relative path there would spell
// `/tmp/packages/lint/scripts/….log`, whose parent directories do not exist,
// so the redirect fails and the reader is handed a broken command again —
// the same defect, relocated one token to the right.
const command = importerCommandPath(importerUrl);
const subject = measures ? `whether ${measures}` : `what it gates`;
return (
`\n${gate}: PREREQUISITE NOT MET — ${verdict.headline}\n\n` +
Expand All@@ -502,7 +573,7 @@ function prerequisiteNotMetText(importerUrl, verdict, measures) {
` result says NOTHING about ${subject}. It is NOT a finding, and it is not\n` +
` evidence that anything in the tree is wrong.\n` +
` (Exit code ${EXIT_PREREQUISITE_NOT_MET}, distinct from a finding's ${EXIT_FINDINGS} — capture it BEFORE any pipe:\n` +
` \`node scripts/${gate}.mjs > /tmp/${gate}.log 2>&1; echo "EXIT=$?"\`.\n` +
` \`node ${command} > /tmp/${gate}.log 2>&1; echo "EXIT=$?"\`.\n` +
` Piped, \`$?\` is the LAST command's status, and \`head\`/\`tail\` essentially never fail — that\n` +
` is the false green, and no pipe shape repairs it. \`\${PIPESTATUS[0]}\`/\`pipefail\` do recover\n` +
` this gate's own code: \`| tail\` reads to EOF and forwards it, while \`| head -N\` closes the\n` +
Expand DownExpand Up@@ -682,6 +753,87 @@ export function selfTest() {
findPackageDir('whole-fixture', deep) === join(nm, 'whole-fixture'));
t('a package that is nowhere on the path is not found',
findPackageDir('totally-absent-fixture', deep) === '');

// ── the printed COMMAND: a path the reader can run, not a name ──────────
//
// A REAL tree again, for this module's standing reason: the derivation
// turns on files being on disk, and a model would agree with an
// implementation that never looked.
//
// The fixture is shaped like the checkout every agent actually works in —
// a LINKED WORKTREE, whose `.git` is a FILE holding a `gitdir:` pointer.
// That shape is the whole reason the marker is the workspace manifest, and
// the negative control below is what turns that from a preference into a
// measurement.
const wt = join(dir, 'objectstack-issue-fixture');
mkdirSync(join(wt, 'scripts'), { recursive: true });
mkdirSync(join(wt, 'packages', 'lint', 'scripts'), { recursive: true });
writeFileSync(join(wt, 'pnpm-workspace.yaml'), "packages:\n - 'packages/*'\n");
writeFileSync(join(wt, '.git'), `gitdir: ${join(dir, 'common', 'worktrees', 'wt')}\n`);

const advisoryFor = (abs) =>
prerequisiteNotMetText(pathToFileURL(abs).href, { headline: 'h', detail: ['d'], fix: 'f' }, undefined);
const lintGate = join(wt, 'packages', 'lint', 'scripts', 'check-doc-formula-expressions.mjs');
const rootGate = join(wt, 'scripts', 'check-ci-filter-parity.mjs');

// (a) THE DEFECT, in both directions. The negative is the load-bearing
// one: `node scripts/check-doc-formula-expressions.mjs` is the exact string
// this card exists to stop printing, and it names a file that has never
// existed.
t('a packages/lint/scripts importer prints its REAL repo-relative path',
advisoryFor(lintGate).includes('`node packages/lint/scripts/check-doc-formula-expressions.mjs > '),
advisoryFor(lintGate));
t('⛔ and NEVER the `scripts/` basename guess, which names no file on disk',
!advisoryFor(lintGate).includes('node scripts/check-doc-formula-expressions.mjs'));

// (b) The 42 importers under `scripts/**` inherit this line verbatim, so
// the spelling is pinned WHOLE — command, log sink and the `echo` that
// captures the code before any pipe.
t('a scripts/** importer still prints `scripts/NAME.mjs`, spelling unchanged',
advisoryFor(rootGate).includes(
'`node scripts/check-ci-filter-parity.mjs > /tmp/check-ci-filter-parity.log 2>&1; echo "EXIT=$?"`'),
advisoryFor(rootGate));

// (c) The marker choice, as a paired measurement rather than an assertion.
const gitIsDirectoryWalk = (from) => {
let d = resolve(from);
for (;;) {
try {
if (statSync(join(d, '.git')).isDirectory()) return d;
} catch { /* absent here; keep walking */ }
const parent = dirname(d);
if (parent === d) return '';
d = parent;
}
};
t('the workspace-manifest walk finds the worktree root',
repoRootFrom(join(wt, 'packages', 'lint', 'scripts')) === wt);
t('NEGATIVE CONTROL: a `.git`-isDirectory walk finds NO root in a worktree shape',
gitIsDirectoryWalk(join(wt, 'packages', 'lint', 'scripts')) === '' && statSync(join(wt, '.git')).isFile());

// (d) No locatable root: absolute, which always runs. ⛔ Never a relative
// path invented against a root that was never found.
const orphanGate = join(dir, 'no-marker', 'scripts', 'check-orphan-fixture.mjs');
mkdirSync(dirname(orphanGate), { recursive: true });
t('an importer with no locatable root prints an ABSOLUTE path, always runnable',
importerCommandPath(pathToFileURL(orphanGate).href) === orphanGate,
importerCommandPath(pathToFileURL(orphanGate).href));
t('⛔ and never a relative path invented against a root that was not found',
!advisoryFor(orphanGate).includes('`node scripts/check-orphan-fixture.mjs'));

// (e) Triage's explicit boundary on this card: the HEADLINE gate name is a
// basename and is CORRECT as one. Only the command was wrong.
t('the headline still names the gate by BASENAME, never by path',
advisoryFor(lintGate).includes('\ncheck-doc-formula-expressions: PREREQUISITE NOT MET')
&& !advisoryFor(lintGate).includes('packages/lint/scripts/check-doc-formula-expressions: PREREQUISITE'),
advisoryFor(lintGate));

// (f) The log sink keeps the basename too — `/tmp/packages/lint/scripts/
// ….log` names directories that do not exist, so a blanket substitution
// would hand back a broken command one token to the right.
t('the /tmp log sink keeps the BASENAME — a repo-relative one names absent directories',
advisoryFor(lintGate).includes('> /tmp/check-doc-formula-expressions.log 2>&1')
&& !advisoryFor(lintGate).includes('/tmp/packages/lint'));
} finally {
rmSync(dir, { recursive: true, force: true });
}
Expand DownExpand Up@@ -738,6 +890,18 @@ export function selfTest() {
t('NEGATIVE CONTROL: the literal-exit pin can still fail', hardcodesExitCall(controlHardcodedExit));
t('NEGATIVE CONTROL: the literal-advisory pin can still fail', spellsALiteralCode(controlLiteralAdvisory));

// The same shape for the directory. The regression that costs something here
// is not a mistyped path: it is an author interpolating the gate NAME back
// into a hard-coded `scripts/` because the headline beside it does exactly
// that. It would read correct, stay green for the 42 gates under `scripts/`,
// and be wrong only for the three that are the whole point of this pin.
const hardcodesScriptsDir = (fn) => /`node scripts\//.test(fn.toString());
const controlHardcodedScriptsDir = () => ` \`node scripts/${'gate'}.mjs > /tmp/x.log\``;
t('the advisory INTERPOLATES the importer path rather than hard-coding `scripts/`',
!hardcodesScriptsDir(prerequisiteNotMetText));
t('NEGATIVE CONTROL: the hard-coded-directory pin can still fail',
hardcodesScriptsDir(controlHardcodedScriptsDir));

t('the refusal class is 3 — the code four sibling gates answer these words with',
EXIT_PREREQUISITE_NOT_MET === 3, String(EXIT_PREREQUISITE_NOT_MET));
t('the refusal class is distinct from a finding and from a pass',
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 167 additions & 3 deletions scripts/import-prerequisite.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -79,8 +79,8 @@
*/
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { dirname, join, relative, resolve, sep } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { WORKSPACE_SCOPE, workspaceBuildFix } from './cli-build-prerequisite.mjs';
import { isEntrypoint } from './invoked-as.mjs';

Expand DownExpand Up@@ -253,6 +253,70 @@ function isWholePackage(pkg, fromDir) {
return Boolean(dir) && entryPointOnDisk(dir).present === true;
}

/**
* The repo root at or above a directory: the nearest ancestor holding
* `pnpm-workspace.yaml`. '' when none does.
*
* ⚠️ The marker is the workspace manifest and NOT `.git`, which looks like the
* more obvious choice and is wrong for the exact checkout shape `CLAUDE.md`
* mandates. In a linked worktree — `git worktree add ../objectstack-<task>` —
* `.git` is a FILE containing a `gitdir:` pointer, not a directory (measured
* here: 70 bytes, ASCII). A walk testing `statSync('.git').isDirectory()`
* therefore steps straight PAST the worktree root, finds nothing above it, and
* reports no root at all — in the one tree every agent actually works in.
* `existsSync` on `.git` would survive that, but the workspace manifest is the
* marker this repo already publishes for "repo root" (AGENTS.md names
* `findUp(existsSync(join(dir, 'pnpm-workspace.yaml')))` as the spelling), so
* it is the one used here rather than a second convention.
*
* NEAREST wins, as node and pnpm resolve. The tree holds a second
* `pnpm-workspace.yaml`, under `packages/create-objectstack/src/templates/blank/`
* — a scaffold template, containing no gate and importing nothing, so no
* importer resolves through it. A "highest wins" walk would be the riskier rule:
* it can climb OUT of the repo when the checkout sits inside another workspace.
*/
export function repoRootFrom(dir) {
let d = resolve(dir);
for (;;) {
if (existsSync(join(d, 'pnpm-workspace.yaml'))) return d;
const parent = dirname(d);
if (parent === d) return '';
d = parent;
}
}

/**
* The importer spelled the way the reader can actually RUN it.
*
* The gate NAME is a basename and is correct as one (it is what the headline
* says, and what the gate is called). The COMMAND is not a name, it is a path,
* and interpolating the basename into a hard-coded `scripts/` directory was
* right for the 42 importers under `scripts/**` and wrong for the three under
* `packages/lint/scripts/**`: it printed `node scripts/check-doc-formula-
* expressions.mjs`, which does not exist. Copy-pasting it answered
* `Cannot find module` at exit 1 — so a banner whose whole purpose is to stop a
* reader misreading an exit code handed them a THIRD failure, wearing a
* finding's exit code, one level down from the defect this module removes.
*
* Falls back to the ABSOLUTE path when no root is found, never to the old
* basename guess. An absolute path always runs; a relative path invented
* against a root that was never located is the confident wrong answer this
* module exists to refuse.
*
* Emitted with POSIX separators: the result is a shell command, not a path for
* this process to open.
*/
export function importerCommandPath(importerUrl) {
const file = fileURLToPath(importerUrl);
const root = repoRootFrom(dirname(file));
if (!root) return file;
const rel = relative(root, file);
// A path that climbs out of the root is not repo-relative in any useful
// sense; print the absolute one rather than a `../..` chain.
if (!rel || rel.startsWith('..')) return file;
return rel.split(sep).join('/');
}

/**
* The package node says it could not find, read out of its own error text.
*
Expand DownExpand Up@@ -493,6 +557,13 @@ export function reportPrerequisiteNotMet(importerUrl, verdict, measures) {
*/
function prerequisiteNotMetText(importerUrl, verdict, measures) {
const gate = fileURLToPath(importerUrl).split('/').pop().replace(/\.mjs$/, '');
// The path to RUN and the name to CALL IT BY are two different strings, and
// only the first moves. ⛔ The `/tmp/${gate}.log` sink below keeps the
// BASENAME on purpose: a repo-relative path there would spell
// `/tmp/packages/lint/scripts/….log`, whose parent directories do not exist,
// so the redirect fails and the reader is handed a broken command again —
// the same defect, relocated one token to the right.
const command = importerCommandPath(importerUrl);
const subject = measures ? `whether ${measures}` : `what it gates`;
return (
`\n${gate}: PREREQUISITE NOT MET — ${verdict.headline}\n\n` +
Expand All@@ -502,7 +573,7 @@ function prerequisiteNotMetText(importerUrl, verdict, measures) {
` result says NOTHING about ${subject}. It is NOT a finding, and it is not\n` +
` evidence that anything in the tree is wrong.\n` +
` (Exit code ${EXIT_PREREQUISITE_NOT_MET}, distinct from a finding's ${EXIT_FINDINGS} — capture it BEFORE any pipe:\n` +
` \`node scripts/${gate}.mjs > /tmp/${gate}.log 2>&1; echo "EXIT=$?"\`.\n` +
` \`node ${command} > /tmp/${gate}.log 2>&1; echo "EXIT=$?"\`.\n` +
` Piped, \`$?\` is the LAST command's status, and \`head\`/\`tail\` essentially never fail — that\n` +
` is the false green, and no pipe shape repairs it. \`\${PIPESTATUS[0]}\`/\`pipefail\` do recover\n` +
` this gate's own code: \`| tail\` reads to EOF and forwards it, while \`| head -N\` closes the\n` +
Expand DownExpand Up@@ -682,6 +753,87 @@ export function selfTest() {
findPackageDir('whole-fixture', deep) === join(nm, 'whole-fixture'));
t('a package that is nowhere on the path is not found',
findPackageDir('totally-absent-fixture', deep) === '');

// ── the printed COMMAND: a path the reader can run, not a name ──────────
//
// A REAL tree again, for this module's standing reason: the derivation
// turns on files being on disk, and a model would agree with an
// implementation that never looked.
//
// The fixture is shaped like the checkout every agent actually works in —
// a LINKED WORKTREE, whose `.git` is a FILE holding a `gitdir:` pointer.
// That shape is the whole reason the marker is the workspace manifest, and
// the negative control below is what turns that from a preference into a
// measurement.
const wt = join(dir, 'objectstack-issue-fixture');
mkdirSync(join(wt, 'scripts'), { recursive: true });
mkdirSync(join(wt, 'packages', 'lint', 'scripts'), { recursive: true });
writeFileSync(join(wt, 'pnpm-workspace.yaml'), "packages:\n - 'packages/*'\n");
writeFileSync(join(wt, '.git'), `gitdir: ${join(dir, 'common', 'worktrees', 'wt')}\n`);

const advisoryFor = (abs) =>
prerequisiteNotMetText(pathToFileURL(abs).href, { headline: 'h', detail: ['d'], fix: 'f' }, undefined);
const lintGate = join(wt, 'packages', 'lint', 'scripts', 'check-doc-formula-expressions.mjs');
const rootGate = join(wt, 'scripts', 'check-ci-filter-parity.mjs');

// (a) THE DEFECT, in both directions. The negative is the load-bearing
// one: `node scripts/check-doc-formula-expressions.mjs` is the exact string
// this card exists to stop printing, and it names a file that has never
// existed.
t('a packages/lint/scripts importer prints its REAL repo-relative path',
advisoryFor(lintGate).includes('`node packages/lint/scripts/check-doc-formula-expressions.mjs > '),
advisoryFor(lintGate));
t('⛔ and NEVER the `scripts/` basename guess, which names no file on disk',
!advisoryFor(lintGate).includes('node scripts/check-doc-formula-expressions.mjs'));

// (b) The 42 importers under `scripts/**` inherit this line verbatim, so
// the spelling is pinned WHOLE — command, log sink and the `echo` that
// captures the code before any pipe.
t('a scripts/** importer still prints `scripts/NAME.mjs`, spelling unchanged',
advisoryFor(rootGate).includes(
'`node scripts/check-ci-filter-parity.mjs > /tmp/check-ci-filter-parity.log 2>&1; echo "EXIT=$?"`'),
advisoryFor(rootGate));

// (c) The marker choice, as a paired measurement rather than an assertion.
const gitIsDirectoryWalk = (from) => {
let d = resolve(from);
for (;;) {
try {
if (statSync(join(d, '.git')).isDirectory()) return d;
} catch { /* absent here; keep walking */ }
const parent = dirname(d);
if (parent === d) return '';
d = parent;
}
};
t('the workspace-manifest walk finds the worktree root',
repoRootFrom(join(wt, 'packages', 'lint', 'scripts')) === wt);
t('NEGATIVE CONTROL: a `.git`-isDirectory walk finds NO root in a worktree shape',
gitIsDirectoryWalk(join(wt, 'packages', 'lint', 'scripts')) === '' && statSync(join(wt, '.git')).isFile());

// (d) No locatable root: absolute, which always runs. ⛔ Never a relative
// path invented against a root that was never found.
const orphanGate = join(dir, 'no-marker', 'scripts', 'check-orphan-fixture.mjs');
mkdirSync(dirname(orphanGate), { recursive: true });
t('an importer with no locatable root prints an ABSOLUTE path, always runnable',
importerCommandPath(pathToFileURL(orphanGate).href) === orphanGate,
importerCommandPath(pathToFileURL(orphanGate).href));
t('⛔ and never a relative path invented against a root that was not found',
!advisoryFor(orphanGate).includes('`node scripts/check-orphan-fixture.mjs'));

// (e) Triage's explicit boundary on this card: the HEADLINE gate name is a
// basename and is CORRECT as one. Only the command was wrong.
t('the headline still names the gate by BASENAME, never by path',
advisoryFor(lintGate).includes('\ncheck-doc-formula-expressions: PREREQUISITE NOT MET')
&& !advisoryFor(lintGate).includes('packages/lint/scripts/check-doc-formula-expressions: PREREQUISITE'),
advisoryFor(lintGate));

// (f) The log sink keeps the basename too — `/tmp/packages/lint/scripts/
// ….log` names directories that do not exist, so a blanket substitution
// would hand back a broken command one token to the right.
t('the /tmp log sink keeps the BASENAME — a repo-relative one names absent directories',
advisoryFor(lintGate).includes('> /tmp/check-doc-formula-expressions.log 2>&1')
&& !advisoryFor(lintGate).includes('/tmp/packages/lint'));
} finally {
rmSync(dir, { recursive: true, force: true });
}
Expand DownExpand Up@@ -738,6 +890,18 @@ export function selfTest() {
t('NEGATIVE CONTROL: the literal-exit pin can still fail', hardcodesExitCall(controlHardcodedExit));
t('NEGATIVE CONTROL: the literal-advisory pin can still fail', spellsALiteralCode(controlLiteralAdvisory));

// The same shape for the directory. The regression that costs something here
// is not a mistyped path: it is an author interpolating the gate NAME back
// into a hard-coded `scripts/` because the headline beside it does exactly
// that. It would read correct, stay green for the 42 gates under `scripts/`,
// and be wrong only for the three that are the whole point of this pin.
const hardcodesScriptsDir = (fn) => /`node scripts\//.test(fn.toString());
const controlHardcodedScriptsDir = () => ` \`node scripts/${'gate'}.mjs > /tmp/x.log\``;
t('the advisory INTERPOLATES the importer path rather than hard-coding `scripts/`',
!hardcodesScriptsDir(prerequisiteNotMetText));
t('NEGATIVE CONTROL: the hard-coded-directory pin can still fail',
hardcodesScriptsDir(controlHardcodedScriptsDir));

t('the refusal class is 3 — the code four sibling gates answer these words with',
EXIT_PREREQUISITE_NOT_MET === 3, String(EXIT_PREREQUISITE_NOT_MET));
t('the refusal class is distinct from a finding and from a pass',
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 167 additions & 3 deletions scripts/import-prerequisite.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -79,8 +79,8 @@
*/
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { dirname, join, relative, resolve, sep } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { WORKSPACE_SCOPE, workspaceBuildFix } from './cli-build-prerequisite.mjs';
import { isEntrypoint } from './invoked-as.mjs';

Expand DownExpand Up@@ -253,6 +253,70 @@ function isWholePackage(pkg, fromDir) {
return Boolean(dir) && entryPointOnDisk(dir).present === true;
}

/**
* The repo root at or above a directory: the nearest ancestor holding
* `pnpm-workspace.yaml`. '' when none does.
*
* ⚠️ The marker is the workspace manifest and NOT `.git`, which looks like the
* more obvious choice and is wrong for the exact checkout shape `CLAUDE.md`
* mandates. In a linked worktree — `git worktree add ../objectstack-<task>` —
* `.git` is a FILE containing a `gitdir:` pointer, not a directory (measured
* here: 70 bytes, ASCII). A walk testing `statSync('.git').isDirectory()`
* therefore steps straight PAST the worktree root, finds nothing above it, and
* reports no root at all — in the one tree every agent actually works in.
* `existsSync` on `.git` would survive that, but the workspace manifest is the
* marker this repo already publishes for "repo root" (AGENTS.md names
* `findUp(existsSync(join(dir, 'pnpm-workspace.yaml')))` as the spelling), so
* it is the one used here rather than a second convention.
*
* NEAREST wins, as node and pnpm resolve. The tree holds a second
* `pnpm-workspace.yaml`, under `packages/create-objectstack/src/templates/blank/`
* — a scaffold template, containing no gate and importing nothing, so no
* importer resolves through it. A "highest wins" walk would be the riskier rule:
* it can climb OUT of the repo when the checkout sits inside another workspace.
*/
export function repoRootFrom(dir) {
let d = resolve(dir);
for (;;) {
if (existsSync(join(d, 'pnpm-workspace.yaml'))) return d;
const parent = dirname(d);
if (parent === d) return '';
d = parent;
}
}

/**
* The importer spelled the way the reader can actually RUN it.
*
* The gate NAME is a basename and is correct as one (it is what the headline
* says, and what the gate is called). The COMMAND is not a name, it is a path,
* and interpolating the basename into a hard-coded `scripts/` directory was
* right for the 42 importers under `scripts/**` and wrong for the three under
* `packages/lint/scripts/**`: it printed `node scripts/check-doc-formula-
* expressions.mjs`, which does not exist. Copy-pasting it answered
* `Cannot find module` at exit 1 — so a banner whose whole purpose is to stop a
* reader misreading an exit code handed them a THIRD failure, wearing a
* finding's exit code, one level down from the defect this module removes.
*
* Falls back to the ABSOLUTE path when no root is found, never to the old
* basename guess. An absolute path always runs; a relative path invented
* against a root that was never located is the confident wrong answer this
* module exists to refuse.
*
* Emitted with POSIX separators: the result is a shell command, not a path for
* this process to open.
*/
export function importerCommandPath(importerUrl) {
const file = fileURLToPath(importerUrl);
const root = repoRootFrom(dirname(file));
if (!root) return file;
const rel = relative(root, file);
// A path that climbs out of the root is not repo-relative in any useful
// sense; print the absolute one rather than a `../..` chain.
if (!rel || rel.startsWith('..')) return file;
return rel.split(sep).join('/');
}

/**
* The package node says it could not find, read out of its own error text.
*
Expand DownExpand Up@@ -493,6 +557,13 @@ export function reportPrerequisiteNotMet(importerUrl, verdict, measures) {
*/
function prerequisiteNotMetText(importerUrl, verdict, measures) {
const gate = fileURLToPath(importerUrl).split('/').pop().replace(/\.mjs$/, '');
// The path to RUN and the name to CALL IT BY are two different strings, and
// only the first moves. ⛔ The `/tmp/${gate}.log` sink below keeps the
// BASENAME on purpose: a repo-relative path there would spell
// `/tmp/packages/lint/scripts/….log`, whose parent directories do not exist,
// so the redirect fails and the reader is handed a broken command again —
// the same defect, relocated one token to the right.
const command = importerCommandPath(importerUrl);
const subject = measures ? `whether ${measures}` : `what it gates`;
return (
`\n${gate}: PREREQUISITE NOT MET — ${verdict.headline}\n\n` +
Expand All@@ -502,7 +573,7 @@ function prerequisiteNotMetText(importerUrl, verdict, measures) {
` result says NOTHING about ${subject}. It is NOT a finding, and it is not\n` +
` evidence that anything in the tree is wrong.\n` +
` (Exit code ${EXIT_PREREQUISITE_NOT_MET}, distinct from a finding's ${EXIT_FINDINGS} — capture it BEFORE any pipe:\n` +
` \`node scripts/${gate}.mjs > /tmp/${gate}.log 2>&1; echo "EXIT=$?"\`.\n` +
` \`node ${command} > /tmp/${gate}.log 2>&1; echo "EXIT=$?"\`.\n` +
` Piped, \`$?\` is the LAST command's status, and \`head\`/\`tail\` essentially never fail — that\n` +
` is the false green, and no pipe shape repairs it. \`\${PIPESTATUS[0]}\`/\`pipefail\` do recover\n` +
` this gate's own code: \`| tail\` reads to EOF and forwards it, while \`| head -N\` closes the\n` +
Expand DownExpand Up@@ -682,6 +753,87 @@ export function selfTest() {
findPackageDir('whole-fixture', deep) === join(nm, 'whole-fixture'));
t('a package that is nowhere on the path is not found',
findPackageDir('totally-absent-fixture', deep) === '');

// ── the printed COMMAND: a path the reader can run, not a name ──────────
//
// A REAL tree again, for this module's standing reason: the derivation
// turns on files being on disk, and a model would agree with an
// implementation that never looked.
//
// The fixture is shaped like the checkout every agent actually works in —
// a LINKED WORKTREE, whose `.git` is a FILE holding a `gitdir:` pointer.
// That shape is the whole reason the marker is the workspace manifest, and
// the negative control below is what turns that from a preference into a
// measurement.
const wt = join(dir, 'objectstack-issue-fixture');
mkdirSync(join(wt, 'scripts'), { recursive: true });
mkdirSync(join(wt, 'packages', 'lint', 'scripts'), { recursive: true });
writeFileSync(join(wt, 'pnpm-workspace.yaml'), "packages:\n - 'packages/*'\n");
writeFileSync(join(wt, '.git'), `gitdir: ${join(dir, 'common', 'worktrees', 'wt')}\n`);

const advisoryFor = (abs) =>
prerequisiteNotMetText(pathToFileURL(abs).href, { headline: 'h', detail: ['d'], fix: 'f' }, undefined);
const lintGate = join(wt, 'packages', 'lint', 'scripts', 'check-doc-formula-expressions.mjs');
const rootGate = join(wt, 'scripts', 'check-ci-filter-parity.mjs');

// (a) THE DEFECT, in both directions. The negative is the load-bearing
// one: `node scripts/check-doc-formula-expressions.mjs` is the exact string
// this card exists to stop printing, and it names a file that has never
// existed.
t('a packages/lint/scripts importer prints its REAL repo-relative path',
advisoryFor(lintGate).includes('`node packages/lint/scripts/check-doc-formula-expressions.mjs > '),
advisoryFor(lintGate));
t('⛔ and NEVER the `scripts/` basename guess, which names no file on disk',
!advisoryFor(lintGate).includes('node scripts/check-doc-formula-expressions.mjs'));

// (b) The 42 importers under `scripts/**` inherit this line verbatim, so
// the spelling is pinned WHOLE — command, log sink and the `echo` that
// captures the code before any pipe.
t('a scripts/** importer still prints `scripts/NAME.mjs`, spelling unchanged',
advisoryFor(rootGate).includes(
'`node scripts/check-ci-filter-parity.mjs > /tmp/check-ci-filter-parity.log 2>&1; echo "EXIT=$?"`'),
advisoryFor(rootGate));

// (c) The marker choice, as a paired measurement rather than an assertion.
const gitIsDirectoryWalk = (from) => {
let d = resolve(from);
for (;;) {
try {
if (statSync(join(d, '.git')).isDirectory()) return d;
} catch { /* absent here; keep walking */ }
const parent = dirname(d);
if (parent === d) return '';
d = parent;
}
};
t('the workspace-manifest walk finds the worktree root',
repoRootFrom(join(wt, 'packages', 'lint', 'scripts')) === wt);
t('NEGATIVE CONTROL: a `.git`-isDirectory walk finds NO root in a worktree shape',
gitIsDirectoryWalk(join(wt, 'packages', 'lint', 'scripts')) === '' && statSync(join(wt, '.git')).isFile());

// (d) No locatable root: absolute, which always runs. ⛔ Never a relative
// path invented against a root that was never found.
const orphanGate = join(dir, 'no-marker', 'scripts', 'check-orphan-fixture.mjs');
mkdirSync(dirname(orphanGate), { recursive: true });
t('an importer with no locatable root prints an ABSOLUTE path, always runnable',
importerCommandPath(pathToFileURL(orphanGate).href) === orphanGate,
importerCommandPath(pathToFileURL(orphanGate).href));
t('⛔ and never a relative path invented against a root that was not found',
!advisoryFor(orphanGate).includes('`node scripts/check-orphan-fixture.mjs'));

// (e) Triage's explicit boundary on this card: the HEADLINE gate name is a
// basename and is CORRECT as one. Only the command was wrong.
t('the headline still names the gate by BASENAME, never by path',
advisoryFor(lintGate).includes('\ncheck-doc-formula-expressions: PREREQUISITE NOT MET')
&& !advisoryFor(lintGate).includes('packages/lint/scripts/check-doc-formula-expressions: PREREQUISITE'),
advisoryFor(lintGate));

// (f) The log sink keeps the basename too — `/tmp/packages/lint/scripts/
// ….log` names directories that do not exist, so a blanket substitution
// would hand back a broken command one token to the right.
t('the /tmp log sink keeps the BASENAME — a repo-relative one names absent directories',
advisoryFor(lintGate).includes('> /tmp/check-doc-formula-expressions.log 2>&1')
&& !advisoryFor(lintGate).includes('/tmp/packages/lint'));
} finally {
rmSync(dir, { recursive: true, force: true });
}
Expand DownExpand Up@@ -738,6 +890,18 @@ export function selfTest() {
t('NEGATIVE CONTROL: the literal-exit pin can still fail', hardcodesExitCall(controlHardcodedExit));
t('NEGATIVE CONTROL: the literal-advisory pin can still fail', spellsALiteralCode(controlLiteralAdvisory));

// The same shape for the directory. The regression that costs something here
// is not a mistyped path: it is an author interpolating the gate NAME back
// into a hard-coded `scripts/` because the headline beside it does exactly
// that. It would read correct, stay green for the 42 gates under `scripts/`,
// and be wrong only for the three that are the whole point of this pin.
const hardcodesScriptsDir = (fn) => /`node scripts\//.test(fn.toString());
const controlHardcodedScriptsDir = () => ` \`node scripts/${'gate'}.mjs > /tmp/x.log\``;
t('the advisory INTERPOLATES the importer path rather than hard-coding `scripts/`',
!hardcodesScriptsDir(prerequisiteNotMetText));
t('NEGATIVE CONTROL: the hard-coded-directory pin can still fail',
hardcodesScriptsDir(controlHardcodedScriptsDir));

t('the refusal class is 3 — the code four sibling gates answer these words with',
EXIT_PREREQUISITE_NOT_MET === 3, String(EXIT_PREREQUISITE_NOT_MET));
t('the refusal class is distinct from a finding and from a pass',
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 167 additions & 3 deletions scripts/import-prerequisite.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -79,8 +79,8 @@
*/
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { dirname, join, relative, resolve, sep } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { WORKSPACE_SCOPE, workspaceBuildFix } from './cli-build-prerequisite.mjs';
import { isEntrypoint } from './invoked-as.mjs';

Expand DownExpand Up@@ -253,6 +253,70 @@ function isWholePackage(pkg, fromDir) {
return Boolean(dir) && entryPointOnDisk(dir).present === true;
}

/**
* The repo root at or above a directory: the nearest ancestor holding
* `pnpm-workspace.yaml`. '' when none does.
*
* ⚠️ The marker is the workspace manifest and NOT `.git`, which looks like the
* more obvious choice and is wrong for the exact checkout shape `CLAUDE.md`
* mandates. In a linked worktree — `git worktree add ../objectstack-<task>` —
* `.git` is a FILE containing a `gitdir:` pointer, not a directory (measured
* here: 70 bytes, ASCII). A walk testing `statSync('.git').isDirectory()`
* therefore steps straight PAST the worktree root, finds nothing above it, and
* reports no root at all — in the one tree every agent actually works in.
* `existsSync` on `.git` would survive that, but the workspace manifest is the
* marker this repo already publishes for "repo root" (AGENTS.md names
* `findUp(existsSync(join(dir, 'pnpm-workspace.yaml')))` as the spelling), so
* it is the one used here rather than a second convention.
*
* NEAREST wins, as node and pnpm resolve. The tree holds a second
* `pnpm-workspace.yaml`, under `packages/create-objectstack/src/templates/blank/`
* — a scaffold template, containing no gate and importing nothing, so no
* importer resolves through it. A "highest wins" walk would be the riskier rule:
* it can climb OUT of the repo when the checkout sits inside another workspace.
*/
export function repoRootFrom(dir) {
let d = resolve(dir);
for (;;) {
if (existsSync(join(d, 'pnpm-workspace.yaml'))) return d;
const parent = dirname(d);
if (parent === d) return '';
d = parent;
}
}

/**
* The importer spelled the way the reader can actually RUN it.
*
* The gate NAME is a basename and is correct as one (it is what the headline
* says, and what the gate is called). The COMMAND is not a name, it is a path,
* and interpolating the basename into a hard-coded `scripts/` directory was
* right for the 42 importers under `scripts/**` and wrong for the three under
* `packages/lint/scripts/**`: it printed `node scripts/check-doc-formula-
* expressions.mjs`, which does not exist. Copy-pasting it answered
* `Cannot find module` at exit 1 — so a banner whose whole purpose is to stop a
* reader misreading an exit code handed them a THIRD failure, wearing a
* finding's exit code, one level down from the defect this module removes.
*
* Falls back to the ABSOLUTE path when no root is found, never to the old
* basename guess. An absolute path always runs; a relative path invented
* against a root that was never located is the confident wrong answer this
* module exists to refuse.
*
* Emitted with POSIX separators: the result is a shell command, not a path for
* this process to open.
*/
export function importerCommandPath(importerUrl) {
const file = fileURLToPath(importerUrl);
const root = repoRootFrom(dirname(file));
if (!root) return file;
const rel = relative(root, file);
// A path that climbs out of the root is not repo-relative in any useful
// sense; print the absolute one rather than a `../..` chain.
if (!rel || rel.startsWith('..')) return file;
return rel.split(sep).join('/');
}

/**
* The package node says it could not find, read out of its own error text.
*
Expand DownExpand Up@@ -493,6 +557,13 @@ export function reportPrerequisiteNotMet(importerUrl, verdict, measures) {
*/
function prerequisiteNotMetText(importerUrl, verdict, measures) {
const gate = fileURLToPath(importerUrl).split('/').pop().replace(/\.mjs$/, '');
// The path to RUN and the name to CALL IT BY are two different strings, and
// only the first moves. ⛔ The `/tmp/${gate}.log` sink below keeps the
// BASENAME on purpose: a repo-relative path there would spell
// `/tmp/packages/lint/scripts/….log`, whose parent directories do not exist,
// so the redirect fails and the reader is handed a broken command again —
// the same defect, relocated one token to the right.
const command = importerCommandPath(importerUrl);
const subject = measures ? `whether ${measures}` : `what it gates`;
return (
`\n${gate}: PREREQUISITE NOT MET — ${verdict.headline}\n\n` +
Expand All@@ -502,7 +573,7 @@ function prerequisiteNotMetText(importerUrl, verdict, measures) {
` result says NOTHING about ${subject}. It is NOT a finding, and it is not\n` +
` evidence that anything in the tree is wrong.\n` +
` (Exit code ${EXIT_PREREQUISITE_NOT_MET}, distinct from a finding's ${EXIT_FINDINGS} — capture it BEFORE any pipe:\n` +
` \`node scripts/${gate}.mjs > /tmp/${gate}.log 2>&1; echo "EXIT=$?"\`.\n` +
` \`node ${command} > /tmp/${gate}.log 2>&1; echo "EXIT=$?"\`.\n` +
` Piped, \`$?\` is the LAST command's status, and \`head\`/\`tail\` essentially never fail — that\n` +
` is the false green, and no pipe shape repairs it. \`\${PIPESTATUS[0]}\`/\`pipefail\` do recover\n` +
` this gate's own code: \`| tail\` reads to EOF and forwards it, while \`| head -N\` closes the\n` +
Expand DownExpand Up@@ -682,6 +753,87 @@ export function selfTest() {
findPackageDir('whole-fixture', deep) === join(nm, 'whole-fixture'));
t('a package that is nowhere on the path is not found',
findPackageDir('totally-absent-fixture', deep) === '');

// ── the printed COMMAND: a path the reader can run, not a name ──────────
//
// A REAL tree again, for this module's standing reason: the derivation
// turns on files being on disk, and a model would agree with an
// implementation that never looked.
//
// The fixture is shaped like the checkout every agent actually works in —
// a LINKED WORKTREE, whose `.git` is a FILE holding a `gitdir:` pointer.
// That shape is the whole reason the marker is the workspace manifest, and
// the negative control below is what turns that from a preference into a
// measurement.
const wt = join(dir, 'objectstack-issue-fixture');
mkdirSync(join(wt, 'scripts'), { recursive: true });
mkdirSync(join(wt, 'packages', 'lint', 'scripts'), { recursive: true });
writeFileSync(join(wt, 'pnpm-workspace.yaml'), "packages:\n - 'packages/*'\n");
writeFileSync(join(wt, '.git'), `gitdir: ${join(dir, 'common', 'worktrees', 'wt')}\n`);

const advisoryFor = (abs) =>
prerequisiteNotMetText(pathToFileURL(abs).href, { headline: 'h', detail: ['d'], fix: 'f' }, undefined);
const lintGate = join(wt, 'packages', 'lint', 'scripts', 'check-doc-formula-expressions.mjs');
const rootGate = join(wt, 'scripts', 'check-ci-filter-parity.mjs');

// (a) THE DEFECT, in both directions. The negative is the load-bearing
// one: `node scripts/check-doc-formula-expressions.mjs` is the exact string
// this card exists to stop printing, and it names a file that has never
// existed.
t('a packages/lint/scripts importer prints its REAL repo-relative path',
advisoryFor(lintGate).includes('`node packages/lint/scripts/check-doc-formula-expressions.mjs > '),
advisoryFor(lintGate));
t('⛔ and NEVER the `scripts/` basename guess, which names no file on disk',
!advisoryFor(lintGate).includes('node scripts/check-doc-formula-expressions.mjs'));

// (b) The 42 importers under `scripts/**` inherit this line verbatim, so
// the spelling is pinned WHOLE — command, log sink and the `echo` that
// captures the code before any pipe.
t('a scripts/** importer still prints `scripts/NAME.mjs`, spelling unchanged',
advisoryFor(rootGate).includes(
'`node scripts/check-ci-filter-parity.mjs > /tmp/check-ci-filter-parity.log 2>&1; echo "EXIT=$?"`'),
advisoryFor(rootGate));

// (c) The marker choice, as a paired measurement rather than an assertion.
const gitIsDirectoryWalk = (from) => {
let d = resolve(from);
for (;;) {
try {
if (statSync(join(d, '.git')).isDirectory()) return d;
} catch { /* absent here; keep walking */ }
const parent = dirname(d);
if (parent === d) return '';
d = parent;
}
};
t('the workspace-manifest walk finds the worktree root',
repoRootFrom(join(wt, 'packages', 'lint', 'scripts')) === wt);
t('NEGATIVE CONTROL: a `.git`-isDirectory walk finds NO root in a worktree shape',
gitIsDirectoryWalk(join(wt, 'packages', 'lint', 'scripts')) === '' && statSync(join(wt, '.git')).isFile());

// (d) No locatable root: absolute, which always runs. ⛔ Never a relative
// path invented against a root that was never found.
const orphanGate = join(dir, 'no-marker', 'scripts', 'check-orphan-fixture.mjs');
mkdirSync(dirname(orphanGate), { recursive: true });
t('an importer with no locatable root prints an ABSOLUTE path, always runnable',
importerCommandPath(pathToFileURL(orphanGate).href) === orphanGate,
importerCommandPath(pathToFileURL(orphanGate).href));
t('⛔ and never a relative path invented against a root that was not found',
!advisoryFor(orphanGate).includes('`node scripts/check-orphan-fixture.mjs'));

// (e) Triage's explicit boundary on this card: the HEADLINE gate name is a
// basename and is CORRECT as one. Only the command was wrong.
t('the headline still names the gate by BASENAME, never by path',
advisoryFor(lintGate).includes('\ncheck-doc-formula-expressions: PREREQUISITE NOT MET')
&& !advisoryFor(lintGate).includes('packages/lint/scripts/check-doc-formula-expressions: PREREQUISITE'),
advisoryFor(lintGate));

// (f) The log sink keeps the basename too — `/tmp/packages/lint/scripts/
// ….log` names directories that do not exist, so a blanket substitution
// would hand back a broken command one token to the right.
t('the /tmp log sink keeps the BASENAME — a repo-relative one names absent directories',
advisoryFor(lintGate).includes('> /tmp/check-doc-formula-expressions.log 2>&1')
&& !advisoryFor(lintGate).includes('/tmp/packages/lint'));
} finally {
rmSync(dir, { recursive: true, force: true });
}
Expand DownExpand Up@@ -738,6 +890,18 @@ export function selfTest() {
t('NEGATIVE CONTROL: the literal-exit pin can still fail', hardcodesExitCall(controlHardcodedExit));
t('NEGATIVE CONTROL: the literal-advisory pin can still fail', spellsALiteralCode(controlLiteralAdvisory));

// The same shape for the directory. The regression that costs something here
// is not a mistyped path: it is an author interpolating the gate NAME back
// into a hard-coded `scripts/` because the headline beside it does exactly
// that. It would read correct, stay green for the 42 gates under `scripts/`,
// and be wrong only for the three that are the whole point of this pin.
const hardcodesScriptsDir = (fn) => /`node scripts\//.test(fn.toString());
const controlHardcodedScriptsDir = () => ` \`node scripts/${'gate'}.mjs > /tmp/x.log\``;
t('the advisory INTERPOLATES the importer path rather than hard-coding `scripts/`',
!hardcodesScriptsDir(prerequisiteNotMetText));
t('NEGATIVE CONTROL: the hard-coded-directory pin can still fail',
hardcodesScriptsDir(controlHardcodedScriptsDir));

t('the refusal class is 3 — the code four sibling gates answer these words with',
EXIT_PREREQUISITE_NOT_MET === 3, String(EXIT_PREREQUISITE_NOT_MET));
t('the refusal class is distinct from a finding and from a pass',
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 167 additions & 3 deletions scripts/import-prerequisite.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -79,8 +79,8 @@
*/
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { dirname, join, relative, resolve, sep } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { WORKSPACE_SCOPE, workspaceBuildFix } from './cli-build-prerequisite.mjs';
import { isEntrypoint } from './invoked-as.mjs';

Expand DownExpand Up@@ -253,6 +253,70 @@ function isWholePackage(pkg, fromDir) {
return Boolean(dir) && entryPointOnDisk(dir).present === true;
}

/**
* The repo root at or above a directory: the nearest ancestor holding
* `pnpm-workspace.yaml`. '' when none does.
*
* ⚠️ The marker is the workspace manifest and NOT `.git`, which looks like the
* more obvious choice and is wrong for the exact checkout shape `CLAUDE.md`
* mandates. In a linked worktree — `git worktree add ../objectstack-<task>` —
* `.git` is a FILE containing a `gitdir:` pointer, not a directory (measured
* here: 70 bytes, ASCII). A walk testing `statSync('.git').isDirectory()`
* therefore steps straight PAST the worktree root, finds nothing above it, and
* reports no root at all — in the one tree every agent actually works in.
* `existsSync` on `.git` would survive that, but the workspace manifest is the
* marker this repo already publishes for "repo root" (AGENTS.md names
* `findUp(existsSync(join(dir, 'pnpm-workspace.yaml')))` as the spelling), so
* it is the one used here rather than a second convention.
*
* NEAREST wins, as node and pnpm resolve. The tree holds a second
* `pnpm-workspace.yaml`, under `packages/create-objectstack/src/templates/blank/`
* — a scaffold template, containing no gate and importing nothing, so no
* importer resolves through it. A "highest wins" walk would be the riskier rule:
* it can climb OUT of the repo when the checkout sits inside another workspace.
*/
export function repoRootFrom(dir) {
let d = resolve(dir);
for (;;) {
if (existsSync(join(d, 'pnpm-workspace.yaml'))) return d;
const parent = dirname(d);
if (parent === d) return '';
d = parent;
}
}

/**
* The importer spelled the way the reader can actually RUN it.
*
* The gate NAME is a basename and is correct as one (it is what the headline
* says, and what the gate is called). The COMMAND is not a name, it is a path,
* and interpolating the basename into a hard-coded `scripts/` directory was
* right for the 42 importers under `scripts/**` and wrong for the three under
* `packages/lint/scripts/**`: it printed `node scripts/check-doc-formula-
* expressions.mjs`, which does not exist. Copy-pasting it answered
* `Cannot find module` at exit 1 — so a banner whose whole purpose is to stop a
* reader misreading an exit code handed them a THIRD failure, wearing a
* finding's exit code, one level down from the defect this module removes.
*
* Falls back to the ABSOLUTE path when no root is found, never to the old
* basename guess. An absolute path always runs; a relative path invented
* against a root that was never located is the confident wrong answer this
* module exists to refuse.
*
* Emitted with POSIX separators: the result is a shell command, not a path for
* this process to open.
*/
export function importerCommandPath(importerUrl) {
const file = fileURLToPath(importerUrl);
const root = repoRootFrom(dirname(file));
if (!root) return file;
const rel = relative(root, file);
// A path that climbs out of the root is not repo-relative in any useful
// sense; print the absolute one rather than a `../..` chain.
if (!rel || rel.startsWith('..')) return file;
return rel.split(sep).join('/');
}

/**
* The package node says it could not find, read out of its own error text.
*
Expand DownExpand Up@@ -493,6 +557,13 @@ export function reportPrerequisiteNotMet(importerUrl, verdict, measures) {
*/
function prerequisiteNotMetText(importerUrl, verdict, measures) {
const gate = fileURLToPath(importerUrl).split('/').pop().replace(/\.mjs$/, '');
// The path to RUN and the name to CALL IT BY are two different strings, and
// only the first moves. ⛔ The `/tmp/${gate}.log` sink below keeps the
// BASENAME on purpose: a repo-relative path there would spell
// `/tmp/packages/lint/scripts/….log`, whose parent directories do not exist,
// so the redirect fails and the reader is handed a broken command again —
// the same defect, relocated one token to the right.
const command = importerCommandPath(importerUrl);
const subject = measures ? `whether ${measures}` : `what it gates`;
return (
`\n${gate}: PREREQUISITE NOT MET — ${verdict.headline}\n\n` +
Expand All@@ -502,7 +573,7 @@ function prerequisiteNotMetText(importerUrl, verdict, measures) {
` result says NOTHING about ${subject}. It is NOT a finding, and it is not\n` +
` evidence that anything in the tree is wrong.\n` +
` (Exit code ${EXIT_PREREQUISITE_NOT_MET}, distinct from a finding's ${EXIT_FINDINGS} — capture it BEFORE any pipe:\n` +
` \`node scripts/${gate}.mjs > /tmp/${gate}.log 2>&1; echo "EXIT=$?"\`.\n` +
` \`node ${command} > /tmp/${gate}.log 2>&1; echo "EXIT=$?"\`.\n` +
` Piped, \`$?\` is the LAST command's status, and \`head\`/\`tail\` essentially never fail — that\n` +
` is the false green, and no pipe shape repairs it. \`\${PIPESTATUS[0]}\`/\`pipefail\` do recover\n` +
` this gate's own code: \`| tail\` reads to EOF and forwards it, while \`| head -N\` closes the\n` +
Expand DownExpand Up@@ -682,6 +753,87 @@ export function selfTest() {
findPackageDir('whole-fixture', deep) === join(nm, 'whole-fixture'));
t('a package that is nowhere on the path is not found',
findPackageDir('totally-absent-fixture', deep) === '');

// ── the printed COMMAND: a path the reader can run, not a name ──────────
//
// A REAL tree again, for this module's standing reason: the derivation
// turns on files being on disk, and a model would agree with an
// implementation that never looked.
//
// The fixture is shaped like the checkout every agent actually works in —
// a LINKED WORKTREE, whose `.git` is a FILE holding a `gitdir:` pointer.
// That shape is the whole reason the marker is the workspace manifest, and
// the negative control below is what turns that from a preference into a
// measurement.
const wt = join(dir, 'objectstack-issue-fixture');
mkdirSync(join(wt, 'scripts'), { recursive: true });
mkdirSync(join(wt, 'packages', 'lint', 'scripts'), { recursive: true });
writeFileSync(join(wt, 'pnpm-workspace.yaml'), "packages:\n - 'packages/*'\n");
writeFileSync(join(wt, '.git'), `gitdir: ${join(dir, 'common', 'worktrees', 'wt')}\n`);

const advisoryFor = (abs) =>
prerequisiteNotMetText(pathToFileURL(abs).href, { headline: 'h', detail: ['d'], fix: 'f' }, undefined);
const lintGate = join(wt, 'packages', 'lint', 'scripts', 'check-doc-formula-expressions.mjs');
const rootGate = join(wt, 'scripts', 'check-ci-filter-parity.mjs');

// (a) THE DEFECT, in both directions. The negative is the load-bearing
// one: `node scripts/check-doc-formula-expressions.mjs` is the exact string
// this card exists to stop printing, and it names a file that has never
// existed.
t('a packages/lint/scripts importer prints its REAL repo-relative path',
advisoryFor(lintGate).includes('`node packages/lint/scripts/check-doc-formula-expressions.mjs > '),
advisoryFor(lintGate));
t('⛔ and NEVER the `scripts/` basename guess, which names no file on disk',
!advisoryFor(lintGate).includes('node scripts/check-doc-formula-expressions.mjs'));

// (b) The 42 importers under `scripts/**` inherit this line verbatim, so
// the spelling is pinned WHOLE — command, log sink and the `echo` that
// captures the code before any pipe.
t('a scripts/** importer still prints `scripts/NAME.mjs`, spelling unchanged',
advisoryFor(rootGate).includes(
'`node scripts/check-ci-filter-parity.mjs > /tmp/check-ci-filter-parity.log 2>&1; echo "EXIT=$?"`'),
advisoryFor(rootGate));

// (c) The marker choice, as a paired measurement rather than an assertion.
const gitIsDirectoryWalk = (from) => {
let d = resolve(from);
for (;;) {
try {
if (statSync(join(d, '.git')).isDirectory()) return d;
} catch { /* absent here; keep walking */ }
const parent = dirname(d);
if (parent === d) return '';
d = parent;
}
};
t('the workspace-manifest walk finds the worktree root',
repoRootFrom(join(wt, 'packages', 'lint', 'scripts')) === wt);
t('NEGATIVE CONTROL: a `.git`-isDirectory walk finds NO root in a worktree shape',
gitIsDirectoryWalk(join(wt, 'packages', 'lint', 'scripts')) === '' && statSync(join(wt, '.git')).isFile());

// (d) No locatable root: absolute, which always runs. ⛔ Never a relative
// path invented against a root that was never found.
const orphanGate = join(dir, 'no-marker', 'scripts', 'check-orphan-fixture.mjs');
mkdirSync(dirname(orphanGate), { recursive: true });
t('an importer with no locatable root prints an ABSOLUTE path, always runnable',
importerCommandPath(pathToFileURL(orphanGate).href) === orphanGate,
importerCommandPath(pathToFileURL(orphanGate).href));
t('⛔ and never a relative path invented against a root that was not found',
!advisoryFor(orphanGate).includes('`node scripts/check-orphan-fixture.mjs'));

// (e) Triage's explicit boundary on this card: the HEADLINE gate name is a
// basename and is CORRECT as one. Only the command was wrong.
t('the headline still names the gate by BASENAME, never by path',
advisoryFor(lintGate).includes('\ncheck-doc-formula-expressions: PREREQUISITE NOT MET')
&& !advisoryFor(lintGate).includes('packages/lint/scripts/check-doc-formula-expressions: PREREQUISITE'),
advisoryFor(lintGate));

// (f) The log sink keeps the basename too — `/tmp/packages/lint/scripts/
// ….log` names directories that do not exist, so a blanket substitution
// would hand back a broken command one token to the right.
t('the /tmp log sink keeps the BASENAME — a repo-relative one names absent directories',
advisoryFor(lintGate).includes('> /tmp/check-doc-formula-expressions.log 2>&1')
&& !advisoryFor(lintGate).includes('/tmp/packages/lint'));
} finally {
rmSync(dir, { recursive: true, force: true });
}
Expand DownExpand Up@@ -738,6 +890,18 @@ export function selfTest() {
t('NEGATIVE CONTROL: the literal-exit pin can still fail', hardcodesExitCall(controlHardcodedExit));
t('NEGATIVE CONTROL: the literal-advisory pin can still fail', spellsALiteralCode(controlLiteralAdvisory));

// The same shape for the directory. The regression that costs something here
// is not a mistyped path: it is an author interpolating the gate NAME back
// into a hard-coded `scripts/` because the headline beside it does exactly
// that. It would read correct, stay green for the 42 gates under `scripts/`,
// and be wrong only for the three that are the whole point of this pin.
const hardcodesScriptsDir = (fn) => /`node scripts\//.test(fn.toString());
const controlHardcodedScriptsDir = () => ` \`node scripts/${'gate'}.mjs > /tmp/x.log\``;
t('the advisory INTERPOLATES the importer path rather than hard-coding `scripts/`',
!hardcodesScriptsDir(prerequisiteNotMetText));
t('NEGATIVE CONTROL: the hard-coded-directory pin can still fail',
hardcodesScriptsDir(controlHardcodedScriptsDir));

t('the refusal class is 3 — the code four sibling gates answer these words with',
EXIT_PREREQUISITE_NOT_MET === 3, String(EXIT_PREREQUISITE_NOT_MET));
t('the refusal class is distinct from a finding and from a pass',
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 167 additions & 3 deletions scripts/import-prerequisite.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -79,8 +79,8 @@
*/
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { dirname, join, relative, resolve, sep } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { WORKSPACE_SCOPE, workspaceBuildFix } from './cli-build-prerequisite.mjs';
import { isEntrypoint } from './invoked-as.mjs';

Expand DownExpand Up@@ -253,6 +253,70 @@ function isWholePackage(pkg, fromDir) {
return Boolean(dir) && entryPointOnDisk(dir).present === true;
}

/**
* The repo root at or above a directory: the nearest ancestor holding
* `pnpm-workspace.yaml`. '' when none does.
*
* ⚠️ The marker is the workspace manifest and NOT `.git`, which looks like the
* more obvious choice and is wrong for the exact checkout shape `CLAUDE.md`
* mandates. In a linked worktree — `git worktree add ../objectstack-<task>` —
* `.git` is a FILE containing a `gitdir:` pointer, not a directory (measured
* here: 70 bytes, ASCII). A walk testing `statSync('.git').isDirectory()`
* therefore steps straight PAST the worktree root, finds nothing above it, and
* reports no root at all — in the one tree every agent actually works in.
* `existsSync` on `.git` would survive that, but the workspace manifest is the
* marker this repo already publishes for "repo root" (AGENTS.md names
* `findUp(existsSync(join(dir, 'pnpm-workspace.yaml')))` as the spelling), so
* it is the one used here rather than a second convention.
*
* NEAREST wins, as node and pnpm resolve. The tree holds a second
* `pnpm-workspace.yaml`, under `packages/create-objectstack/src/templates/blank/`
* — a scaffold template, containing no gate and importing nothing, so no
* importer resolves through it. A "highest wins" walk would be the riskier rule:
* it can climb OUT of the repo when the checkout sits inside another workspace.
*/
export function repoRootFrom(dir) {
let d = resolve(dir);
for (;;) {
if (existsSync(join(d, 'pnpm-workspace.yaml'))) return d;
const parent = dirname(d);
if (parent === d) return '';
d = parent;
}
}

/**
* The importer spelled the way the reader can actually RUN it.
*
* The gate NAME is a basename and is correct as one (it is what the headline
* says, and what the gate is called). The COMMAND is not a name, it is a path,
* and interpolating the basename into a hard-coded `scripts/` directory was
* right for the 42 importers under `scripts/**` and wrong for the three under
* `packages/lint/scripts/**`: it printed `node scripts/check-doc-formula-
* expressions.mjs`, which does not exist. Copy-pasting it answered
* `Cannot find module` at exit 1 — so a banner whose whole purpose is to stop a
* reader misreading an exit code handed them a THIRD failure, wearing a
* finding's exit code, one level down from the defect this module removes.
*
* Falls back to the ABSOLUTE path when no root is found, never to the old
* basename guess. An absolute path always runs; a relative path invented
* against a root that was never located is the confident wrong answer this
* module exists to refuse.
*
* Emitted with POSIX separators: the result is a shell command, not a path for
* this process to open.
*/
export function importerCommandPath(importerUrl) {
const file = fileURLToPath(importerUrl);
const root = repoRootFrom(dirname(file));
if (!root) return file;
const rel = relative(root, file);
// A path that climbs out of the root is not repo-relative in any useful
// sense; print the absolute one rather than a `../..` chain.
if (!rel || rel.startsWith('..')) return file;
return rel.split(sep).join('/');
}

/**
* The package node says it could not find, read out of its own error text.
*
Expand DownExpand Up@@ -493,6 +557,13 @@ export function reportPrerequisiteNotMet(importerUrl, verdict, measures) {
*/
function prerequisiteNotMetText(importerUrl, verdict, measures) {
const gate = fileURLToPath(importerUrl).split('/').pop().replace(/\.mjs$/, '');
// The path to RUN and the name to CALL IT BY are two different strings, and
// only the first moves. ⛔ The `/tmp/${gate}.log` sink below keeps the
// BASENAME on purpose: a repo-relative path there would spell
// `/tmp/packages/lint/scripts/….log`, whose parent directories do not exist,
// so the redirect fails and the reader is handed a broken command again —
// the same defect, relocated one token to the right.
const command = importerCommandPath(importerUrl);
const subject = measures ? `whether ${measures}` : `what it gates`;
return (
`\n${gate}: PREREQUISITE NOT MET — ${verdict.headline}\n\n` +
Expand All@@ -502,7 +573,7 @@ function prerequisiteNotMetText(importerUrl, verdict, measures) {
` result says NOTHING about ${subject}. It is NOT a finding, and it is not\n` +
` evidence that anything in the tree is wrong.\n` +
` (Exit code ${EXIT_PREREQUISITE_NOT_MET}, distinct from a finding's ${EXIT_FINDINGS} — capture it BEFORE any pipe:\n` +
` \`node scripts/${gate}.mjs > /tmp/${gate}.log 2>&1; echo "EXIT=$?"\`.\n` +
` \`node ${command} > /tmp/${gate}.log 2>&1; echo "EXIT=$?"\`.\n` +
` Piped, \`$?\` is the LAST command's status, and \`head\`/\`tail\` essentially never fail — that\n` +
` is the false green, and no pipe shape repairs it. \`\${PIPESTATUS[0]}\`/\`pipefail\` do recover\n` +
` this gate's own code: \`| tail\` reads to EOF and forwards it, while \`| head -N\` closes the\n` +
Expand DownExpand Up@@ -682,6 +753,87 @@ export function selfTest() {
findPackageDir('whole-fixture', deep) === join(nm, 'whole-fixture'));
t('a package that is nowhere on the path is not found',
findPackageDir('totally-absent-fixture', deep) === '');

// ── the printed COMMAND: a path the reader can run, not a name ──────────
//
// A REAL tree again, for this module's standing reason: the derivation
// turns on files being on disk, and a model would agree with an
// implementation that never looked.
//
// The fixture is shaped like the checkout every agent actually works in —
// a LINKED WORKTREE, whose `.git` is a FILE holding a `gitdir:` pointer.
// That shape is the whole reason the marker is the workspace manifest, and
// the negative control below is what turns that from a preference into a
// measurement.
const wt = join(dir, 'objectstack-issue-fixture');
mkdirSync(join(wt, 'scripts'), { recursive: true });
mkdirSync(join(wt, 'packages', 'lint', 'scripts'), { recursive: true });
writeFileSync(join(wt, 'pnpm-workspace.yaml'), "packages:\n - 'packages/*'\n");
writeFileSync(join(wt, '.git'), `gitdir: ${join(dir, 'common', 'worktrees', 'wt')}\n`);

const advisoryFor = (abs) =>
prerequisiteNotMetText(pathToFileURL(abs).href, { headline: 'h', detail: ['d'], fix: 'f' }, undefined);
const lintGate = join(wt, 'packages', 'lint', 'scripts', 'check-doc-formula-expressions.mjs');
const rootGate = join(wt, 'scripts', 'check-ci-filter-parity.mjs');

// (a) THE DEFECT, in both directions. The negative is the load-bearing
// one: `node scripts/check-doc-formula-expressions.mjs` is the exact string
// this card exists to stop printing, and it names a file that has never
// existed.
t('a packages/lint/scripts importer prints its REAL repo-relative path',
advisoryFor(lintGate).includes('`node packages/lint/scripts/check-doc-formula-expressions.mjs > '),
advisoryFor(lintGate));
t('⛔ and NEVER the `scripts/` basename guess, which names no file on disk',
!advisoryFor(lintGate).includes('node scripts/check-doc-formula-expressions.mjs'));

// (b) The 42 importers under `scripts/**` inherit this line verbatim, so
// the spelling is pinned WHOLE — command, log sink and the `echo` that
// captures the code before any pipe.
t('a scripts/** importer still prints `scripts/NAME.mjs`, spelling unchanged',
advisoryFor(rootGate).includes(
'`node scripts/check-ci-filter-parity.mjs > /tmp/check-ci-filter-parity.log 2>&1; echo "EXIT=$?"`'),
advisoryFor(rootGate));

// (c) The marker choice, as a paired measurement rather than an assertion.
const gitIsDirectoryWalk = (from) => {
let d = resolve(from);
for (;;) {
try {
if (statSync(join(d, '.git')).isDirectory()) return d;
} catch { /* absent here; keep walking */ }
const parent = dirname(d);
if (parent === d) return '';
d = parent;
}
};
t('the workspace-manifest walk finds the worktree root',
repoRootFrom(join(wt, 'packages', 'lint', 'scripts')) === wt);
t('NEGATIVE CONTROL: a `.git`-isDirectory walk finds NO root in a worktree shape',
gitIsDirectoryWalk(join(wt, 'packages', 'lint', 'scripts')) === '' && statSync(join(wt, '.git')).isFile());

// (d) No locatable root: absolute, which always runs. ⛔ Never a relative
// path invented against a root that was never found.
const orphanGate = join(dir, 'no-marker', 'scripts', 'check-orphan-fixture.mjs');
mkdirSync(dirname(orphanGate), { recursive: true });
t('an importer with no locatable root prints an ABSOLUTE path, always runnable',
importerCommandPath(pathToFileURL(orphanGate).href) === orphanGate,
importerCommandPath(pathToFileURL(orphanGate).href));
t('⛔ and never a relative path invented against a root that was not found',
!advisoryFor(orphanGate).includes('`node scripts/check-orphan-fixture.mjs'));

// (e) Triage's explicit boundary on this card: the HEADLINE gate name is a
// basename and is CORRECT as one. Only the command was wrong.
t('the headline still names the gate by BASENAME, never by path',
advisoryFor(lintGate).includes('\ncheck-doc-formula-expressions: PREREQUISITE NOT MET')
&& !advisoryFor(lintGate).includes('packages/lint/scripts/check-doc-formula-expressions: PREREQUISITE'),
advisoryFor(lintGate));

// (f) The log sink keeps the basename too — `/tmp/packages/lint/scripts/
// ….log` names directories that do not exist, so a blanket substitution
// would hand back a broken command one token to the right.
t('the /tmp log sink keeps the BASENAME — a repo-relative one names absent directories',
advisoryFor(lintGate).includes('> /tmp/check-doc-formula-expressions.log 2>&1')
&& !advisoryFor(lintGate).includes('/tmp/packages/lint'));
} finally {
rmSync(dir, { recursive: true, force: true });
}
Expand DownExpand Up@@ -738,6 +890,18 @@ export function selfTest() {
t('NEGATIVE CONTROL: the literal-exit pin can still fail', hardcodesExitCall(controlHardcodedExit));
t('NEGATIVE CONTROL: the literal-advisory pin can still fail', spellsALiteralCode(controlLiteralAdvisory));

// The same shape for the directory. The regression that costs something here
// is not a mistyped path: it is an author interpolating the gate NAME back
// into a hard-coded `scripts/` because the headline beside it does exactly
// that. It would read correct, stay green for the 42 gates under `scripts/`,
// and be wrong only for the three that are the whole point of this pin.
const hardcodesScriptsDir = (fn) => /`node scripts\//.test(fn.toString());
const controlHardcodedScriptsDir = () => ` \`node scripts/${'gate'}.mjs > /tmp/x.log\``;
t('the advisory INTERPOLATES the importer path rather than hard-coding `scripts/`',
!hardcodesScriptsDir(prerequisiteNotMetText));
t('NEGATIVE CONTROL: the hard-coded-directory pin can still fail',
hardcodesScriptsDir(controlHardcodedScriptsDir));

t('the refusal class is 3 — the code four sibling gates answer these words with',
EXIT_PREREQUISITE_NOT_MET === 3, String(EXIT_PREREQUISITE_NOT_MET));
t('the refusal class is distinct from a finding and from a pass',
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 167 additions & 3 deletions scripts/import-prerequisite.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -79,8 +79,8 @@
*/
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { dirname, join, relative, resolve, sep } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { WORKSPACE_SCOPE, workspaceBuildFix } from './cli-build-prerequisite.mjs';
import { isEntrypoint } from './invoked-as.mjs';

Expand DownExpand Up@@ -253,6 +253,70 @@ function isWholePackage(pkg, fromDir) {
return Boolean(dir) && entryPointOnDisk(dir).present === true;
}

/**
* The repo root at or above a directory: the nearest ancestor holding
* `pnpm-workspace.yaml`. '' when none does.
*
* ⚠️ The marker is the workspace manifest and NOT `.git`, which looks like the
* more obvious choice and is wrong for the exact checkout shape `CLAUDE.md`
* mandates. In a linked worktree — `git worktree add ../objectstack-<task>` —
* `.git` is a FILE containing a `gitdir:` pointer, not a directory (measured
* here: 70 bytes, ASCII). A walk testing `statSync('.git').isDirectory()`
* therefore steps straight PAST the worktree root, finds nothing above it, and
* reports no root at all — in the one tree every agent actually works in.
* `existsSync` on `.git` would survive that, but the workspace manifest is the
* marker this repo already publishes for "repo root" (AGENTS.md names
* `findUp(existsSync(join(dir, 'pnpm-workspace.yaml')))` as the spelling), so
* it is the one used here rather than a second convention.
*
* NEAREST wins, as node and pnpm resolve. The tree holds a second
* `pnpm-workspace.yaml`, under `packages/create-objectstack/src/templates/blank/`
* — a scaffold template, containing no gate and importing nothing, so no
* importer resolves through it. A "highest wins" walk would be the riskier rule:
* it can climb OUT of the repo when the checkout sits inside another workspace.
*/
export function repoRootFrom(dir) {
let d = resolve(dir);
for (;;) {
if (existsSync(join(d, 'pnpm-workspace.yaml'))) return d;
const parent = dirname(d);
if (parent === d) return '';
d = parent;
}
}

/**
* The importer spelled the way the reader can actually RUN it.
*
* The gate NAME is a basename and is correct as one (it is what the headline
* says, and what the gate is called). The COMMAND is not a name, it is a path,
* and interpolating the basename into a hard-coded `scripts/` directory was
* right for the 42 importers under `scripts/**` and wrong for the three under
* `packages/lint/scripts/**`: it printed `node scripts/check-doc-formula-
* expressions.mjs`, which does not exist. Copy-pasting it answered
* `Cannot find module` at exit 1 — so a banner whose whole purpose is to stop a
* reader misreading an exit code handed them a THIRD failure, wearing a
* finding's exit code, one level down from the defect this module removes.
*
* Falls back to the ABSOLUTE path when no root is found, never to the old
* basename guess. An absolute path always runs; a relative path invented
* against a root that was never located is the confident wrong answer this
* module exists to refuse.
*
* Emitted with POSIX separators: the result is a shell command, not a path for
* this process to open.
*/
export function importerCommandPath(importerUrl) {
const file = fileURLToPath(importerUrl);
const root = repoRootFrom(dirname(file));
if (!root) return file;
const rel = relative(root, file);
// A path that climbs out of the root is not repo-relative in any useful
// sense; print the absolute one rather than a `../..` chain.
if (!rel || rel.startsWith('..')) return file;
return rel.split(sep).join('/');
}

/**
* The package node says it could not find, read out of its own error text.
*
Expand DownExpand Up@@ -493,6 +557,13 @@ export function reportPrerequisiteNotMet(importerUrl, verdict, measures) {
*/
function prerequisiteNotMetText(importerUrl, verdict, measures) {
const gate = fileURLToPath(importerUrl).split('/').pop().replace(/\.mjs$/, '');
// The path to RUN and the name to CALL IT BY are two different strings, and
// only the first moves. ⛔ The `/tmp/${gate}.log` sink below keeps the
// BASENAME on purpose: a repo-relative path there would spell
// `/tmp/packages/lint/scripts/….log`, whose parent directories do not exist,
// so the redirect fails and the reader is handed a broken command again —
// the same defect, relocated one token to the right.
const command = importerCommandPath(importerUrl);
const subject = measures ? `whether ${measures}` : `what it gates`;
return (
`\n${gate}: PREREQUISITE NOT MET — ${verdict.headline}\n\n` +
Expand All@@ -502,7 +573,7 @@ function prerequisiteNotMetText(importerUrl, verdict, measures) {
` result says NOTHING about ${subject}. It is NOT a finding, and it is not\n` +
` evidence that anything in the tree is wrong.\n` +
` (Exit code ${EXIT_PREREQUISITE_NOT_MET}, distinct from a finding's ${EXIT_FINDINGS} — capture it BEFORE any pipe:\n` +
` \`node scripts/${gate}.mjs > /tmp/${gate}.log 2>&1; echo "EXIT=$?"\`.\n` +
` \`node ${command} > /tmp/${gate}.log 2>&1; echo "EXIT=$?"\`.\n` +
` Piped, \`$?\` is the LAST command's status, and \`head\`/\`tail\` essentially never fail — that\n` +
` is the false green, and no pipe shape repairs it. \`\${PIPESTATUS[0]}\`/\`pipefail\` do recover\n` +
` this gate's own code: \`| tail\` reads to EOF and forwards it, while \`| head -N\` closes the\n` +
Expand DownExpand Up@@ -682,6 +753,87 @@ export function selfTest() {
findPackageDir('whole-fixture', deep) === join(nm, 'whole-fixture'));
t('a package that is nowhere on the path is not found',
findPackageDir('totally-absent-fixture', deep) === '');

// ── the printed COMMAND: a path the reader can run, not a name ──────────
//
// A REAL tree again, for this module's standing reason: the derivation
// turns on files being on disk, and a model would agree with an
// implementation that never looked.
//
// The fixture is shaped like the checkout every agent actually works in —
// a LINKED WORKTREE, whose `.git` is a FILE holding a `gitdir:` pointer.
// That shape is the whole reason the marker is the workspace manifest, and
// the negative control below is what turns that from a preference into a
// measurement.
const wt = join(dir, 'objectstack-issue-fixture');
mkdirSync(join(wt, 'scripts'), { recursive: true });
mkdirSync(join(wt, 'packages', 'lint', 'scripts'), { recursive: true });
writeFileSync(join(wt, 'pnpm-workspace.yaml'), "packages:\n - 'packages/*'\n");
writeFileSync(join(wt, '.git'), `gitdir: ${join(dir, 'common', 'worktrees', 'wt')}\n`);

const advisoryFor = (abs) =>
prerequisiteNotMetText(pathToFileURL(abs).href, { headline: 'h', detail: ['d'], fix: 'f' }, undefined);
const lintGate = join(wt, 'packages', 'lint', 'scripts', 'check-doc-formula-expressions.mjs');
const rootGate = join(wt, 'scripts', 'check-ci-filter-parity.mjs');

// (a) THE DEFECT, in both directions. The negative is the load-bearing
// one: `node scripts/check-doc-formula-expressions.mjs` is the exact string
// this card exists to stop printing, and it names a file that has never
// existed.
t('a packages/lint/scripts importer prints its REAL repo-relative path',
advisoryFor(lintGate).includes('`node packages/lint/scripts/check-doc-formula-expressions.mjs > '),
advisoryFor(lintGate));
t('⛔ and NEVER the `scripts/` basename guess, which names no file on disk',
!advisoryFor(lintGate).includes('node scripts/check-doc-formula-expressions.mjs'));

// (b) The 42 importers under `scripts/**` inherit this line verbatim, so
// the spelling is pinned WHOLE — command, log sink and the `echo` that
// captures the code before any pipe.
t('a scripts/** importer still prints `scripts/NAME.mjs`, spelling unchanged',
advisoryFor(rootGate).includes(
'`node scripts/check-ci-filter-parity.mjs > /tmp/check-ci-filter-parity.log 2>&1; echo "EXIT=$?"`'),
advisoryFor(rootGate));

// (c) The marker choice, as a paired measurement rather than an assertion.
const gitIsDirectoryWalk = (from) => {
let d = resolve(from);
for (;;) {
try {
if (statSync(join(d, '.git')).isDirectory()) return d;
} catch { /* absent here; keep walking */ }
const parent = dirname(d);
if (parent === d) return '';
d = parent;
}
};
t('the workspace-manifest walk finds the worktree root',
repoRootFrom(join(wt, 'packages', 'lint', 'scripts')) === wt);
t('NEGATIVE CONTROL: a `.git`-isDirectory walk finds NO root in a worktree shape',
gitIsDirectoryWalk(join(wt, 'packages', 'lint', 'scripts')) === '' && statSync(join(wt, '.git')).isFile());

// (d) No locatable root: absolute, which always runs. ⛔ Never a relative
// path invented against a root that was never found.
const orphanGate = join(dir, 'no-marker', 'scripts', 'check-orphan-fixture.mjs');
mkdirSync(dirname(orphanGate), { recursive: true });
t('an importer with no locatable root prints an ABSOLUTE path, always runnable',
importerCommandPath(pathToFileURL(orphanGate).href) === orphanGate,
importerCommandPath(pathToFileURL(orphanGate).href));
t('⛔ and never a relative path invented against a root that was not found',
!advisoryFor(orphanGate).includes('`node scripts/check-orphan-fixture.mjs'));

// (e) Triage's explicit boundary on this card: the HEADLINE gate name is a
// basename and is CORRECT as one. Only the command was wrong.
t('the headline still names the gate by BASENAME, never by path',
advisoryFor(lintGate).includes('\ncheck-doc-formula-expressions: PREREQUISITE NOT MET')
&& !advisoryFor(lintGate).includes('packages/lint/scripts/check-doc-formula-expressions: PREREQUISITE'),
advisoryFor(lintGate));

// (f) The log sink keeps the basename too — `/tmp/packages/lint/scripts/
// ….log` names directories that do not exist, so a blanket substitution
// would hand back a broken command one token to the right.
t('the /tmp log sink keeps the BASENAME — a repo-relative one names absent directories',
advisoryFor(lintGate).includes('> /tmp/check-doc-formula-expressions.log 2>&1')
&& !advisoryFor(lintGate).includes('/tmp/packages/lint'));
} finally {
rmSync(dir, { recursive: true, force: true });
}
Expand DownExpand Up@@ -738,6 +890,18 @@ export function selfTest() {
t('NEGATIVE CONTROL: the literal-exit pin can still fail', hardcodesExitCall(controlHardcodedExit));
t('NEGATIVE CONTROL: the literal-advisory pin can still fail', spellsALiteralCode(controlLiteralAdvisory));

// The same shape for the directory. The regression that costs something here
// is not a mistyped path: it is an author interpolating the gate NAME back
// into a hard-coded `scripts/` because the headline beside it does exactly
// that. It would read correct, stay green for the 42 gates under `scripts/`,
// and be wrong only for the three that are the whole point of this pin.
const hardcodesScriptsDir = (fn) => /`node scripts\//.test(fn.toString());
const controlHardcodedScriptsDir = () => ` \`node scripts/${'gate'}.mjs > /tmp/x.log\``;
t('the advisory INTERPOLATES the importer path rather than hard-coding `scripts/`',
!hardcodesScriptsDir(prerequisiteNotMetText));
t('NEGATIVE CONTROL: the hard-coded-directory pin can still fail',
hardcodesScriptsDir(controlHardcodedScriptsDir));

t('the refusal class is 3 — the code four sibling gates answer these words with',
EXIT_PREREQUISITE_NOT_MET === 3, String(EXIT_PREREQUISITE_NOT_MET));
t('the refusal class is distinct from a finding and from a pass',
Expand Down
Loading