feat(storage): align StorageDriver/BlobStore interfaces with S06 consistency model

What

Brings the storage interface definitions in line with the S06 consistency model refined in !375 (merged) — the non-conflicting subset. Stacked on !375 (merged).

  • StorageDriver.Exists(ctx, path) (bool, error) — the narrow boolean existence probe Session crash-recovery needs to distinguish a finalized staging object from a vanished one (D1b) and to probe destPath after a failed commit DB transaction (D2a/D2b). A missing object is (false, nil); the error channel is reserved for transient backend failures.
  • StorageDriver.Writer doc — documents that Writer(offset>0) MUST return *OffsetDivergenceError on a backend/DB offset mismatch (terminate-on-divergence, no self-heal).
  • FileWriter doc — documents that a Close/Commit buffer-flush failure surfaces as *PartialFlushError and is terminal.
  • BlobStore.ResumeSession / GetSessionStatus / Session / SessionStatus docs — drop the stale SELECT ... FOR UPDATE / write-lock wording, replaced with the no-lock size_bytes-CAS + dirty poison-pill reconciliation model and the Exists-probe recovery branches.

Scope notes

  • No behavior change. No concrete StorageDriver exists yet (S3/GCS land later), so adding Exists to the interface breaks no build, and there are no implementations to update. The OffsetDivergenceError / PartialFlushError error types already exist in errors.go.
  • Deliberately excluded: the ErrSessionUnrecoverable distinct-sentinel for D2b. The spec (!375 (merged)) mandates it, but !352 (closed)'s RunCommitTxUnrecoverable conformance test asserts D2b → ErrSessionNotFound, and the current errors.go/stub encode that same decision. That change ships in a separate MR stacked on !352 (closed) so the contradiction is resolved in one place (stub + handler + the !352 (closed) test together).

Type label

type::maintenance — interface/doc alignment to an already-decided spec, no shippable behavior. Consistent with the sibling MRs (!375 (merged) spec, !352 (closed) tests). Relabel to type::feature if you'd rather classify the new Exists method that way.

🤖 Generated with Claude Code

Merge request reports

Loading
Loading