Skip to content

Add notebook schema versioning ladder#940

Open
BenjaminScholtens wants to merge 4 commits into
mainfrom
feat/notebook-schema-versioning
Open

Add notebook schema versioning ladder#940
BenjaminScholtens wants to merge 4 commits into
mainfrom
feat/notebook-schema-versioning

Conversation

@BenjaminScholtens
Copy link
Copy Markdown
Collaborator

Introduces a per-file metadata.schemaVersion on .codex and .source notebooks, plus a shared migration ladder run at four points so files always reach the current schema before any merge or render:

  1. Activation: scan every notebook and bring it to current (no completion flag — the per-file version is the truth).
  2. Save: serializer stamps schemaVersion on every write.
  3. Merge: resolveCodexCustomMerge brings both ours and theirs to current before merging, then stamps the result. Replaces the ad-hoc needsEditHistoryMigration / migrateEditHistoryInContent helpers, which become the v0 → v1 ladder step.
  4. Post-sync (clean fast-forward): executeSyncInBackground walks syncResult.changedFiles ∪ newFiles and brings each touched notebook to current before downstream helpers (index rebuild, webview refresh) read them.

bringNotebookToCurrent(notebook, ctx) is the single entry point and is idempotent. It refuses to migrate downward when a file's version exceeds CURRENT_SCHEMA_VERSION, so a teammate on a newer build won't accidentally regress everyone else's files.

The v0 → v1 step lifts the legacy cellValue + missing editMap shape into the modern value + editMap = ["value"] form. Future schema bumps will append further steps.

Made-with: Cursor

Introduces a per-file `metadata.schemaVersion` on `.codex` and `.source`
notebooks, plus a shared migration ladder run at four points so files
always reach the current schema before any merge or render:

  1. Activation: scan every notebook and bring it to current
     (no completion flag — the per-file version is the truth).
  2. Save: serializer stamps `schemaVersion` on every write.
  3. Merge: `resolveCodexCustomMerge` brings both ours and theirs to
     current before merging, then stamps the result. Replaces the
     ad-hoc `needsEditHistoryMigration` / `migrateEditHistoryInContent`
     helpers, which become the v0 → v1 ladder step.
  4. Post-sync (clean fast-forward): `executeSyncInBackground` walks
     `syncResult.changedFiles ∪ newFiles` and brings each touched
     notebook to current before downstream helpers (index rebuild,
     webview refresh) read them.

`bringNotebookToCurrent(notebook, ctx)` is the single entry point and
is idempotent. It refuses to migrate downward when a file's version
exceeds `CURRENT_SCHEMA_VERSION`, so a teammate on a newer build
won't accidentally regress everyone else's files.

The v0 → v1 step lifts the legacy `cellValue` + missing `editMap`
shape into the modern `value` + `editMap = ["value"]` form. Future
schema bumps will append further steps.

Made-with: Cursor
Replaces the `any`-typed `notebook`/`edit`/`cell` parameters in the
schema ladder with structural interfaces co-located in
`src/projectManager/utils/schema/index.ts`:

  - `SchemaNotebook` / `SchemaNotebookMetadata`
  - `SchemaCell` / `SchemaCellMetadata`
  - `SchemaEdit` (with `validatedBy: ValidationEntry[]`)

Each interface has explicit fields the ladder reads/writes plus an
`[key: string]: unknown` index signature so unrelated fields a future
migration step might add (e.g. `generationId`) round-trip untouched.

`SchemaMigration`, `getSchemaVersion`, `bringNotebookToCurrent`, and
`bringNotebookToCurrentForFile` all accept `SchemaNotebook` directly.

No runtime behavior change.

Made-with: Cursor
  - Add `src/projectManager/utils/schema/README.md` describing the three
    type layers (pre-ladder SchemaNotebook, ladder internals, post-ladder
    canonical CodexNotebookAsJSONData) and where each one is the right
    call. Includes a "how to add a new version" recipe so future
    contributors don't have to reverse-engineer the wiring.

  - In `resolveCodexCustomMerge`, type the parsed-JSON locals as
    `SchemaNotebook` (pre-ladder) and explicitly cast through `unknown`
    to the canonical `CustomNotebookCellData[]` / `CustomNotebookMetadata`
    after `bringNotebookToCurrent` returns. This makes the layer
    transition visible in code and matches the boundary the README
    describes.

No runtime behavior change.

Made-with: Cursor
Mirrors the layer-boundary doc in
src/projectManager/utils/schema/README.md as a Cursor rule so the AI
agent reaches for the right type family by default — SchemaNotebook
inside the migration boundary, canonical types
(CodexNotebookAsJSONData / CustomNotebookCellData / etc.) everywhere
else. Same shape as the existing types.mdc.

Made-with: Cursor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant