Skip to content

Durable stores derive their declared schema on the writer's open - #2578

Merged
trissim merged 3 commits into
mainfrom
claude-ai/derived-schema
Oct 21, 2026
Merged

trissim merged 3 commits into
mainfrom
claude-ai/derived-schema

Conversation

@trissim

@trissim trissim commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

Until now a durable store refused any stored schema that differed from its declaration, so every schema change needed a hand-written carry step, and the step drifted from the class. c99becf edited carry_problem_numbers after the bus had already run it, install 46 skipped the edit, and todos.sqlite3 then refused every write. The commander's stale bridge state hit the same refusal.

DurableTables.reconcile_schema now carries the file onto its declaration, inside one write transaction, wherever the declaration says how:

  • A row's declared earlier table name (TypedTable.renamed_from) is renamed to the declared one. If both names hold tables it refuses, because nothing says which rows to keep.
  • Indexes, triggers and views that differ are dropped and rebuilt from their declared SQL.
  • Missing declared objects are created.
  • A table whose columns differ is still refused, and its rows are left untouched.

The catalog kinds (CatalogKind and its members, SQLiteCatalogObject) moved from carry_declared_schema into typed_table, so there is one owner; the legacy step now calls them. carry_problem_numbers is deleted because ProblemAllocation.renamed_from = ("problem_number",). Its data half, deleting allocation rows for numbers already created, only mattered for a bus that hadn't been carried, and the one live bus was carried by hand at 22:27 UTC.

Not covered here: a column that changes type or meaning, such as P421's Todo.goal → Todo.request. That stays a data carry. P421 (#2560) should move its local rebuild(db, row, changed) onto TypedTable as a classmethod, so the table rebuilds itself and the carry supplies only the per-field SQL expressions. carry_bus_history's row moves are data and stay as they are.

Tests: the retained-store test now drops the allocation table and indexes, and renames the table to problem_number, and checks the next write derives both. A new durable-store test drops the declared indexes, checks the next write rebuilds them, and checks that an undeclared column is refused.


Generated by Claude Code

A durable store refused any stored schema that differed from its declaration, so every schema change
needed a hand-written carry step, and the step and the class drifted: c99becf edited
carry_problem_numbers after the bus had run it, and install 46 left todos.sqlite3 refusing every
write (the bridge's stale state hit the same refusal). DurableTables.reconcile_schema now carries the
file onto its declaration inside one write transaction wherever the declaration says how: a row's
declared earlier table name (TypedTable.renamed_from) is renamed to it, indexes, triggers and views
are rebuilt from their declared SQL, and missing declared objects are created. A table whose columns
differ is still refused with its rows untouched. The catalog kinds moved from carry_declared_schema
into typed_table, which now uses them, and carry_problem_numbers is deleted: ProblemAllocation
declares it was problem_number.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AeUaZjvChAcb6qAd6zPYmw
Copilot AI balanced review requested due to automatic review settings October 21, 2026 23:01

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

…through their declaration

carry_declared_schema was a second owner of 'carry a file onto its declaration' beside DurableTables,
and every bus has run it; its dry run also refused tables it did not know (unit-filebus 17008: a
batch-derived table broke CarryChain.pending). Its test goes with it. carry_native_input_proofs now
converts differing proof journals with NativeContextJournal.reconcile_schema, and its dry run counts
them, since a step's dry run is what decides whether it runs. CatalogKind's two boolean flags had no
reader left.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AeUaZjvChAcb6qAd6zPYmw
There is one bus, and install 47 reported 'Pending carries: none' at 7dc1894, so every step on
main had run on it. Keeping them as 'legacy' code was slop: it can only run against a bus that does
not exist, and each one's dry run now decides installs. Deleted: carry_context_store,
carry_goal_execution, carry_goal_work_decision, carry_install_schedule, carry_native_input_proofs,
carry_order_scopes, carry_proof_build_commits, carry_review_timers, the one-shot P380
connector_browser_trust tool, and the tests that exercised them (including test_order_scopes' carry
test, which still called the deleted pending(applied) signature). carry_retired_ledger is the only
step left, so the RetiredFiles base with one user folds into it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AeUaZjvChAcb6qAd6zPYmw
@trissim
trissim merged commit 597327a into main Oct 21, 2026
6 checks passed
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.

3 participants