Skip to content

Commit 544767d

Browse files
test(spec): pin proof 4's message-includes leg with a fifth check-mode box (#19754)
Fixes #18865 Clause-②: no `delivers()` in `packages/spec/scripts/build-schemas.ts` is a conjunction, and proof 4's check (c) counts a refusal it cannot read as **"no evidence"**, never as proof: ```ts return issue !== undefined && issue.message.includes(prescription); ``` The left half — "the door refused this write" — is defended by the `ui/ViewItem` fixture, which asserts the probe raises no `unrecognized_keys` issue at all. So `&&` short-circuits in it and the RIGHT half is never evaluated. That half is the only thing that separates a def parsing through its declaration's own error map from a strict CLONE built to the same declaration without it. Before this PR it was defended by a zero. The card asserts "no fixture would fire", **not** "it is already broken". This PR does not claim the leg has ever failed silently in the tree, and it measured no such thing. ## What lands One fifth sandbox in this harness, built in the shape of the four that already copy `src/`, plus two cases: | case | this box's `strictObject` | verdict | exit | |:--|:--|:--|:--| | LIT | error map dropped | `declared-but-silent` | 1 | | DARK | the tree's own bytes | `prescribed`, deletion waived | 0 | A gate that lost the message conjunct turns the LIT case red and leaves the DARK one green. ⚠️ The failure direction is "reads as compliant" — a defeated leg WAIVES the deletion, it does not add a "no evidence" row — which is why both directions are pinned, not just one. ## Re-derived, not inherited Read at branch head `cbb3521fe5` in this worktree, 2026-09-22T22:07Z. The line numbers the card and its triage comment cite were taken on 2026-09-18 and have all moved; the sites below are given by shape and by their reading today. | reading | on `origin/main` `c120dbdfb8` | on `cbb3521fe5` | |:--|:--|:--| | harness length | 4531 lines | 4812 lines | | `it(` cases | 85 | 87 | | `symlinkSync` sites | 6 | 7 | | sites whose entry array still names `src` | 1 (the shared `createSandbox`, `:476`) | 1 (unchanged) | | `cpSync` of `PKG/src` into a box | 4 (`:3438` `:3737` `:4103` `:4367`) | 5 (`:4695` added) | So the shared `createSandbox` and the 85 cases that run through it are untouched: the diff is one appended `describe` block and one `import { z } from 'zod'`. ## The pin can fail — ablation, on disk, both legs proven `node scripts/ablation-replace.mjs` in WRAP mode on `packages/spec/scripts/build-schemas.ts`, anchor `return issue !== undefined && issue.message.includes(prescription);` replaced by `return issue !== undefined;` — the message leg, and nothing else. 2026-09-22T22:10Z. ```text anchor "return issue !== undefined && issue.message.includes(prescription);" x1 (before) anchor hits 1 time(s), as declared anchor x1 -> x0 replace "return issue !== undefined;" x0 -> x1 blob c886e17 -> 3cccd072c9cfe48685728086055cefef6cb7b52a ok mutation landed: anchor 1 -> 0, blob c886e17 -> 3cccd072c9cf ``` Result, the two cases under `-t '#18865'`: ```text × LIT — a strict clone that does not carry its declaration's error map is NOT proof: the deletion is refused AssertionError: expected +0 to be 1 // Object.is equality - Expected 1 + Received 0 ❯ scripts/build-schemas-check-mode.test.ts:4751:22 -> expect(status).toBe(1) Tests 1 failed | 1 passed | 85 skipped (87) ``` The LIT case goes red **for the ablated reason**: with the conjunct gone the gate exits 0 — it waives the deletion, which is the card's stated failure direction — and the DARK case stays green, so the pair discriminates "reads the message" from "refuses everything". Restore, proven on disk rather than by an exit code: ```text restore packages/spec/scripts/build-schemas.ts blob after restore c886e17 blob at HEAD c886e17 git diff HEAD empty ok restored: blob == HEAD (c886e17) and `git diff HEAD` is empty ``` Green again on restore: the full 87-case run below passes both cases with the generator back at its HEAD bytes. ## Route A stays out, measured `@objectstack/spec`'s `files[]` carries `src/**/*.zod.ts`, so a synthetic def written into the real `src/` would ship in the tarball. This fixture writes only into the BOX's own copy of `src/`, and the repo's `src/` is never touched. `npm pack --dry-run --json` on a real build of `@objectstack/spec` (built at 2026-09-22T22:16Z), run on this branch and again with the one changed file restored to `c120dbdfb8`: | | entries | diff | |:--|--:|:--| | before (`c120dbdfb8` bytes of the one changed file) | 2031 | — | | after (this branch) | 2031 | byte-identical file lists, `diff` exit 0, 0 lines | Controls on the after list: - POSITIVE — `src/shared/http.zod.ts` present, `src/system/stack-server.zod.ts` present, 204 `src/` entries in all: the instrument does reach the directory a route-A fixture would have landed in. - NEGATIVE — `scripts/build-schemas-check-mode.test.ts` absent; `scripts/` contributes 0 entries; `src/shared/strict-object.ts` (not a `.zod.ts`) absent. - DARK — `src/shared/http.zod.tsx`, a name that does not exist, absent. The file this PR changes is the only file it changes, and it publishes nothing. ## The cost this adds, measured here, and what the measurement can and cannot resolve Both runs: `vitest run --project repo scripts/build-schemas-check-mode.test.ts --reporter=verbose`, through the shared heavy-verify lock on one **shared** 4-core box with sibling agents active — the before arm queued 123s behind another locked run and the after arm queued 161s, so these are shared-box seconds, not idle-box figures. The two trees differ in exactly the one file. | arm | tree | cases | vitest `Duration` | |:--|:--|--:|--:| | before | the one changed file at `c120dbdfb8` (blob `18100c70f8`, 4531 lines) | 85 | 632.50 s | | after | this branch (blob `326a8c9466`, 4812 lines) | 87 | 646.38 s | Whole-suite delta: **+13.88 s (+2.19 %)**. ⚠️ That number is **NOT distinguishable from run-to-run noise**, and it is not the cost. The control for it is inside the same pair: the **85 cases that are byte-identical in both arms** summed **623.31 s** in the after run and **625.88 s** in the before run — the unchanged work measured **2.57 s FASTER** in the arm that was supposed to be slower, and its summed per-case absolute drift was **31.05 s** (median 290 ms, p90 720 ms, max 1352 ms per case). A 13.88 s whole-run delta sits inside that. The figure that IS resolvable is the direct one: the two new cases are new work and were timed individually — **7.803 s + 8.342 s = 16.14 s**, **2.50 %** of the after run. Both land between this harness's own p75 (7.405 s) and its max (19.08 s), against a per-case mean of 7.35 s, which is what two ordinary gate spawns cost here; the one extra `src` copy this box pays is not separately resolvable at that scale. Sandbox construction is not where this harness spends its time — 87 gate spawns are. Plainly: the box costs about **two cases' worth**, the suite total moved by less than its own noise, and nothing here supports quoting the whole-run delta as a cost. ## Verification - `pnpm exec vitest run --project repo scripts/build-schemas-check-mode.test.ts` — **87 passed (87)**, exit 0, 2026-09-22T22:41Z. The `build-schemas-check-mode` case count moves **85 to 87**. - `pnpm --filter @objectstack/spec test` — the `local` project, which is where the package's `test` script points; this harness is in the `repo` project and is run separately above. **515 files passed, 15043 passed | 1 todo (15044)**, exit 0, 183.81 s, 2026-09-22T22:59Z. - `pnpm --filter @objectstack/spec typecheck` — exit 0, 50 s, same window. - Gate families derived from **this worktree** with `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` (it reports the tree it read: `objectstack-ai/objectstack` at `cbb3521fe5`, 1 changed path, 281 changed lines). **57 commands, each exit code captured before any pipe**: **54 exit 0**, **3 exit 3**. - The three exit-3 rows are **NOT MEASURED, and NOT a pass**: `check:dual-build-cjs-loads`, `check:lean-entry-closure` and `check:type-check-debt` each print `PREREQUISITE NOT MET` and refuse because this worktree has `dist/` for `@objectstack/spec` only. Each reads BUILT output of packages this diff does not touch; the reading CI takes on a fully built tree is the one that counts. Reconciled with `--ran`. - `dispatch-gates.mjs` also names, as outside those 57 and therefore unmeasured here: 58 artifact-roster families whose `silent` verdict is a fact about a list, 11 wide-population families, 9 that apply once a changeset exists, 7 that take a value from the workflow, 5 path-scheduled CI jobs and 4 type-check lanes. Its own words: that silence is not a clearance. ## Changeset This diff changes one file, `packages/spec/scripts/build-schemas-check-mode.test.ts`, and it publishes nothing: measured, not argued — `npm pack --dry-run` lists **2031 entries and 0 under `scripts/`**, and the list is byte-identical to the one taken with that file restored to `c120dbdfb8`. The changeset gate's own route 0 discriminator, `git diff --name-status c120dbd...HEAD -- '.changeset/*.md'`, returns **nothing** — this PR neither adds nor corrects a changeset — so route 0 does not match and the gate's prescription is its **route 2**, quoted from `.github/workflows/pr-automation.yml`: ```text 2. It releases nothing (.github/, .claude/, skills/, docs/, content/, examples/, tests-only, and the like) -> apply the 'skip-changeset' label. ``` (the workflow marks that last line PREFERRED; the marker is dropped from the quote above only because its arrow characters do not survive a GitHub body intact.) ⛔ This round applies no label. The prescription is reported here for the owning seat to act on. ## Acceptance notes Observations, none of them filed and none of them fixed here — this PR's scope is this card: - Every line number the card body and its triage comment cite has moved (the harness is 4531 lines on `origin/main`, not the 4466 the card cites), which is why every site above is given by shape and re-derived. Nothing in the tree is wrong; a line number is simply not an anchor. - The card's stated route-B blocker ("the fixture def can only be written into the real `src`") is false for four of the five sandboxes, which already copy `src/` privately. That is what made a fifth box possible without touching `createSandbox`. - ⛔ Still unmeasured, exactly as the card left it: how many OTHER fail-closed legs of proof 4 are in the same undefended state, and whether this leg has ever actually failed silently in the tree. This PR pins one leg and claims nothing about a population. --- _Generated by [Claude Code](https://claude.ai/code/session_013RDBh5DqXd2xnLwvHLgLFr)_ Co-authored-by: objectstack-fleet[bot] <noreply@anthropic.com>
1 parent 2bdb81f commit 544767d

