REL-NB-006 — Reject stale concurrent notebook saves
| Field | Value |
|---|---|
| Status | Open; source-verified |
| Architecture state | Source-backed persistence contract |
| Severity | High |
| Affected surface | Multiple browser contexts and authorized collaborators |
| Components | sparqd/workspace-file-management-backend, sparqd/oqullus; BFF API forwards writes |
| Associated issues | workspace-file-management-backend #18, then oqullus #523 |
Where the problem appears
Open one notebook in two isolated contexts, save different edits from the same loaded version, and inspect the final object and history.
Concrete observed case
The client revision counter is local and not supplied as a server precondition. The BFF forwards an unconditional update, and the file service advances the current object version without checking the version originally loaded.
Expected condition
Load and save expose one canonical object version. A stale update is rejected before overwrite and offers compare, reload, or save-copy recovery.
Cause and evidence
The persistence contract lacks an expected version or equivalent conditional write. Local revision tracking only protects against changes during one request.
Why it matters
Two valid editors can silently overwrite one another. History enables forensic recovery but does not prevent the data-loss event.
Existing controls and workarounds
Notebook history, diff, and revert can recover an earlier complete object after the overwrite is discovered. Coordinate editing or save a copy when concurrent access is expected.
Alternatives considered
- Recommended: optimistic concurrency with current/expected object version and explicit conflict resolution.
- Exclusive edit locks — stronger but creates stale-lock and collaboration problems.
- Keep last-write-wins with history — rejected because recovery is delayed and user-driven.
Component involvement
sparqd/workspace-file-management-backendenforces conditional updates and returns conflicts.sparqd/oqullussends the expected version and presents resolution.- BFF API preserves the conditional contract without weakening it.
Reproduction and verification
Follow NB-S018.
Resolution conditions
Close when a deterministic two-context test rejects the stale write, preserves both recoverable versions, and the UI offers a safe next action.
Validation and blockers
Source behavior is confirmed. A disposable two-context deployed test remains pending.