Skip to content

Commit df1cee0

Browse files
committed
test(spec): check-mode 沙箱补种 authorable-defaults/ 记录
四个沙箱(顶层 + 三个 box)此前只种 authorable-surface/。默认值门禁每次调用 都会跑,缺少记录时 `--check` 报「产物缺失」,六条 fixture 因此在它们真正要测的 删除 / 改名判定之前就红了。补种后沙箱重新是真实树的缩影。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014wsZeReNTqiceBfLb5Pyf5
1 parent 2823a66 commit df1cee0

1 file changed

Lines changed: 48 additions & 6 deletions

File tree

packages/spec/scripts/build-schemas-check-mode.test.ts

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,13 @@ import {
6868
authorableSurfaceShardTexts,
6969
schemaManifestShardTexts,
7070
writeShards,
71+
type ShardArrayField,
7172
} from './lib/sharded-artifacts';
73+
import {
74+
AUTHORABLE_DEFAULTS_DIR_NAME,
75+
authorableDefaultsShardTexts,
76+
parseDefaultEntries,
77+
} from './lib/authorable-defaults';
7278

7379
const HERE = path.dirname(fileURLToPath(import.meta.url));
7480
const PKG = path.resolve(HERE, '..');
@@ -103,10 +109,25 @@ function writeManifestShards(dir: string, schemas: readonly string[]): string {
103109
}
104110

