Repository navigation
feat(sync): a restored store joins a journaled stream; two-device sync end to end (T13312) - #1967
Open
kryptobaseddev wants to merge 8 commits into
Open
kryptobaseddev wants to merge 8 commits into
kryptobaseddev wants to merge 8 commits into
Conversation
…c end to end (T13312, T12999, T12996) A store restored from another device's journal checkpoint had no row meta and no join state, so enable push refused it and a second device could not enter the stream. - Restore keeps _sync_row_meta and _sync_field_leave on a journal checkpoint (carryMachineState snapshotCarried). - joinStream: refuses unless every row matches its restored meta, there are no waiting captures and the triggers are present, then cuts at the capture position, baselines the ledgers, turns on push/pull/undo and seeds the pull cursor from the checkpoint. Sealing is enabled only after the check. - enableSyncPush joins (status 'joined') when the head journal checkpoint is the one this store synced and its manifest matches; a changed store is refused with the restore --force remedy, never folded; any other store gets E_NEXUS_SYNC_STREAM_JOURNALED. - Tests: the two-device headline (A and B each write, sync, see the other's write; a concurrent done/cancel converges by the typed rules), pull-only joiner reports synced with the push leg skipped, the three refusals, the T13306 remedy followed through to a join. All 7 mutations killed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he join; a refused join restores capture (T13312 review) MED (#1967): planRepair runs outside the cut's transaction, so a write in that gap was captured live at seq <= cut and baselined as checkpoint state. Capture is on before the check, so any such write is a live capture: inside the cut's BEGIN IMMEDIATE the join now refuses on one (the store changed since its restore). Sealing turns on inside that transaction too. LOW: a refused join puts capture back as it found it, so a store that had it off does not pile up captures that refuse every retry. Tests (genesis.test.ts): a join of a meta-complete store; a write in the gap (via the now() hook) refuses, no cut, push off, the row unbaselined; a refused join leaves capture off and no capture triggers. Both mutations killed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… test Main's T13109 binds a new replica when a vault restore places a store; the CLI's relink attaches it, which this helper machine does by hand. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Task: T13312 (T12999 JOIN; closes T12996's last AC, the two-device headline test)
Stacked on #1962 (feat/T12996-cloud-sync).
Problem
A store restored from another device's journal checkpoint carried no
_sync_row_meta, no_sync_metajoin keys and no cursor (a new machine's restore clears local-only tables).cleo sync enable pushrefused it, so a second device could never enter a journaled stream.Change
vault-manifest.ts,nexus-vault.ts): on a journal checkpoint,carryMachineStatekeeps the snapshot's_sync_row_metaand_sync_field_leave(snapshotCarried).joinStream(store/sync/genesis.ts):planRepairis clean), no capture is waiting and the triggers are present. Only "table does not exist", "not in the sync set" and "no uid column" skips are benign.writeStreamCursor, now shared with the pull page transaction).sync.sealis turned on only after the check passes.enableSyncPush:joinStream(row meta) and returns status'joined'. No second genesis.E_NEXUS_SYNC_REFUSEDwith the remedycleo cloud restore --force, then join. It is never folded.E_NEXUS_SYNC_STREAM_JOURNALEDwith the same restore-then-join path. The T13306 pull refusal already names that path.CloudSyncPushEnableResult.statusadds'joined'.genesis.ts_sync_metaexemption goes from 3 to 4, with a reason (the join's suspect-mark delete).Tests (
nexus-vault.test.ts, fake server)cloud syncon both, each device has the other's write.cursorFromCheckpoint(genesis).status: 'synced',skipped: ['sync.push is off'], and A's write applied.--forcerestore remedy; no cut, push off, no segments;E_NEXUS_SYNC_STREAM_JOURNALED.Verification
nexus-vault,vault-manifest,genesis,push,pull) pass, 183 of 183.tscis clean. The test file adds no new error class: the one added error is the existingrestoreNexusVault(vopts(..., {mode:'pull'}))idiom, already present 15 times.--base feat/T12996-cloud-sync), 40 and 32 (--base) pass;lint-changesetspasses.sync.pushandsync.pullstay unreleased.🤖 Generated with Claude Code