Skip to content

fix(spec): render-projection-diff generates a base's git-ignored migration registry - #22750

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-22744-projection-diff-base-registry
Oct 11, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-22744-projection-diff-base-registry

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

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 ed1de8c2db --out-dir ... gave exit 1:

## Generated ADR-0087 projections — NOT rendered
- base ed1de8c2db = ed1de8c2db 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 ed1de8c2db = ed1de8c2db 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:

✓ neither projection changes against HEAD^1 = ed1de8c2db
  • Control leg, a base from before the registry left git: --base f59a73c395 (its archive carries a committed registry.ts) gave exit 0, ✓ neither projection changes against f59a73c395. 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


Generated by Claude Code

…ation registry

Since the migration registry left git, a git archive of a base at or after
that change carries only registry.ts.template and entries/, so both base
projection generators died on a missing ../src/migrations/registry module
and the "Render the generated spec-changes and upgrade-guide diff" step went
red on every merge-queue entry.

realMaterializeBase now runs the base's own build-migration-registry.ts in
the base tree when the archive has the generator but not the registry. A
base that committed the registry is untouched; a generator that fails, or
exits 0 without writing, reds the base side with its output.

Claude-Session: https://claude.ai/code/session_01S3aAf11JjbW1mSGL1EhfFj
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 11, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json ed1de8c2db206be39aebd012e6c47503263bbf80 → packageMentionDocs.

marchtian pushed a commit that referenced this pull request Oct 11, 2026
…migration registry

Byte-identical to that PR's head 2a4ccb4 for render-projection-diff.ts and
its test; a no-op once main carries it.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AGgRrdom7nizSbHc5Gws2U
@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 11, 2026 01:36
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 11, 2026 01:36
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 11, 2026
Merged via the queue into main with commit 052a5e1 Oct 11, 2026
41 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-22744-projection-diff-base-registry branch October 11, 2026 02:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate tests tooling

Projects

None yet

2 participants