Rust-owned opening and retained-source migration
The runtime accepts repository format 86, sync protocol 26, and remote SQL protocol 12. node scripts/compatibility.mjs reads the current versions from the Rust constants. Older protocol clients must be rejected before any mutation. open_lix() owns supported storage upgrades in Rust; JavaScript exposes the same lifecycle through openLix(). Local filesystem storage, browser storage, and hosted authorities all use that contract. Opening remains pending until the repository is usable, with progress identifying local or authority work. Applications do not catch a migration-required error and invoke another migration API.
The reference server retains its hosted lifecycle guard, authority-role validation, and catalog identity checks around the shared Rust opener. Concurrent opens share the same opening operation. It publishes admission only after the repository opens successfully, using a conditional catalog update. Compatible transport-only upgrades require no content scan. Browser clients await server migration internally.
The registered copy-and-activate chain covers full repositories v72–85 and eligible partial replicas v79–85. The v85→86 step registers epoch-scoped negative checkpoint-conversation proofs for partial replicas without rewriting canonical checkpoint pointers or packed commit records. A version-2 durable read-interest journal is upgraded losslessly inside the candidate epoch before publication; malformed or unsupported recipes fail with the source retained for repair and retry. See opening upgrades and retained-source recovery for the supported migration and recovery cases. The chain retains source banks and verifies semantic preservation before activation. Historical preflight defaults to 250,000 changes and 512 MiB; limit exhaustion preserves the source and fails with LIX_ERROR_MIGRATION_LIMIT_EXCEEDED. No migration chain exists for pre-v72 full repository record shapes; preserve these repositories for a version-specific export/import tool. Never silently reset them.
Operator tooling can still use lix::migration::inspect_repository(storage) for read-only inventory and migrate_repository_with_options for explicit positive limits. These tools share the implementation used during opening. The offline-migration Cargo feature remains a compatibility feature; applications do not need it to open supported older repositories.
The v84→85 step adds authenticated semantic fingerprints. The v83→84 step records nearest-checkpoint summaries. Both are part of the supported opening migration chain.
The v82→83 step upgrades branch controls for author IDs and retains readers for existing HOT rows and immutable tracked-state leaves. Rows whose older format did not record an author use the anonymous account. New writes persist their author.
The v81→82 step rebuilds declared-column indexes with composite keys and reverse memberships from authoritative current rows, under the migration limits. Its source-derived replacement plan is projected into the preservation digest. Sparse replicas retire the derived index without asserting unproven completeness or hydrating remote state; their authoritative read path remains available. No pending operation, upload identity, or receipt is rewritten.
The historical v80→81 step changes only the protocol marker. Its digest excludes exactly the protocol marker and mutation-revision key and covers all other registered logical records, including blobs, history, pending work, and acceptance receipts. Equal digests prove exact preservation. For v79, a bounded source-derived plan permits exactly canonical header-incorporation encoding, certified selected locator inventory repair, and certified omitted-history owner markers. The tool projects that plan over the complete source record stream before migration and compares expected_content_digest with the final candidate digest. Raw before and after hashes remain in the report; preservation_basis identifies the normalization. Unplanned changes to rows, history, pending work, or receipts fail the comparison. Older transformations still require their own validator; a false semantic_preservation_verified must block fleet completion.
embedded_repository_id records the portable identity inside the validated repository. A hosted URL/catalog identity can intentionally differ after cloning or restoration. Preserve that original catalog mapping through cutover; an embedded identity or physical prefix alone does not authorize adopting an orphan. Candidate engine admission alone is not a preservation proof.
The ordinary native and WASM SDK artifacts include the Rust lifecycle needed for automatic opening. The separate @lix-js/sdk/migration JavaScript entry remains available for operator conversion and recovery workflows and shares the ordinary WASM engine; normal application opening does not depend on loading that entry.
Direct operator migration APIs neither close a supplied provider nor publish a browser active-store pointer. An operator workflow must preserve physical-lock exclusion, retained sources, crash-safe publication, and detection of late edits from old offline tabs. A new epoch flag cannot fence an old bundle that does not read it.
After new-format writes begin, recover forward. Restoring an older backup would lose those writes; a rollback then requires a separate data-preserving migration.