From 8e6d326c65d1d13c14a69c7bfb21ec918dcfd918 Mon Sep 17 00:00:00 2001 From: os-elon Date: Sat, 22 Aug 2026 15:59:38 +0000 Subject: [PATCH 1/3] test(cli): fail when the two scaffold paths disagree about pnpm build approvals (#10499) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two producers render a `pnpm-workspace.yaml` into a new user's project — `renderPnpmWorkspaceYaml()` in packages/cli and create-objectstack's literal blank template — and both ratchets are package-local, so neither can fail for the other file's regression. That is how one scaffold path went on shipping the pre-`allowBuilds` shape for months, and how the two currently ship contradictory pnpm boundaries for the same key. The gate compares the RENDERED outputs of both producers: the packages each key actually grants a build to, and the pnpm versions each file actually names for each key. Neither file's expected content is restated in the test — every expected value comes from the other producer. Verified RED against the live divergence on main before the comment fix: `objectstack init names [10.26] and npx create-objectstack names [10.31]`. The template read escapes packages/cli, so it is declared in check-cross-package-test-inputs.mjs and in turbo.json's `@objectstack/cli#test` inputs — without that, a template-only diff would replay a cached green. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_019bmVFqoQPq63zhKrxdYG1r --- .../scaffold-workspace-consistency.test.ts | 211 ++++++++++++++++++ scripts/check-cross-package-test-inputs.mjs | 16 ++ turbo.json | 3 +- 3 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 packages/cli/test/scaffold-workspace-consistency.test.ts diff --git a/packages/cli/test/scaffold-workspace-consistency.test.ts b/packages/cli/test/scaffold-workspace-consistency.test.ts new file mode 100644 index 0000000000..c62d0a4190 --- /dev/null +++ b/packages/cli/test/scaffold-workspace-consistency.test.ts @@ -0,0 +1,211 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. +// +// scaffold-workspace-consistency — the two scaffold paths render a +// `pnpm-workspace.yaml` into a new user's project independently, and this file +// is the only thing that can fail when they disagree (#10499). +// +// ── The shape of the defect ───────────────────────────────────────────────── +// +// Two producers write that file, each stating the same pnpm build-approval rule +// in its own words: +// +// * `renderPnpmWorkspaceYaml()` in `packages/cli/src/commands/init.ts`, for +// `objectstack init` — a string builder, ratcheted by `test/init.test.ts`. +// * `packages/create-objectstack/src/templates/blank/pnpm-workspace.yaml`, +// for `npx create-objectstack` — a literal file copied into the project, +// ratcheted by that package's `src/template-consistency.test.ts`. +// +// Both ratchets are PACKAGE-LOCAL, so neither can fail for the other file's +// regression: `allowBuilds` was added to the template when pnpm 11 turned an +// unapproved build script into a hard error, the renderer was not touched, and +// one of the two scaffold paths went on shipping the pre-fix shape for months +// — found by a first-run audit (#10405), not by a gate. The measured pnpm +// boundary was corrected in the renderer by that fix and NOT in the template, +// which is the second instance of the same class (#10498): a user on pnpm +// 10.28 was told by the file inside their own project that their pnpm cannot +// read the key it is in fact reading, while the sibling scaffold path said the +// opposite. +// +// ── ⚠️ The assertion this file must NOT make ──────────────────────────────── +// +// "Both files mention `allowBuilds`" passes while the two contradict each +// other — it passed on `main` throughout the divergence above. An assertion +// that green-lights the live defect is worse than no gate, because it certifies +// the state the gate exists to catch. So what is compared here is the RENDERED +// OUTPUT of each producer: the packages each one actually grants a build, and +// the pnpm versions each one actually names for each key. Neither file's +// expected content is restated below — every expected value comes from the +// OTHER producer, so this file measures the two against each other rather than +// against a transcription that stops tracking either of them. +// +// ── Why this file lives in `packages/cli` ─────────────────────────────────── +// +// The CLI side must be CALLED rather than text-parsed (it is a string builder; +// parsing its source would measure the source, not the render), and only this +// package can call it. The template side is a static file, so reading it IS +// reading its producer. `packages/cli` already depends on `create-objectstack` +// (`workspace:*`, for the shared `created-summary` renderer), so the read below +// introduces no dependency edge in either direction — and no shared module: the +// two producers stay independent, this file just makes their disagreement +// loud. The read escapes this package, so it is declared in +// `scripts/check-cross-package-test-inputs.mjs` and in turbo.json's +// `@objectstack/cli#test` inputs; without that declaration a template-only diff +// could not reach this suite and its cache would replay a stale green. +// +// ⛔ `peerDependencyRules` is deliberately NOT compared here. The peer-warning +// skew between the two files is #10931, open on this same surface; a limb +// added here would either duplicate that card or pre-empt its ruling. + +import { describe, it, expect } from 'vitest'; +import { readFileSync } from 'node:fs'; +import { resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { renderPnpmWorkspaceYaml } from '../src/commands/init'; + +const HERE = resolve(fileURLToPath(import.meta.url), '..'); + +const TEMPLATE_WORKSPACE_YAML = resolve( + HERE, + '../../create-objectstack/src/templates/blank/pnpm-workspace.yaml', +); + +/** The rendered output of each scaffold path, keyed by the command a user runs. */ +const RENDERED = { + 'objectstack init': renderPnpmWorkspaceYaml(), + 'npx create-objectstack': readFileSync(TEMPLATE_WORKSPACE_YAML, 'utf8'), +} as const; + +type Producer = keyof typeof RENDERED; +const [CLI, TEMPLATE] = Object.keys(RENDERED) as [Producer, Producer]; + +/** The two keys that grant a dependency's build script permission to run. */ +const APPROVAL_KEYS = ['allowBuilds', 'onlyBuiltDependencies'] as const; + +/** + * The packages each key actually grants a build to, read out of the settings + * with the prose stripped first — the comments below each key NAME these + * packages, and must never be what satisfies an assertion about the grant. + */ +function grantedBuilds(yaml: string): Record<(typeof APPROVAL_KEYS)[number], string[]> { + const settings = yaml.replace(/^\s*#.*$/gm, ''); + const mapping = /^allowBuilds:\n((?:[ \t]+.*\n?)*)/m.exec(settings)?.[1] ?? ''; + const list = /^onlyBuiltDependencies:\n((?:[ \t]*-.*\n?)*)/m.exec(settings)?.[1] ?? ''; + return { + allowBuilds: [...mapping.matchAll(/^[ \t]+([^\s:]+):[ \t]*true[ \t]*$/gm)] + .map((m) => m[1]) + .sort(), + onlyBuiltDependencies: [...list.matchAll(/^[ \t]*-[ \t]*(\S+)[ \t]*$/gm)] + .map((m) => m[1]) + .sort(), + }; +} + +/** + * The prose each file attaches to each approval key, as one string per key. + * + * Both files write it as a definition list inside the header comment — the key + * at the start of a comment line, its explanation column-aligned after it, and + * continuation lines indented under that. The two wordings differ and are meant + * to; only the VERSION CLAIMS inside them are compared. + */ +function keyProse(yaml: string): Map { + const prose = new Map(); + let current: string | null = null; + for (const line of yaml.split('\n')) { + const definition = /^#[ \t]{2,}(allowBuilds|onlyBuiltDependencies)[ \t]{2,}(\S.*)$/.exec(line); + if (definition) { + current = definition[1]; + prose.set(current, definition[2].trim()); + continue; + } + // A continuation is an indented comment line that starts no new key; a bare + // `#` (or anything that is not an indented comment) closes the entry. + const continuation = current === null ? null : /^#[ \t]{2,}(\S.*)$/.exec(line); + if (continuation) { + prose.set(current!, `${prose.get(current!)} ${continuation[1].trim()}`); + continue; + } + current = null; + } + return prose; +} + +/** + * Every pnpm version a piece of prose names, in the order it names them. + * + * Dotted only: `10.26`, `10.0`, `11.22.0` are boundary CLAIMS, while the bare + * majors both files use in passing ("pnpm 11 reads ONLY this one") are prose, + * and so is the `1` in "exits 1". + */ +function versionsNamed(prose: string): string[] { + return [...prose.matchAll(/\d+\.\d+(?:\.\d+)?/g)].map((m) => m[0]); +} + +describe('the two scaffold paths render the same pnpm build approvals (#10499)', () => { + it('grants exactly the same packages a build, under both keys', () => { + const cli = grantedBuilds(RENDERED[CLI]); + const template = grantedBuilds(RENDERED[TEMPLATE]); + + // Non-vacuity: an empty grant on both sides would compare equal while + // approving nothing, which is the shape that fails a user's first install. + for (const [producer, granted] of [[CLI, cli], [TEMPLATE, template]] as const) { + for (const key of APPROVAL_KEYS) { + expect( + granted[key].length, + `${producer} renders no package under \`${key}\` — a scaffolded project's ` + + 'first `pnpm install` fails on pnpm 11 with ERR_PNPM_IGNORED_BUILDS', + ).toBeGreaterThan(0); + } + } + + for (const key of APPROVAL_KEYS) { + expect( + cli[key], + `\`${key}\` grants a different build set in the two scaffold paths: ` + + `${CLI} approves [${cli[key].join(', ')}] and ${TEMPLATE} approves ` + + `[${template[key].join(', ')}]. Both write a pnpm-workspace.yaml into a new ` + + 'user\'s project and neither package\'s own tests can see the other, so a ' + + 'divergence here ships to whichever half of users took the other path.', + ).toEqual(template[key]); + } + }); + + it('states the same pnpm version boundary for each key', () => { + const cli = keyProse(RENDERED[CLI]); + const template = keyProse(RENDERED[TEMPLATE]); + + expect( + [...cli.keys()].sort(), + 'the two scaffold paths explain a different set of build-approval keys', + ).toEqual([...template.keys()].sort()); + + for (const key of APPROVAL_KEYS) { + const claimed = { + [CLI]: versionsNamed(cli.get(key) ?? ''), + [TEMPLATE]: versionsNamed(template.get(key) ?? ''), + }; + + // Non-vacuity again: prose naming no version at all would compare equal + // between the two files while telling the reader nothing, and this whole + // block would pass over a boundary nobody states. + for (const producer of [CLI, TEMPLATE] as const) { + expect( + claimed[producer].length, + `${producer} states no pnpm version for \`${key}\` — the boundary is what the ` + + 'reader of a scaffolded project needs, and an unstated one cannot be kept ' + + 'in step with the other scaffold path', + ).toBeGreaterThan(0); + } + + expect( + claimed[CLI], + `the two scaffold paths tell a user different things about which pnpm reads ` + + `\`${key}\`: ${CLI} names [${claimed[CLI].join(', ')}] and ${TEMPLATE} names ` + + `[${claimed[TEMPLATE].join(', ')}]. Both files ship into a user's own project, ` + + 'so one of them is telling that user their pnpm cannot read a key it is ' + + 'reading. The measured boundary is the one to move TO — never move a correct ' + + 'file to match a wrong one.', + ).toEqual(claimed[TEMPLATE]); + } + }); +}); diff --git a/scripts/check-cross-package-test-inputs.mjs b/scripts/check-cross-package-test-inputs.mjs index 60fbf72624..8a82d2be45 100644 --- a/scripts/check-cross-package-test-inputs.mjs +++ b/scripts/check-cross-package-test-inputs.mjs @@ -398,6 +398,22 @@ export const CROSS_PACKAGE_TEST_INPUTS = { // `@objectstack/spec` is a real dependency of this package, so the graph // already re-runs these tests on any spec change. 'packages/spec/src/system/translation.zod.ts', + // The blank template's rendered `pnpm-workspace.yaml`, READ by + // test/scaffold-workspace-consistency.test.ts (#10499). Two scaffold + // paths write that file into a new user's project — this package's + // `renderPnpmWorkspaceYaml()` and create-objectstack's literal + // template — and each package's own ratchets are package-local, so + // neither could ever fail for the other's regression. The consistency + // test compares the two RENDERED outputs, which makes the template file + // a real input to this package's verdict: a template-only diff changes + // what that test measures. Without this declaration such a diff reaches + // neither layer — `turbo ls --affected` would still pick cli up (it + // depends on create-objectstack for the shared `created-summary` + // renderer), but `@objectstack/cli#test` would hash the same and replay + // a cached green over the divergence, which is #7802's Layer B exactly. + // One file, not `packages/create-objectstack/**`: the test reads that + // template and nothing else across the boundary. + 'packages/create-objectstack/src/templates/blank/pnpm-workspace.yaml', ], }, '@objectstack/client': { diff --git a/turbo.json b/turbo.json index 667339bcae..f85cf71644 100644 --- a/turbo.json +++ b/turbo.json @@ -75,7 +75,8 @@ "$TURBO_ROOT$/scripts/check-nul-bytes.mjs", "$TURBO_ROOT$/scripts/js-comment-mask.mjs", "$TURBO_ROOT$/scripts/js-comment-mask.d.mts", - "$TURBO_ROOT$/packages/spec/src/system/translation.zod.ts" + "$TURBO_ROOT$/packages/spec/src/system/translation.zod.ts", + "$TURBO_ROOT$/packages/create-objectstack/src/templates/blank/pnpm-workspace.yaml" ] }, "@objectstack/client#test": { From 58953f2083d16be5a658a87312ebae10ba63f54e Mon Sep 17 00:00:00 2001 From: os-elon Date: Sat, 22 Aug 2026 16:03:09 +0000 Subject: [PATCH 2/3] fix(create-objectstack): state the measured pnpm boundary for allowBuilds (#10498) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The blank template's `pnpm-workspace.yaml` is copied verbatim into every scaffolded project, and its comment told the reader `allowBuilds` needs pnpm >= 10.31 while `onlyBuiltDependencies` covers 10.0-10.30. Measured with one clean install per pnpm version, each with its own store, the floor is 10.26.0: 10.25.0 ignores `allowBuilds`, 10.26.0 honours it. So a user on pnpm 10.28 was told by the file inside their own project that their pnpm cannot read the key it is in fact reading. Both load-bearing claims in that comment were and remain correct — both keys are needed, and pnpm 11 reads only `allowBuilds`. Only the boundary moves. The sibling scaffold path (`renderPnpmWorkspaceYaml` in packages/cli) already carried the measured numbers, so this is what closes the divergence the new consistency gate catches. Comment-only: no assertion, no behaviour and no rendered setting changes. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_019bmVFqoQPq63zhKrxdYG1r --- .../create-objectstack/src/template-consistency.test.ts | 6 +++--- .../src/templates/blank/pnpm-workspace.yaml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/create-objectstack/src/template-consistency.test.ts b/packages/create-objectstack/src/template-consistency.test.ts index 2ae47f3014..d9cc196217 100644 --- a/packages/create-objectstack/src/template-consistency.test.ts +++ b/packages/create-objectstack/src/template-consistency.test.ts @@ -435,7 +435,7 @@ describe('blank template explicit empty workspace', () => { // hard error, so the template declaring nothing meant `npx create-objectstack` // + `pnpm install` exited 1 for every user on a current pnpm (#3119). Both keys // are load-bearing and read by different pnpm versions: pnpm 11 honours only -// `allowBuilds`, while pnpm 10.0–10.30 understand only `onlyBuiltDependencies`. +// `allowBuilds`, while pnpm 10.0–10.25 understand only `onlyBuiltDependencies`. describe('blank template pnpm build approvals (#3119)', () => { const wsPath = path.join(pkgRoot, 'src', 'templates', 'blank', 'pnpm-workspace.yaml'); const APPROVED = ['better-sqlite3', 'esbuild']; @@ -463,12 +463,12 @@ describe('blank template pnpm build approvals (#3119)', () => { } }); - it('lists the same packages under onlyBuiltDependencies for pnpm 10.0–10.30', () => { + it('lists the same packages under onlyBuiltDependencies for pnpm 10.0–10.25', () => { const block = /^onlyBuiltDependencies:\n((?:[ \t]*-.*\n?)*)/m.exec(settings)?.[1] ?? ''; for (const pkg of APPROVED) { expect( new RegExp(`^\\s*-\\s*${pkg}\\s*$`, 'm').test(block), - `onlyBuiltDependencies must list "${pkg}" — pnpm < 10.31 does not understand allowBuilds`, + `onlyBuiltDependencies must list "${pkg}" — pnpm < 10.26 does not understand allowBuilds`, ).toBe(true); } }); diff --git a/packages/create-objectstack/src/templates/blank/pnpm-workspace.yaml b/packages/create-objectstack/src/templates/blank/pnpm-workspace.yaml index 1cc1696274..9b9058ad73 100644 --- a/packages/create-objectstack/src/templates/blank/pnpm-workspace.yaml +++ b/packages/create-objectstack/src/templates/blank/pnpm-workspace.yaml @@ -12,9 +12,9 @@ packages: [] # ERR_PNPM_IGNORED_BUILDS — pnpm 10 only warned, pnpm 11 made it a hard error. # # Both keys are needed; they are read by different pnpm versions: -# allowBuilds pnpm >= 10.31 and pnpm 11+. pnpm 11 reads ONLY this +# allowBuilds pnpm >= 10.26 and pnpm 11+. pnpm 11 reads ONLY this # one — onlyBuiltDependencies alone still errors. -# onlyBuiltDependencies pnpm 10.0–10.30, which do not understand allowBuilds. +# onlyBuiltDependencies pnpm 10.0–10.25, which do not understand allowBuilds. # # better-sqlite3 is the native sqlite driver (@objectstack/driver-sql's optional # dependency); esbuild compiles objectstack.config.ts. Both ship prebuilt From 69c17a234765db90f3c804ab9c383f5de4a18696 Mon Sep 17 00:00:00 2001 From: os-elon Date: Sat, 22 Aug 2026 16:19:50 +0000 Subject: [PATCH 3/3] chore(cli): declare the gate's cross-package inputs and add the changeset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three repairs the gates themselves found, all on the new consistency test: * `check:cross-package-test-inputs` rejected the declared template glob as held by nothing — the read was spelled `resolve(\n HERE,\n '…')`, and the detector reconstructs that expression only on one line. Put back on one line, with a comment saying why it must stay there. The reverse-staleness limb catching this is the gate working: an unrecognised read means no declaration, silently. * The same gate then demanded a declaration for `scripts/check-cross-package-test-inputs.mjs` itself, which the test's header quotes while explaining where its read is declared. Declared, following this package's own `check-nul-bytes.mjs` precedent: the literal collector takes quoted paths without parsing, and declaring a rarely-touched file is the trade that entry already settles. * The relative import was extensionless. `packages/cli` is `moduleResolution: NodeNext` and `packages/cli/test` is a hidden typecheck layer (tsconfig `include` is `src` only) held by a shrink-only ledger, so an extensionless import adds a TS2835 plus its TS7006 cascade and reddens check:type-check-debt for everyone. Now `../src/commands/init.js`; measured at 0 errors over `src` + this file. Changeset is a `create-objectstack` patch: the corrected comment ships inside every scaffolded project, while nothing executable moves. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_019bmVFqoQPq63zhKrxdYG1r --- ...old-pnpm-workspace-boundary-consistency.md | 41 +++++++++++++++++++ .../scaffold-workspace-consistency.test.ts | 16 +++++--- scripts/check-cross-package-test-inputs.mjs | 7 ++++ turbo.json | 1 + 4 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 .changeset/scaffold-pnpm-workspace-boundary-consistency.md diff --git a/.changeset/scaffold-pnpm-workspace-boundary-consistency.md b/.changeset/scaffold-pnpm-workspace-boundary-consistency.md new file mode 100644 index 0000000000..18d27ba963 --- /dev/null +++ b/.changeset/scaffold-pnpm-workspace-boundary-consistency.md @@ -0,0 +1,41 @@ +--- +"create-objectstack": patch +--- + +Correct the pnpm boundary the blank template states for `allowBuilds`, and gate +the two scaffold paths against each other (#10498, #10499). + +`packages/create-objectstack/src/templates/blank/pnpm-workspace.yaml` is copied +verbatim into every scaffolded project, so its header comment is prose that +ships **inside the user's own repository**. It said `allowBuilds` needs +pnpm >= 10.31 and that `onlyBuiltDependencies` covers pnpm 10.0–10.30. Measured +on a probe depending on `esbuild@0.28.2`, with a workspace file carrying only +`allowBuilds`, one clean install per pnpm version and each with its own +`--store-dir` (isolation matters — pnpm's side-effects cache will otherwise hand +a later run a build an earlier run performed, and it reads as "the key worked"): + +| pnpm | `allowBuilds` alone | +|:--|:--| +| 10.15.0 – 10.25.0 | ignored — build not run | +| **10.26.0** | **honoured — build ran** | +| 10.28.0 – 10.33.0 | honoured — build ran | + +So the floor is 10.26.0 and the older-key band is 10.0–10.25. A user on pnpm +10.28 was being told by the file in front of them that their pnpm cannot read +the key it is in fact reading. Both load-bearing claims in that comment were +correct and are unchanged: both keys are needed, and pnpm 11 reads only +`allowBuilds`. No setting, no assertion and no install behaviour changes — the +rendered `onlyBuiltDependencies` / `allowBuilds` values are byte-identical. + +The reason it was wrong for so long is the second half of this change. +`objectstack init` renders the same file from `renderPnpmWorkspaceYaml()` in +`packages/cli`, it was corrected to the measured numbers separately, and each +package's ratchets are package-local — so neither could ever fail for the other +file's regression, and the two scaffold paths shipped contradictory prose about +the same rule with every gate green. `packages/cli/test/scaffold-workspace-consistency.test.ts` +now compares the two **rendered outputs**: the packages each key actually grants +a build to, and the pnpm versions each file actually names for each key. It was +confirmed failing against the live divergence before this correction landed. + +Bumped `patch` rather than left out: the corrected text is user-visible — it is +delivered into every new project — while nothing executable moves. diff --git a/packages/cli/test/scaffold-workspace-consistency.test.ts b/packages/cli/test/scaffold-workspace-consistency.test.ts index c62d0a4190..0dfbe09e8a 100644 --- a/packages/cli/test/scaffold-workspace-consistency.test.ts +++ b/packages/cli/test/scaffold-workspace-consistency.test.ts @@ -60,14 +60,20 @@ import { describe, it, expect } from 'vitest'; import { readFileSync } from 'node:fs'; import { resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { renderPnpmWorkspaceYaml } from '../src/commands/init'; +// `.js`, not extensionless: this package is `moduleResolution: NodeNext`, where a +// relative import without the extension does not resolve — every symbol it names +// becomes `any` (TS2835 + a TS7006 cascade). packages/cli/test is a HIDDEN +// typecheck layer (tsconfig `include` is `src` only) held by a shrink-only +// ledger in scripts/check-type-check-coverage.mjs, so an extensionless import +// here raises that count and reddens check:type-check-debt for everyone. +import { renderPnpmWorkspaceYaml } from '../src/commands/init.js'; const HERE = resolve(fileURLToPath(import.meta.url), '..'); -const TEMPLATE_WORKSPACE_YAML = resolve( - HERE, - '../../create-objectstack/src/templates/blank/pnpm-workspace.yaml', -); +// One line on purpose: `check:cross-package-test-inputs` reconstructs this read +// by SOURCE SCAN, and a `resolve(HERE, …)` split across lines is a spelling it +// does not recognise — which would leave the glob declared and held by nothing. +const TEMPLATE_WORKSPACE_YAML = resolve(HERE, '../../create-objectstack/src/templates/blank/pnpm-workspace.yaml'); /** The rendered output of each scaffold path, keyed by the command a user runs. */ const RENDERED = { diff --git a/scripts/check-cross-package-test-inputs.mjs b/scripts/check-cross-package-test-inputs.mjs index 8a82d2be45..d35f909b2b 100644 --- a/scripts/check-cross-package-test-inputs.mjs +++ b/scripts/check-cross-package-test-inputs.mjs @@ -384,6 +384,13 @@ export const CROSS_PACKAGE_TEST_INPUTS = { 'content/docs/deployment/index.mdx', 'content/docs/permissions/authentication.mdx', 'scripts/check-nul-bytes.mjs', + // This gate's OWN script, the third entry of the mention shape on this + // package: test/scaffold-workspace-consistency.test.ts quotes it while + // explaining where its cross-package read is declared. Settled the way + // check-nul-bytes.mjs above is — the literal collector takes quoted paths + // without parsing, so a mention forces a declaration, and declaring one + // rarely-touched file is cheaper than rewording prose to dodge a scanner. + 'scripts/check-cross-package-test-inputs.mjs', 'scripts/js-comment-mask.mjs', 'scripts/js-comment-mask.d.mts', // `translation.zod.ts` is the second entry no test READS -- named in a diff --git a/turbo.json b/turbo.json index f85cf71644..6a5451b8d7 100644 --- a/turbo.json +++ b/turbo.json @@ -76,6 +76,7 @@ "$TURBO_ROOT$/scripts/js-comment-mask.mjs", "$TURBO_ROOT$/scripts/js-comment-mask.d.mts", "$TURBO_ROOT$/packages/spec/src/system/translation.zod.ts", + "$TURBO_ROOT$/scripts/check-cross-package-test-inputs.mjs", "$TURBO_ROOT$/packages/create-objectstack/src/templates/blank/pnpm-workspace.yaml" ] },