fix(engine): run the sweep as an idle job and admit a grafted version restore - #1917
Conversation
|
Warning Review limit reachedNext included review available in 31 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Repository: FSM1/cipher-box/.coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (3)
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository: FSM1/cipher-box/.coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (14)
Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review. WalkthroughThe web file details flow now uses scoped access for version commands. The engine now supports reusable sweep jobs, idle convergence sweeps, and write-granted version restores. Tests cover permission transitions, background tasks, restoration, and convergence. ChangesScope-aware version access
Idle sweep processing and restore convergence
Priority: ➖ Normal Estimated code review effort: 4 (Complex) | ~60 minutes Change: Feature Sequence Diagram(s)sequenceDiagram
participant Engine
participant IdleSweepJob
participant Sweeper
participant ScopeRecords
Engine->>IdleSweepJob: start idle sweep job
IdleSweepJob->>Engine: discover owned unconverged scopes
IdleSweepJob->>Sweeper: sweep each target
Sweeper->>ScopeRecords: re-seal unsettled records
Sweeper-->>IdleSweepJob: return SweepRun
IdleSweepJob-->>Engine: continue at sweep cadence
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The sweep ran only as the task a cut enqueues, capped at three passes. A sweep that failed, or a restart after a cut, left interior nodes at the old epoch until a write reached them. The engine now spawns the idle sweep job at start. Each sweep cadence it runs one pass over every scope this vault owns that is past its genesis epoch and that no pass of this session confirmed converged at its current epoch. Nothing new is durable: a restart starts with every such scope due. A granted scope is never a target. Part of #1911.
A version restore reorders the file's own history: the named version becomes the head and the outgoing head becomes the newest prior version. It drops no version, prunes nothing and touches no bin, so it is a write like a new version. The facade now admits it for a proved write pass. A version delete stays refused. The web details dialog shows the restore control again in a share granted for writing, and still hides the version delete there.
a380c82 to
e1477c5
Compare
|
@coderabbitai review |
|
|
A sweep pass whose child-scope index repair lost the CAS now reports index_repair_lost_race, and worth_another_pass counts it. The idle job then does not record the scope as converged, so a later round re-derives and republishes the index.
Part of #1911.
This change also lets a write grantee restore a prior version of a file below a proved grafted write root. The owner decision for this is #1886 (comment): a version restore publishes a new head from a prior version and deletes no version, the same as an edit. Bin restore, purge, prune and version delete stay refused.
Part 1: the idle sweep job
Problem
blueprint/engine.md"sweep" says that the sweep runs as an idle-cadence Scheduler job.run_sweep_jobhad no production caller. The only sweep was the task that a cut enqueues, capped at three passes. A sweep that failed, or a restart after a cut, left interior nodes at the old epoch until a write reached them.Change
Engine::startspawns the idle sweep job (spawn_sweep_jobincrates/engine/src/facade.rs). Eachsweep_cadenceit runs one pass over each due scope.walked_read_epochs). A grafted scope is never a target.GENESIS_EPOCH. For the vault root the epoch comes from the durable epoch floor. For a nested scope it comes from the walk.Sweeperbuilds the owner rotation net for both the cut task (three passes) and the idle job (one pass per round).run_sweep_jobincrates/engine/src/rotation/sweep.rsnow takes the per-scope sweep as a closure, because each scope needs its own ascent authority.blueprint/engine.mdsays that the sweep is "Runnable by any write-capable client", but this change wires the job only for the scopes that the owner's own vault holds. A write grantee's session runs the job only over the scopes of its own vault, never over a grafted scope.SweepRun:Swept(result), orSessionEndedwhen the session keys are gone. The job then stops.Tests
In
crates/engine/tests/mount_convergence.rs, new section "The lazy wave a cut leaves behind":the_sweep_a_cut_enqueues_re_seals_the_folder_it_left_behind: the test drives the tasks thatRotateNowspawned, with no clock advance, and the folder is re-sealed at the new epoch.after_a_restart_the_idle_sweep_converges_what_a_failed_sweep_left: the cut's own sweep fails (all endpoints fail), the device restarts, and the idle job converges the lagging folder with no write to it.a_read_only_member_never_runs_the_wave: a read grantee runs three sweep cadences after the owner's cut and no record on any endpoint changes. The owner's idle job then re-seals the folder.The restart test and the read-only test fail when the job is not spawned.
crates/engine/tests/facade.rsand the facade loop test now count the job among the tasks thatstartspawns, and check that it stops when the engine drops.Part 2: version restore below a proved grafted write root
Verdict: admitted
Command::RestoreVersionjournalsOpKind::RestoreVersion. The drain armpublish_restore_version(crates/engine/src/sync/drain.rs) rotates the named version to the head of the file's ownversionslist and republishes the file record. It keeps every version, prunes nothing, and calls no vault surface: no bin index, no retire ledger, no doomed-name journal. So it is a write like a new version, and it is not a bin restore. The facade now admits it for a proved write pass.DeleteVersion,Restore, andPurgestay refused.Tests
WriteGranteeharness, real facade and real drain):a_write_grantee_authors_every_admitted_write_inside_the_granted_scoperestores the first version and checks the head and the prior list. The version restore case moved out ofa_write_grantee_is_refused_what_leaves_the_scope_or_reaches_the_owners_surfaces.a_write_grantees_version_restore_reaches_the_ownerincrates/engine/tests/mount_convergence.rs. The write grantee restores the prior version of a file that the owner wrote. The owner reads the restored content as the head and the outgoing head as the prior version.Web
DetailsDialog,FileDetailsandVersionHistorytake one required prop,access: ScopeAccess('owner' | 'write-grant' | 'read-only'), in place of two booleans.offers(access, command)is the one rule for which version write each access shows:ownershows restore and delete,write-grantshows restore only,read-onlyshows neither.DetailsDialogalso closes an open confirmation when the new access does not offer its command.Tests in
versions.test.tsx:offers a restore and no delete in a share granted for writing.retires a delete confirmation and keeps a restore one when the access drops to a write grant.Shared file
crates/engine/tests/mount_convergence.rsis also changed by #1914 (lane G20). This change adds its tests in the middle of the file, before the section "A write staged across a cut", and does not change any function that #1914 changes. A move of the new tests to a separate file needs a shared helper module for about 15 helpers of that file, so they stay in it.Local runs
cargo fmt --all --check,cargo clippy --workspace --all-targets -- -D warnings,cargo clippy -p cipherbox-engine -p cipherbox-wasm --target wasm32-unknown-unknown -- -D warnings,cargo test -p cipherbox-engine(all pass),pnpm -r typecheck,pnpm lint,pnpm lint:tracker-refs, and theapps/webvitest suite (763 tests).Reviews run before the draft
--agent --base-commit): 1 minor finding. The test snapshot read only the first endpoint. Fixed: it now reads every endpoint.--agent --base-commit) with 0 findings.Body checks / follow-ups filed
engine: a read cut of the vault root bricks the next cold start on the same device #1916: comment engine: a read cut of the vault root bricks the next cold start on the same device #1916 (comment). The idle job's vault-root path (epoch from the durable floor after a restart) has no restart test. The fix for engine: a read cut of the vault root bricks the next cold start on the same device #1916 must add that case.
engine: a read cut of the vault root bricks the next cold start on the same device #1916 (new,
post-cutover,comp:engine, child of engine: the hardening track for post-review follow-ups #1702): a read cut of the vault root does not publish a new vault-pointer re-point, so the next cold start on the same device fails with a read-epoch floor regression. Found while writing the restart test. The restart test cuts a nested scope for this reason.Note
Run sweep as an idle background job and allow version restore from grafted write scopes
Sweeperandrun_sweep_jobto accept a per-invocation pass cap and per-target sweep callback, returningSweepRunto distinguish a completed sweep fromSessionEnded(crates/engine/src/rotation/sweep.rs)RestoreVersioncommand path so a proved write grantee can stage a version restore;DeleteVersionremains graft-refusedwritableprop with a three-wayScopeAccessclassification (owner, write-grant, read-only) acrossDetailsDialog,FileDetails, andVersionHistory, making version restore available to owners and write grantees while delete stays owner-onlyDetailsDialogare now retired command-specifically when access drops below the required levelSessionEnded. Write grantees can now restore versions, authoring a new version position without rewinding historyMacroscope summarized e1477c5.
Summary by CodeRabbit
New Features
Documentation
Bug Fixes