Files
paseo/docs/STORAGE_REVAMP_PLAN.md
2026-03-29 23:20:18 +07:00

6.8 KiB

Storage Revamp Plan

Status: active rollout, phases 1 and 2 complete

This document now tracks the storage revamp as it exists today, not as a speculative design exercise. The DB foundation and the project/workspace identity cutover have landed. What remains is the explicit creation/archive surface cleanup, timeline durability cutover, and final removal of legacy paths.

Goals

  • make structured records durable in Drizzle + SQLite
  • make projects and workspaces explicit first-class records
  • stop deriving project/workspace identity from agent cwd
  • keep agent snapshot persistence behind clear ownership
  • move committed timeline history to storage-owned rows
  • remove legacy JSON and in-memory authority once the DB path is proven

Out of scope

  • moving config, keypairs, push tokens, or server identity into the DB
  • persisting raw provider deltas or transport-only chunk streams
  • designing a hosted/remote database story beyond keeping the schema portable
  • durable reasoning history unless product explicitly asks for it later

Current state

The storage revamp is no longer hypothetical.

Completed:

  • Drizzle + SQLite database bootstrap is in place
  • projects, workspaces, and agent_snapshots use integer primary keys
  • workspaces.project_id and agent_snapshots.workspace_id cascade on delete
  • agent_snapshots.workspace_id is NOT NULL
  • legacy JSON import feeds the DB-backed structured records
  • project/workspace records use explicit directory fields instead of path-as-identity
  • session read paths now use persisted workspace/project rows instead of cwd/git derivation
  • workspace-reconciliation-service.ts is deleted
  • workspace-registry-bootstrap.ts is deleted
  • workspace-registry-model.ts is reduced to normalizeWorkspaceId

Still pending:

  • explicit create_project / create_workspace API cleanup
  • final archive cascade behavior for descendants and live agents
  • committed timeline storage cutover
  • removal of remaining legacy JSON and in-memory committed-history authority

Converged decisions

Structured record authority

Projects, workspaces, and agent snapshots are DB-backed structured records. The server should not recreate project/workspace identity from:

  • git remotes
  • worktree main-repo roots
  • normalized cwd strings

Temporary exception:

  • agent creation may still find-or-create a workspace by directory if the UI has not yet provided workspaceId explicitly

That fallback is transitional and should be deleted once the client always sends the workspace id.

Storage seams

The useful seams remain concrete and domain-shaped:

  • ProjectRegistry
  • WorkspaceRegistry
  • AgentSnapshotStore
  • AgentTimelineStore

There is no reason to reintroduce a reconciliation service layer for project/workspace identity.

Timeline contract

The long-term timeline contract remains:

  • committed rows are durable, canonical history
  • provisional live updates are transient subscription state
  • committed history is fetched by seq
  • provider history replay is not the durability mechanism

The structured-record cutover is complete before the timeline cutover so timeline rows can rely on stable DB-backed agent and workspace identity.

Remaining phases

Phase 3: Explicit creation and archive cleanup

Goal: Remove the last transitional write paths that still infer state from directories.

Required work:

  • add explicit create_project handling
  • add explicit create_workspace handling
  • make agent creation require workspaceId once the UI is ready
  • finish archive semantics for workspaces/projects and any descendant agent state
  • remove the temporary find-or-create-by-directory fallback from agent creation

Exit gate:

  • project/workspace creation is explicit end to end
  • no normal creation path infers identity from cwd or git metadata
  • archive flows behave consistently for structured records and live runtime state

Phase 4: Timeline storage cutover

Goal: Make committed history durable and storage-owned.

Required work:

  • make AgentTimelineStore authoritative for committed history
  • write one committed row per finalized logical item
  • support tail, before-seq, and after-seq queries from storage
  • stop treating provider history hydration as the normal refresh/load path
  • keep provisional live updates in memory only

Exit gate:

  • committed history survives daemon restart
  • reconnect uses committed catch-up plus future live events without gaps or duplicates
  • unloaded agents can serve committed history from storage alone

Phase 5: Legacy cleanup

Goal: Remove compatibility paths after the DB-backed model is fully authoritative.

Required work:

  • remove legacy JSON authority for structured records
  • remove in-memory committed-history ownership
  • remove provider-history rehydrate compatibility paths
  • trim dead protocol and reducer logic from the pre-storage model
  • update architecture docs to match the final model

Exit gate:

  • there is one durable storage path for structured records
  • there is one durable storage path for committed timeline history
  • the runtime no longer depends on the removed JSON/in-memory model

Data model summary

Projects

  • integer primary key
  • directory is unique
  • display_name
  • kind: git | directory
  • optional git_remote
  • timestamps and archive state

Workspaces

  • integer primary key
  • belongs to a project by project_id
  • directory is unique
  • display_name
  • kind: checkout | worktree
  • timestamps and archive state

Agent snapshots

  • agent_id remains the primary key
  • belongs to a workspace by integer workspace_id
  • workspace_id is required
  • timestamps, lifecycle state, persistence metadata, attention metadata, archive state

Timeline rows

Target shape once Phase 4 lands:

  • agent_id
  • committed seq
  • committed timestamp
  • canonical finalized item payload

Not part of durable history:

  • raw streaming chunks
  • provisional assistant text
  • provisional reasoning text

Verification requirements

Every remaining phase should keep the same bar:

  • npm run typecheck
  • targeted tests for the touched storage/session/runtime paths
  • migration/import coverage when storage authority changes
  • reconnect and catch-up scenario coverage when timeline behavior changes

At minimum, timeline cutover must explicitly prove:

  • fetch-after-seq
  • fetch-before-seq
  • restart durability
  • no-gap/no-duplicate reconnect behavior

Main risks

  • timeline work reintroduces provider-history replay as hidden authority
  • archive behavior diverges between stored records and live in-memory agents
  • explicit creation work leaves the transitional cwd fallback in place too long
  • cleanup stalls after compatibility paths stop being exercised

Rule of thumb

If a new change needs to ask "what can we infer from this cwd?" for project or workspace identity, it is probably moving in the wrong direction.