1 file changed

Lines changed: 281 additions & 0 deletions

File tree

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

Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
// last describe block below drives exactly that.
4949

5050
import { describe, it, expect, beforeAll, afterAll, beforeEach, afterEach } from 'vitest';
51+
import { z } from 'zod';
5152
import { spawnSync } from 'node:child_process';
5253
import fs from 'node:fs';
5354
import os from 'node:os';
@@ -4529,3 +4530,283 @@ describe('build-schemas.ts — a nested retirement row is judged, not ignored (#
45294530
},
45304531
);
45314532
});
4533+
4534+
// ─────────────────────────────────────────────────────────────────────────────
4535+
// #18865 — proof 4's message leg, defended by a fixture instead of by a zero.
4536+
//
4537+
// `delivers()` in build-schemas.ts is a CONJUNCTION, and check (c) counts a
4538+
// refusal it cannot read as "no evidence" rather than as proof:
4539+
//
4540+
// issue !== undefined && issue.message.includes(prescription)
4541+
//
4542+
// The left half — "the door refused this write" — is what the `ui/ViewItem`
4543+
// fixture above defends: a discriminated union the probe's one-key document
4544+
// cannot drive to any arm's door raises no `unrecognized_keys` issue at all, so
4545+
// `issue` is `undefined`. That fixture ASSERTS the probe raises no such issue,
4546+
// which means `&&` short-circuits in it and the right half is never evaluated —
4547+
// delete the `message.includes` conjunct and its verdict does not move, nor does
4548+
// any other case in this file. Measured before this block was written: the leg
4549+
// was defended by a zero.
4550+
//
4551+
// The right half is the only thing that separates a def which parses through the
4552+
// declaration's own error map from a strict CLONE built to the same declaration
4553+
// that does not — `Strict.strip()`, `z.object(Strict.shape)`, an `.extend()`
4554+
// that re-posts the shape without the map. Shape identity cannot tell them apart
4555+
// (that is the narrowing `computeGuidanceRoutes`'s docblock records), and the
4556+
// clone refuses the key with zod's own bare "Unrecognized key", carrying none of
4557+
// the prescription its declaration owes.
4558+
//
4559+
// ⚠️ The failure direction is "reads as compliant": with that conjunct gone the
4560+
// silent clone reads as `prescribed` and its deletion is WAIVED — the one
4561+
// direction this gate must not err in. So the pin below is the LIT case, and the
4562+
// tree's real door is the DARK one beside it; a gate that lost the leg turns the
4563+
// first red and leaves the second green.
4564+
//
4565+
// ── Why a FIFTH box ──────────────────────────────────────────────────────────
4566+
// The subject is a def built WITHOUT its declaration's error map, and the tree
4567+
// holds no such def any more (#18578 closed the last silent twin, which is what
4568+
// turned the `ui/ViewItem` pair into this file's DARK leg). So the fixture makes
4569+
// one, by substituting `strictObject` in this box's OWN copy of `src/` — exactly
4570+
// as the #4659 and #17969 boxes substitute `RETIRED_KEYS_BY_MAJOR`, and for the
4571+
// same reason: the shared sandbox SYMLINKS `src/`, so writing a fixture there
4572+
// would write the repo's own source (and `@objectstack/spec`'s `files[]` carries
4573+
// `src/**/*.zod.ts`, so it would ship). The gate under test is still the copied
4574+
// `scripts/build-schemas.ts`, byte for byte, and no test-only seam is added to
4575+
// it — what differs is the fixture's spec source, which is data exactly as the
4576+
// fabricated `refs/remotes/origin/main` is.
4577+
4578+
/** The anchor this fixture substitutes — `strictObject`'s own declaration. */
4579+
const STRICT_OBJECT_ANCHOR =
4580+
/export function strictObject<T extends z\.ZodRawShape>\(options: StrictObjectOptions, shape: T\) \{\n[\s\S]*?\n\}\n/;
4581+
4582+
describe('build-schemas.ts — proof 4 reads the REFUSAL TEXT: a strict clone without the declaration\'s error map proves nothing (#18865)', () => {
4583+
let box: string;
4584+
let boxScript: string;
4585+
let boxSurfaceDir: string;
4586+
let boxStrictObject: string;
4587+
let pristineStrictObject: string;
4588+
let canonicalBoxSurface: string;
4589+
4590+
/** Same hermetic invocation as the sandbox's `git` — this box is a fixture
4591+
* repository too, and inherits nothing from the machine either (#9068). */
4592+
const boxGit = (...args: string[]): string => gitIn(box, ...args);
4593+
4594+
const runBox = (args: string[] = []): { status: number; output: string } => {
4595+
const r = spawnSync(TSX, [boxScript, ...args], {
4596+
cwd: box,
4597+
encoding: 'utf8',
4598+
timeout: SPAWN_TIMEOUT_MS,
4599+
stdio: ['ignore', 'pipe', 'pipe'],
4600+
// The gate reads `zodByDefKey` for the probe, so it must hold the real
4601+
// instances rather than `lazySchema`'s Proxy — `check:authorable-surface`
4602+
// exports this and so does `gen:schema`.
4603+
env: { ...HERMETIC_ENV, ...EAGER_SCHEMAS_ENV },
4604+
});
4605+
return { status: r.status ?? -1, output: `${r.stdout ?? ''}${r.stderr ?? ''}` };
4606+
};
4607+
4608+
/**
4609+
* Rebuild `strictObject` in this box's own `src/` so every closed shape is a
4610+
* strict clone of its declaration that does NOT carry the declaration's error
4611+
* map: the declaration is still registered (proof 4's first half still finds
4612+
* the promise), the door is still closed (the probe still gets an
4613+
* `unrecognized_keys` issue naming the key), and the refusal carries zod's
4614+
* bare text instead of the prescription.
4615+
*/
4616+
const dropErrorMaps = (): void => {
4617+
const rendered =
4618+
`export function strictObject<T extends z.ZodRawShape>(options: StrictObjectOptions, shape: T) {\n` +
4619+
` strictObjectError(options, shape);\n` +
4620+
` return z.object(shape).strict();\n` +
4621+
`}\n`;
4622+
expect(
4623+
STRICT_OBJECT_ANCHOR.test(pristineStrictObject),
4624+
'`strictObject` is no longer one function declaration in src/shared/strict-object.ts — this ' +
4625+
'fixture substitutes it textually and can no longer find it',
4626+
).toBe(true);
4627+
fs.writeFileSync(boxStrictObject, pristineStrictObject.replace(STRICT_OBJECT_ANCHOR, rendered));
4628+
};
4629+
4630+
/** Put this box's `src/` back to the tree's own bytes — the DARK leg's state. */
4631+
const keepErrorMaps = (): void => {
4632+
fs.writeFileSync(boxStrictObject, pristineStrictObject);
4633+
};
4634+
4635+
beforeAll(() => {
4636+
// ── Fixture validity, loud ───────────────────────────────────────────────
4637+
// Every half below can rot on its own, and each one rots this pin into a
4638+
// green that asserts nothing about the leg.
4639+
expect(
4640+
pristineSurface,
4641+
`${DELETED_SERVER_TWIN} is a real baseline line now — check (c) only ever sees a key the ` +
4642+
`build STOPPED emitting, so this fixture needs a key the baseline does not carry`,
4643+
).not.toContain(DELETED_SERVER_TWIN);
4644+
expect(
4645+
pristine,
4646+
`${SERVER_TWIN_DEF} is no longer emitted — check (c) would route this deletion to the ` +
4647+
`vanished-def proof instead; re-pick the def`,
4648+
).toContain(SERVER_TWIN_DEF);
4649+
expect(
4650+
Object.keys(RateLimitConfigSchema.shape),
4651+
`'${TWIN_LEAF}' is DECLARED on the shape again — it would never reach the unrecognized-key ` +
4652+
`path, so nothing here models a guidance route`,
4653+
).not.toContain(TWIN_LEAF);
4654+
4655+
// The DARK leg's tree fact: the real def parses through the declaration's own
4656+
// error map, so its refusal CARRIES the prescription.
4657+
const delivered = ServerRateLimitConfigSchema.safeParse({ ...TWIN_VALID, [TWIN_LEAF]: 'ip' });
4658+
expect(
4659+
delivered.success,
4660+
`${SERVER_TWIN_DEF} now ACCEPTS '${TWIN_LEAF}' — its door re-opened and the DARK leg below ` +
4661+
`would stop being a delivery at all`,
4662+
).toBe(false);
4663+
expect(
4664+
delivered.success ? '' : delivered.error.issues.map((i) => i.message).join('\n'),
4665+
`${SERVER_TWIN_DEF} rejects '${TWIN_LEAF}' with no prescription — the \`guidance\` entry that ` +
4666+
`is this block's whole subject has gone`,
4667+
).toContain(PRESCRIPTION_BULLET);
4668+
4669+
// The LIT leg's tree fact, taken in process on the very construction the
4670+
// fixture substitutes: a strict clone built from the same shape refuses the
4671+
// key — so the probe DOES get its `unrecognized_keys` issue and `&&` does not
4672+
// short-circuit — and the refusal carries no prescription. This is what makes
4673+
// the case below a pin on the MESSAGE half rather than a second copy of the
4674+
// `ui/ViewItem` pin on the issue-is-undefined half.
4675+
const clone = z.object(RateLimitConfigSchema.shape).strict();
4676+
const silent = clone.safeParse({ ...TWIN_VALID, [TWIN_LEAF]: 'ip' });
4677+
expect(
4678+
silent.success,
4679+
`a strict clone of ${SHARED_TWIN_DEF}'s shape now ACCEPTS '${TWIN_LEAF}' — the fixture would ` +
4680+
`model an OPEN door, which is the issue-is-undefined half, not this one`,
4681+
).toBe(false);
4682+
expect(
4683+
silent.success ? [] : silent.error.issues.map((i) => i.code),
4684+
`a strict clone without the error map no longer answers with an unrecognized-key issue — ` +
4685+
`\`delivers()\` would short-circuit on its LEFT half and this block would pin nothing`,
4686+
).toContain('unrecognized_keys');
4687+
expect(
4688+
silent.success ? '' : silent.error.issues.map((i) => i.message).join('\n'),
4689+
`zod's own unrecognized-key message now carries the prescription bullet — a clone without the ` +
4690+
`declaration's error map has stopped being silent and this fixture models nothing`,
4691+
).not.toContain(PRESCRIPTION_BULLET);
4692+
4693+
box = fixtureTree('build-schemas-proof4-message-leg-');
4694+
fs.cpSync(path.join(PKG, 'scripts'), path.join(box, 'scripts'), { recursive: true });
4695+
fs.cpSync(path.join(PKG, 'src'), path.join(box, 'src'), { recursive: true });
4696+
for (const entry of ['node_modules', 'package.json']) {
4697+
fs.symlinkSync(path.join(PKG, entry), path.join(box, entry));
4698+
}
4699+
mountCommittedLedgers(box);
4700+
writeManifestShards(path.join(box, SCHEMA_MANIFEST_DIR_NAME), pristine);
4701+
boxSurfaceDir = path.join(box, AUTHORABLE_SURFACE_DIR_NAME);
4702+
writeSurfaceShards(boxSurfaceDir, pristineSurface);
4703+
// The #4666 default ratchet runs on every invocation, so every box needs its
4704+
// committed record too — otherwise a fixture fails on a missing artifact
4705+
// instead of on the row it is actually testing.
4706+
writeDefaultsShards(path.join(box, AUTHORABLE_DEFAULTS_DIR_NAME), pristineDefaults);
4707+
boxScript = path.join(box, 'scripts', 'build-schemas.ts');
4708+
boxStrictObject = path.join(box, 'src', 'shared', 'strict-object.ts');
4709+
pristineStrictObject = fs.readFileSync(boxStrictObject, 'utf8');
4710+
4711+
initFixtureRepo(box);
4712+
boxGit('add', AUTHORABLE_SURFACE_DIR_NAME, AUTHORABLE_DEFAULTS_DIR_NAME);
4713+
boxGit('commit', '-q', '-m', `baseline: committed ${AUTHORABLE_SURFACE_DIR_NAME}/`);
4714+
fs.writeFileSync(
4715+
path.join(box, 'authorable-surface.base.json'),
4716+
JSON.stringify(
4717+
{ description: surfaceBaseDescription, baseRev: boxGit('rev-parse', 'HEAD'), keys: pristineSurface },
4718+
null,
4719+
2,
4720+
) + '\n',
4721+
);
4722+
boxGit('add', 'authorable-surface.base.json');
4723+
boxGit('commit', '-q', '-m', 'baseline anchor');
4724+
// The BASE carries one extra line; the worktree is put back to the live set
4725+
// so check (a) stays silent and check (c) sees exactly one deleted key. Same
4726+
// shape as `seedBase` above, kept local because this box owns its own repo.
4727+
writeSurfaceShards(boxSurfaceDir, [...pristineSurface, DELETED_SERVER_TWIN].sort());
4728+
boxGit('add', AUTHORABLE_SURFACE_DIR_NAME);
4729+
boxGit('commit', '-q', '-m', 'base variant: one extra authorable line');
4730+
boxGit('update-ref', 'refs/remotes/origin/main', boxGit('rev-parse', 'HEAD'));
4731+
canonicalBoxSurface = writeSurfaceShards(boxSurfaceDir, pristineSurface);
4732+
});
4733+
4734+
afterAll(() => {
4735+
if (box) fs.rmSync(sandboxRoot(box), { recursive: true, force: true });
4736+
});
4737+
4738+
it(
4739+
'LIT — a strict clone that does not carry its declaration\'s error map is NOT proof: the deletion is refused',
4740+
{ timeout: SPAWN_TIMEOUT_MS },
4741+
() => {
4742+
// The whole of #18865 in one run. The declaration still NAMES `keyBy`, the
4743+
// door is still closed, the probe still gets its `unrecognized_keys` issue
4744+
// — and the refusal carries zod's bare text, not the prescription. Only
4745+
// `issue.message.includes(prescription)` can see the difference, so this
4746+
// case is red for exactly that conjunct and for nothing else.
4747+
dropErrorMaps();
4748+
4749+
const { status, output } = runBox(['--check']);
4750+
4751+
expect(status).toBe(1);
4752+
expect(output).toContain('authorable baseline line(s) were deleted without proof (#4650)');
4753+
expect(output).toMatch(
4754+
new RegExp(
4755+
`${DELETED_SERVER_TWIN.replace(/[/$]/g, '\\$&')} — def .*; a \`strictObject\` declaration ` +
4756+
`NAMES '${TWIN_LEAF}', but writing it`,
4757+
),
4758+
);
4759+
// ⭐ The waiver is the failure direction, named. A gate that lost the
4760+
// message leg prints THIS instead, exits 0, and reads as compliant.
4761+
expect(output).not.toContain('carries the prescription its `strictObject` declaration owes');
4762+
expect(output).not.toMatch(
4763+
new RegExp(
4764+
`${DELETED_SERVER_TWIN.replace(/[/$]/g, '\\$&')} — def .*is REFUSED as an unrecognized key`,
4765+
),
4766+
);
4767+
// …and it is not being refused by some OTHER proof either: the def is
4768+
// root-reachable and its baseline entry was never `[RETIRED]`, so without
4769+
// these legs the case would pass on a gate that had simply stopped emitting
4770+
// proof 4 at all.
4771+
expect(output).not.toMatch(
4772+
new RegExp(`${DELETED_SERVER_TWIN.replace(/[/$]/g, '\\$&')} — def not reachable from the`),
4773+
);
4774+
expect(output).not.toMatch(
4775+
new RegExp(
4776+
`${DELETED_SERVER_TWIN.replace(/[/$]/g, '\\$&')} — def .*was LIVE \\(never tombstoned\\)\\.`,
4777+
),
4778+
);
4779+
4780+
// A check reports; it does not write (#4711) — this file's founding
4781+
// assertion, and the one a fixture that mutates `src/` most needs.
4782+
expect(shardBytes(boxSurfaceDir)).toBe(canonicalBoxSurface);
4783+
},
4784+
);
4785+
4786+
it(
4787+
'DARK — the tree\'s own door, same key, same box: the refusal carries the prescription and the deletion IS waived',
4788+
{ timeout: SPAWN_TIMEOUT_MS },
4789+
() => {
4790+
// Without this leg the case above passes on a gate that waives nothing —
4791+
// "refuse everything" and "read the message" are indistinguishable from one
4792+
// red run. The ONLY difference between the two cases is whether this box's
4793+
// `strictObject` hands the built shape its declaration's error map.
4794+
keepErrorMaps();
4795+
4796+
const { status, output } = runBox(['--check']);
4797+
4798+
expect(output).toContain('carry their own proof (#4650)');
4799+
expect(output).toMatch(
4800+
new RegExp(
4801+
`${DELETED_SERVER_TWIN.replace(/[/$]/g, '\\$&')} — def .*; writing '${TWIN_LEAF}' on it is ` +
4802+
`REFUSED as an unrecognized key`,
4803+
),
4804+
);
4805+
expect(output).toContain('carries the prescription its `strictObject` declaration owes');
4806+
expect(output).not.toContain('authorable baseline line(s) were deleted without proof (#4650)');
4807+
expect(status).toBe(0);
4808+
4809+
expect(shardBytes(boxSurfaceDir)).toBe(canonicalBoxSurface);
4810+
},
4811+
);
4812+
});

0 commit comments

Comments
 (0)