Skip to content

Commit 052a5e1

Browse files
fix(spec): render-projection-diff generates a base's git-ignored migration registry (#22750)
Fixes #22744 Clause-②: no ## What `Type Check · source gates` runs `render-projection-diff.ts --base HEAD^1`, which generates the two ADR-0087 projections inside a `git archive` of the base. Since the migration registry became git-ignored and generated (ruling B on #22554, landed as `ed1de8c2db`), that archive carries only `registry.ts.template` and `entries/`, so both base generators die on `Cannot find module '../src/migrations/registry'`. Every merge-queue entry built on a base at or after `ed1de8c2db` fails this step. `realMaterializeBase` now calls a new `generateBaseRegistry(specDir)` after the unpack and the `node_modules` symlinks: - registry present in the archive (any base that committed it) - nothing runs, today's path unchanged; - registry absent and the base carries `scripts/build-migration-registry.ts` - the BASE's own generator runs with this checkout's `tsx`, cwd the base `packages/spec`. It resolves its package root from its own path, so it writes the base's registry from the base's template and entries (its built-in self-test runs first, as on every generation); - the generator exits non-zero, or exits 0 without writing the file - thrown, which the existing catch in `renderProjectionDiff` reports as a red base side with the generator's output. The registry file is regenerated, never committed; ruling B is untouched. The diff stays within the claimed surface: `render-projection-diff.ts` (+48 -3) and `render-projection-diff.test.ts` (+110 -0). ## Evidence: the real step, before and after Both runs are from this worktree, against base `ed1de8c2db`, whose archive lists `packages/spec/src/migrations/registry.ts.template` and no `registry.ts`. Before, with `origin/main`'s script (`ed1de8c2db`, no edit), `tsx scripts/render-projection-diff.ts --base ed1de8c --out-dir ...` gave exit 1: ```text ## Generated ADR-0087 projections — NOT rendered - base ed1de8c = ed1de8c spec-changes.json: build-spec-changes.ts exited 1: Error: Cannot find module '../src/migrations/registry' Require stack: - /tmp/render-projection-diff-jyRygH/tree/packages/spec/scripts/build-spec-changes.ts - base ed1de8c = ed1de8c protocol-upgrade-guide.md: build-upgrade-guide.ts exited 1: Error: Cannot find module '../src/migrations/registry' ``` After, with this branch (`2a4ccb4878`), the step exactly as `lint.yml` spells it (`--base HEAD^1`, so HEAD^1 = `ed1de8c2db`) gave exit 0: ```text ✓ neither projection changes against HEAD^1 = ed1de8c ``` - Control leg, a base from before the registry left git: `--base f59a73c` (its archive carries a committed `registry.ts`) gave exit 0, `✓ neither projection changes against f59a73c`. The generator is skipped there. - The base generator itself, run by hand in a `git archive` of `ed1de8c2db`: exit 0, `build-migration-registry --self-test: ok`, `✓ wrote src/migrations/registry.ts (419 semantic, 258 retired-key, 222 retired-def)`. `cmp` against this checkout's generated registry shows the two are byte-identical. ## Tests `render-projection-diff.test.ts` gets five new cases. They use the file's existing injection seam: a `RunScript` runner passed to `generateBaseRegistry`, plus `materializeBase` for the end-to-end case. 1. An archive with the generator and no registry runs the base generator, once, in the base `packages/spec`. 2. A base that committed its registry, or one with no generator, is left as it is (three layouts). 3. A failing generator, or one that exits 0 without writing, is thrown, with the generator and exit code on the first line and its output after. 4. Through `renderProjectionDiff`: a base whose registry cannot be generated is RED and named as the base. 5. The default runner, with real `tsx`, runs a stand-in generator by its own path with the base package as cwd. Results: - `pnpm --filter @objectstack/spec exec vitest run --project local --maxWorkers=2 scripts/render-projection-diff.test.ts`: `Tests 14 passed (14)` (9 existing + 5 new). - `pnpm --filter @objectstack/spec run typecheck`: exit 0. `check:scripts-typecheck` (`tsconfig.scripts.json`) compiles both touched files; `--listFiles` names both. ## Ablations (from committed `2a4ccb4878`, via `scripts/ablation-replace.mjs`, restore proven blob == HEAD) - The generator call inside `generateBaseRegistry` replaced by a no-op result: `Tests 4 failed | 10 passed (14)`. The four that fail are cases 1, 3, 4 and 5. Case 2 stays green, as expected, because it asserts that nothing runs. - The `generateBaseRegistry(specDir);` call deleted from `realMaterializeBase`, then the real step run against `ed1de8c2db`: exit 1 with the same `Cannot find module '../src/migrations/registry'` for both projections. `realMaterializeBase` is not exported and has no unit pin of its own. Its wiring is pinned end to end by this very CI step, which materialises `HEAD^1` on every pull request, and every such base now lacks the registry. ## Gates `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`, derived in this worktree at `2a4ccb4878` (2 paths against merge base `ed1de8c2d`), lists 59 commands. That is the same list the dispatch carried. All 59 ran at `2a4ccb4878` (the final commit), each exit code captured before any pipe: - **55 exit 0.** Among them are `node scripts/check-adr-0087-registration.mjs --base origin/main` and `--self-test`, `pnpm check:nul-bytes`, `pnpm check:test-source-alias`, `pnpm check:cross-package-test-inputs`, `pnpm check:type-check-coverage` and `pnpm check:type-check-debt`. - **4 NOT MEASURED, exit 3 `PREREQUISITE NOT MET`:** `pnpm check:dts-closure`, `pnpm check:dual-build-cjs-loads`, `pnpm check:lean-entry-closure` and `pnpm check:sourcemap-no-sources-content`. Each reads the built `dist/` of the whole workspace, and this worktree has no workspace build. This narrowing is declared, and CI runs all four. The diff changes no build input: `scripts/` is in no tsup entry, and no `src/` file imports it. - `dispatch-gates --ran`, with the exit-coded record, reports: `59 derived famil(ies) accounted for — 55 run, 4 NOT-MEASURED (4 DERIVED from a recorded exit 3)`. Lint is a narrowed run, measured rather than skipped. `eslint --no-inline-config --format json` over the two touched files reports 2 files linted, 0 errors and 0 warnings. `eslint --print-config` gives parserOptions `{"ecmaVersion":"latest","sourceType":"module"}`, with no `project`. Type-aware linting is therefore off, so this diff cannot move a verdict on any untouched file. The repo-wide `pnpm lint` is left to CI. ## Other `git archive` / base-tree readers of `packages/spec` `git grep` over `scripts/`, `packages/*/scripts`, `.github/` and `packages/spec` finds three more archive call sites. None breaks the same way: - `scripts/check-adr-0087-registration.mjs` `generatedWitness` (the archive at `:2089`). The change that made the registry git-ignored already adapted it: when the template is tracked it runs the rev's own registry generator, and a template with no generator is red. Measured: calling `generatedWitness({ cwd, head: 'HEAD' })` at `2a4ccb4878`, whose archive has no `registry.ts`, returns `problem: null` and a parsed manifest with 2 `perMajor` records. - `scripts/check-merged-result.mjs`: a generic merged-tree probe for budget gates. It runs no spec generator. - `scripts/objectui-changeset-digest.mjs:2304`: a self-test sandbox that writes its own fixture `registry.ts`. ## Changeset None, `skip-changeset` route. `packages/spec`'s `files[]` (`dist`, `json-schema`, `liveness`, `prompts`, `llms.txt`, `README.md`, `src/**/*.zod.ts`, `CHANGELOG.md`, `api-surface`, `spec-changes.json`, `protocol-upgrade-guide.md`) does not include `scripts/`, and no `src/` file imports `render-projection-diff`. Measured on a built spec tree (`03181fc07b`): `grep -rl` for `renderProjectionDiff`, `SUMMARY_DIFF_CAP` and `spec-projections-diff` over every `files[]` path found 0 files; the positive control `MIGRATIONS_BY_MAJOR` in `dist` was found in 4 files. ## Acceptance notes - `realMaterializeBase` stays unexported. The new logic lives in the exported `generateBaseRegistry`, which is what the unit cases pin. Exporting the materialiser would need a git-history fixture, which this file's header deliberately avoids. - A base with neither a registry nor its generator (no such commit exists today) keeps today's behaviour. Its projection generators fail loudly on the missing module, so it is red, never silent. - Once this is on `main`, the walled queue entries (#22735, #22740 and any other dequeued entry) need a new merge-group run to pick it up. A rerun of an old run reuses its old merge ref. --- _Generated by [Claude Code](https://claude.ai/code/session_01S3aAf11JjbW1mSGL1EhfFj)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent d7b26df commit 052a5e1

0 file changed

File tree

    0 commit comments

    Comments
     (0)