Skip to content

P1: on-disk state: close the residual schema and race gaps (durability contract ratified in #699) #617

Description

@macanderson

What decision this asks for

Ratify one durability contract for everything stella writes to disk — .stella/ state, the sidecar SQLite databases, the media manifest, and stella.storage.toml — and then implement it once rather than fifteen times. The maintainer has to make three calls up front: (a) is every durable write atomic (temp + fsync + rename), and what does the #[cfg(not(unix))] branch do when the hardened path is unavailable; (b) is a rename-over-target acceptable on the agent's primary source-mutation path, given it replaces the inode and drops mode/owner/hard links; (c) do the sidecar stores carry a schema-version row and real foreign keys, and what is the backfill/starting-value policy for stores already in the field. Two of these items are destructive (a migration that drops a dead seam, and a sweep that deletes LLM conversation history) and need an explicit go/no-go, not a default.

Once those three rulings exist, most of the items below collapse into one shared write helper plus one migration policy. Nothing here should land as a per-crate one-off.

Items

Spot-checked against main at b5a99b4f: items 1, 2, 3, 4, 6/7, 13, and 15 are all still present as described (ORDER BY id DESC LIMIT 1 at store.rs:984; edge.public_id TEXT NOT NULL with no UNIQUE; std::fs::write(&dest, bytes) in save_with_id; the fixed .manifest.json.tmp; the bare std::fs::write(path, bytes) on the project-scope settings branch; path.with_extension("toml.tmp"); tokio::fs::write(&full_path, content)). None appear to have been fixed since the audit.

Why these are together

Every item on this list changes durable data, and almost all of them are the same defect wearing different crate names: a write that truncates before it has the replacement bytes, a read-modify-write with no lock and a fixed temp path, or a store whose schema can never be migrated because nothing records its version. Fixing them one crate at a time produces four incompatible write helpers and four migration conventions, and the two destructive items (the dead-seam migration and the sidecar sweep) can only be judged against a contract that says what state is authoritative and what is rebuildable. One ruling, one helper, one migration policy — then the fifteen become mechanical.

Deferred during the #546 audit remediation. Put Closes #<this issue> in the PR description and as a commit trailer when it lands.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Important — next in linearea:storestella-store — DuckDB persistence & telemetry

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions