Skip to content

Commit 3d63ed7

Browse files
committed
test(cli): the noise-budget e2e aligns the scaffold's engines.protocol with the runtime it boots
The file scaffolds the blank starter and boots it against the workspace runtime without an install. In a Changesets pre-mode window the workspace protocol (18) is ahead of the published line the template stamps (^17), so the handshake refused the pair before any boot diagnostic was printed and the budget assertion read an empty block. The setup now rewrites the one key to '^' + PROTOCOL_MAJOR of the workspace spec, digits only, so it leaves the scaffold byte-for-byte as written when the majors agree. A direct rewrite rather than `migrate meta --write`: that codemod refuses files under a node_modules segment, where this project lives. Budget, assertions and fixture objects and actions are unchanged. Claude-Session: https://claude.ai/code/session_01BmsuLyUeuG5CNpZFMH1jzS Co-authored-by: Claude <noreply@anthropic.com>
1 parent 60fa01c commit 3d63ed7

1 file changed

Lines changed: 40 additions & 1 deletion

File tree

‎packages/cli/test/serve-boot-diagnostics-noise-budget.e2e.test.ts‎

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@
3030

3131
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
3232
import { execFile } from 'node:child_process';
33-
import { appendFileSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
33+
import { appendFileSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
3434
import { join, resolve } from 'node:path';
3535
import { fileURLToPath } from 'node:url';
36+
import { PROTOCOL_MAJOR } from '@objectstack/spec/kernel';
3637
import { childEnv, randomPort, runServe, type ServeRun } from './helpers/serve-process.js';
3738

3839
const HERE = resolve(fileURLToPath(import.meta.url), '..');
@@ -122,6 +123,43 @@ let root: string;
122123
let scaffold: { code: number; output: string };
123124
let boot: ServeRun | undefined;
124125

126+
/**
127+
* Align the scaffold's `engines.protocol` with the protocol of the runtime this
128+
* file boots: the WORKSPACE `@objectstack/spec`, whose `PROTOCOL_MAJOR` this
129+
* reads.
130+
*
131+
* The template stamps the protocol of the packages a real project INSTALLS,
132+
* which is the published line (`create-objectstack`'s own major). That is
133+
* right for users: the Scaffold E2E gate installs from the registry and refuses
134+
* any other range. This file installs nothing — the project resolves the
135+
* workspace copies — so in a Changesets pre-mode window, where
136+
* `PROTOCOL_VERSION` moves ahead of the version pass (packages at 17.x beside
137+
* protocol 18), the pair it boots is one no user has: a published-line scaffold
138+
* on a next-major runtime. The handshake refuses that pair before a single boot
139+
* diagnostic is printed, and this file goes red on the setup rather than the
140+
* budget (review 6099406666 on #22622). So the setup aligns the pair it boots.
141+
*
142+
* Only the major's digits are rewritten. Outside such a window the template
143+
* already stamps `'^PROTOCOL_MAJOR'`, and the file is left byte-for-byte as
144+
* scaffolded.
145+
*
146+
* A direct rewrite of this one key, not `objectstack migrate meta --from N
147+
* --write`, the step the refusal prescribes: that codemod refuses to edit any
148+
* file under a `node_modules` path segment, and this project lives under this
149+
* package's `node_modules` so that its imports resolve. Measured on a scaffold
150+
* there: exit 0, "not written [outside-project]", config unchanged.
151+
*/
152+
function alignProtocolRange(configPath: string): void {
153+
const source = readFileSync(configPath, 'utf8');
154+
const stamp = /engines:\s*\{\s*protocol:\s*'\^(\d+)'\s*\}/;
155+
if (!stamp.test(source)) {
156+
throw new Error(`${configPath} declares no engines.protocol stamp, so the pair this file boots cannot be aligned`);
157+
}
158+
const aligned = source.replace(stamp, (literal, major: string) =>
159+
literal.replace(`'^${major}'`, `'^${PROTOCOL_MAJOR}'`));
160+
if (aligned !== source) writeFileSync(configPath, aligned);
161+
}
162+
125163
function scaffoldProject(cwd: string): Promise<{ code: number; output: string }> {
126164
return new Promise((resolveRun) => {
127165
execFile(
@@ -141,6 +179,7 @@ beforeAll(async () => {
141179
scaffold = await scaffoldProject(root);
142180
if (scaffold.code !== 0) return;
143181
const dir = join(root, PROJECT);
182+
alignProtocolRange(join(dir, 'objectstack.config.ts'));
144183
writeFileSync(join(dir, 'src', 'objects', 'ticket.object.ts'), TICKET_OBJECT);
145184
appendFileSync(join(dir, 'src', 'objects', 'index.ts'), "export { Ticket } from './ticket.object.js';\n");
146185
writeFileSync(join(dir, 'src', 'actions', 'ticket.actions.ts'), TICKET_ACTIONS);

0 commit comments

Comments
 (0)