105111
/** Aggregate a shard directory back into its sorted key set. */
106-
function readShardKeys(dir: string, field: 'keys' | 'schemas'): string[] {
112+
function readShardKeys(dir: string, field: ShardArrayField): string[] {
107113
return aggregateCategoryShards(dir, field)?.entries ?? [];
108114
}
109115

116+
/**
117+
* Write the recorded default fingerprints as canonical authorable-defaults
118+
* shards (#4666).
119+
*
120+
* The sandbox has to carry this artifact for the same reason it carries the
121+
* authorable-surface one: the default-value ratchet runs on every invocation,
122+
* so a fixture tree without it is not a smaller version of a real tree — it is
123+
* a tree whose generated record is missing, which `--check` reports as such.
124+
* Seeding it keeps every fixture below judging the contract it means to judge.
125+
*/
126+
function writeDefaultsShards(dir: string, entries: readonly string[]): string {
127+
writeShards(dir, authorableDefaultsShardTexts(parseDefaultEntries([...entries].sort())));
128+
return shardBytes(dir);
129+
}
130+
110131
/**
111132
* Every run loads the entire spec surface and emits ~1700 JSON Schemas (~7s
112133
* alone, more under turbo's parallel test load). A timeout here should mean
@@ -126,9 +147,11 @@ let sandbox: string;
126147
let script: string;
127148
let manifestDir: string;
128149
let surfaceDir: string;
150+
let defaultsDir: string;
129151
let surfaceBasePath: string;
130152
let pristine: string[];
131153
let pristineSurface: string[];
154+
let pristineDefaults: string[];
132155
/** The generator's own description line for the in-tree anchor, so fixtures
133156
* written here are byte-canonical exactly the way `gen:schema` writes it —
134157
* a hand-rolled string would trip the anchor's own hand-edit check (#5235). */
@@ -165,8 +188,13 @@ const readSurfaceBase = () => fs.readFileSync(surfaceBasePath, 'utf8');
165188
beforeAll(() => {
166189
pristine = readShardKeys(path.join(PKG, SCHEMA_MANIFEST_DIR_NAME), 'schemas');
167190
pristineSurface = readShardKeys(path.join(PKG, AUTHORABLE_SURFACE_DIR_NAME), 'keys');
191+
pristineDefaults = readShardKeys(path.join(PKG, AUTHORABLE_DEFAULTS_DIR_NAME), 'defaults');
168192
expect(pristine.length, `${SCHEMA_MANIFEST_DIR_NAME}/ is empty — it is a committed artifact`).toBeGreaterThan(0);
169193
expect(pristineSurface.length, `${AUTHORABLE_SURFACE_DIR_NAME}/ is empty — it is a committed artifact`).toBeGreaterThan(0);
194+
expect(
195+
pristineDefaults.length,
196+
`${AUTHORABLE_DEFAULTS_DIR_NAME}/ is empty — it is a committed artifact (#4666)`,
197+
).toBeGreaterThan(0);
170198
const realBase = path.join(PKG, 'authorable-surface.base.json');
171199
if (!fs.existsSync(realBase)) {
172200
throw new Error(
@@ -184,15 +212,20 @@ beforeAll(() => {
184212
script = path.join(sandbox, 'scripts', 'build-schemas.ts');
185213
manifestDir = path.join(sandbox, SCHEMA_MANIFEST_DIR_NAME);
186214
surfaceDir = path.join(sandbox, AUTHORABLE_SURFACE_DIR_NAME);
215+
defaultsDir = path.join(sandbox, AUTHORABLE_DEFAULTS_DIR_NAME);
187216
surfaceBasePath = path.join(sandbox, 'authorable-surface.base.json');
188217
// The authorable-surface ratchet runs after the manifest one; give it the
189218
// committed snapshot so a check that gets that far judges the same contract.
190219
writeSurfaceShards(surfaceDir, pristineSurface);
220+
// Same for the default-value ratchet (#4666), which runs after both: without
221+
// its committed record every fixture would fail on a missing artifact rather
222+
// than on the thing it is testing.
223+
writeDefaultsShards(defaultsDir, pristineDefaults);
191224
// Anchor for the #4650 deletion check: a git repo whose origin/main holds the
192225
// committed baseline. Only the baseline is tracked — src/node_modules stay
193226
// symlinked, untracked reads the same as any dirty worktree.
194227
git('init', '-q', '-b', 'main', '.');
195-
git('add', AUTHORABLE_SURFACE_DIR_NAME);
228+
git('add', AUTHORABLE_SURFACE_DIR_NAME, AUTHORABLE_DEFAULTS_DIR_NAME);
196229
git('commit', '-q', '-m', `baseline: committed ${AUTHORABLE_SURFACE_DIR_NAME}/`);
197230
// The in-tree anchor (#5235), authentic by construction: it mirrors the
198231
// baseline at the commit just made, which stays reachable from origin/main for
@@ -1827,12 +1860,16 @@ describe('build-schemas.ts — check (b) matches the exact retired key, not its
18271860
writeManifestShards(path.join(box, SCHEMA_MANIFEST_DIR_NAME), pristine);
18281861
boxSurfaceDir = path.join(box, AUTHORABLE_SURFACE_DIR_NAME);
18291862
writeSurfaceShards(boxSurfaceDir, pristineSurface);
1863+
// The #4666 default ratchet runs on every invocation, so every box needs its
1864+
// committed record too — otherwise a fixture fails on a missing artifact
1865+
// instead of on the removal/rename it is actually testing.
1866+
writeDefaultsShards(path.join(box, AUTHORABLE_DEFAULTS_DIR_NAME), pristineDefaults);
18301867
boxScript = path.join(box, 'scripts', 'build-schemas.ts');
18311868
boxRegistry = path.join(box, 'src', 'migrations', 'registry.ts');
18321869
pristineRegistry = fs.readFileSync(boxRegistry, 'utf8');
18331870

18341871
boxGit('init', '-q', '-b', 'main', '.');
1835-
boxGit('add', AUTHORABLE_SURFACE_DIR_NAME);
1872+
boxGit('add', AUTHORABLE_SURFACE_DIR_NAME, AUTHORABLE_DEFAULTS_DIR_NAME);
18361873
boxGit('commit', '-q', '-m', `baseline: committed ${AUTHORABLE_SURFACE_DIR_NAME}/`);
18371874
fs.writeFileSync(
18381875
path.join(box, 'authorable-surface.base.json'),
@@ -2137,10 +2174,11 @@ describe('build-schemas.ts — a deleted manifest key must prove itself (#4725)'
21372174

21382175
writeManifestShards(boxManifestDir, pristine);
21392176
writeSurfaceShards(boxSurfaceDir, pristineSurface);
2177+
writeDefaultsShards(path.join(box, AUTHORABLE_DEFAULTS_DIR_NAME), pristineDefaults);
21402178
boxGit('init', '-q', '-b', 'main', '.');
21412179
// BOTH artifacts tracked here: the merge-base manifest is what this gate
21422180
// reads, and the surface baseline keeps the #4650 gate honest alongside it.
2143-
boxGit('add', SCHEMA_MANIFEST_DIR_NAME, AUTHORABLE_SURFACE_DIR_NAME);
2181+
boxGit('add', SCHEMA_MANIFEST_DIR_NAME, AUTHORABLE_SURFACE_DIR_NAME, AUTHORABLE_DEFAULTS_DIR_NAME);
21442182
boxGit('commit', '-q', '-m', 'baseline: committed manifest + authorable surface');
21452183
fs.writeFileSync(
21462184
path.join(box, 'authorable-surface.base.json'),
@@ -2466,7 +2504,7 @@ describe('build-schemas.ts — check (c) dates a tombstone by its exact key (#58
24662504
* so those lines read as deleted by this build (the main sandbox's shape). */
24672505
const seedBoxBase = (...extra: string[]): void => {
24682506
writeSurfaceShards(boxSurfaceDir, [...pristineSurface, ...extra].sort());
2469-
boxGit('add', AUTHORABLE_SURFACE_DIR_NAME);
2507+
boxGit('add', AUTHORABLE_SURFACE_DIR_NAME, AUTHORABLE_DEFAULTS_DIR_NAME);
24702508
boxGit('commit', '-q', '--allow-empty', '-m', 'base variant');
24712509
boxGit('update-ref', 'refs/remotes/origin/main', boxGit('rev-parse', 'HEAD'));
24722510
writeSurfaceShards(boxSurfaceDir, pristineSurface);
@@ -2495,12 +2533,16 @@ describe('build-schemas.ts — check (c) dates a tombstone by its exact key (#58
24952533
writeManifestShards(path.join(box, SCHEMA_MANIFEST_DIR_NAME), pristine);
24962534
boxSurfaceDir = path.join(box, AUTHORABLE_SURFACE_DIR_NAME);
24972535
writeSurfaceShards(boxSurfaceDir, pristineSurface);
2536+
// The #4666 default ratchet runs on every invocation, so every box needs its
2537+
// committed record too — otherwise a fixture fails on a missing artifact
2538+
// instead of on the removal/rename it is actually testing.
2539+
writeDefaultsShards(path.join(box, AUTHORABLE_DEFAULTS_DIR_NAME), pristineDefaults);
24982540
boxScript = path.join(box, 'scripts', 'build-schemas.ts');
24992541
boxRegistry = path.join(box, 'src', 'migrations', 'registry.ts');
25002542
pristineRegistry = fs.readFileSync(boxRegistry, 'utf8');
25012543

25022544
boxGit('init', '-q', '-b', 'main', '.');
2503-
boxGit('add', AUTHORABLE_SURFACE_DIR_NAME);
2545+
boxGit('add', AUTHORABLE_SURFACE_DIR_NAME, AUTHORABLE_DEFAULTS_DIR_NAME);
25042546
boxGit('commit', '-q', '-m', `baseline: committed ${AUTHORABLE_SURFACE_DIR_NAME}/`);
25052547
fs.writeFileSync(
25062548
path.join(box, 'authorable-surface.base.json'),

0 commit comments

Comments
 (0)