Skip to content

docs(architecture): version-history design ADR + codebase inventory (#362)#212

Merged
ikrasovytskyi merged 1 commit into
mainfrom
docs/362-version-history-adr
Jul 25, 2026
Merged

docs(architecture): version-history design ADR + codebase inventory (#362)#212
ikrasovytskyi merged 1 commit into
mainfrom
docs/362-version-history-adr

Conversation

@ikrasovytskyi

Copy link
Copy Markdown
Contributor

Design + codebase-inventory ADR for the version-history initiative (#321), gating the C2–C5 build (#363–#366). Docs only — no feature code. Adds docs/architecture/version-history.md and indexes it from CLAUDE.md per the repo ADR convention.

Chosen model

Field-level change-event log (record_field_changes) — one row per changed field per write — each badged by source (human/agent/automation/mcp) via the #330 AgentPrincipal. Debounced whole-content rich-text snapshots (document_versions, snapshots over patches). Whole-record restore first, per-field revert a documented fast-follow off the same log. Structural undelete extends the #229 trash to databases/views/spaces. Scope is history/restore, not point-in-time workspace backup (that's #320 export / #322 backup).

Locked founder decisions the ADR is built around

  • Retention (paid-only): Free = none (capture off) · Pro = 1 day · Business = 7 days · Enterprise = 30 days. Self-hosted = unlimited. Recommendation: on Free don't capture (window is zero ⇒ capture-then-prune is pure write-amp).
  • Attribution: every change badged by source via AgentPrincipal (#330).
  • Rich-text: snapshot on save, debounced.
  • Revert: whole-record restore first; per-field revert fast-follow.

Key inventory findings (what already exists)

  • MN-231 / PR feat(records): record version history — snapshot + restore (MN-231) #115 shipped whole-record snapshots + list/restore: record_versions table (full prior values+title per write), transactional capture in RecordsService.update(), and RecordVersionsController (GET …/versions, POST …/versions/:id/restore, reversible). C2–C5 EXTEND this, they do not replace it — it's the whole-record restore substrate and C3's backend.
  • MN-027 activity_events already holds a display-shaped diff per update but no queryable per-field rows and no source label.
  • Attribution gap: the write path stores only actorId (a user id); agent/automation/human writes are today indistinguishable. auth.via, AgentPrincipal, and the automation/MCP call sites exist, but source is net-new plumbing through RecordsService.update/create.
  • Soft-delete is partial: records/fields/space_documents/comments have deleted_at; databases/views/spaces do not — structural undelete (C5) closes that. No hard-"Erase" endpoint or trash purge cron for records today.
  • Plan gating reusable as-is: BillingService.getStatus + EntitlementsService (self-host short-circuits to unlimited); retention windows belong on PlanDef in plans.ts.
  • Rich-text has no historydocuments/space_documents carry only an optimistic-concurrency version int; C4 is fully net-new.
  • Pruning job MN-231 deferred lands with C2 (prunes all three history tables, set-based per plan tier).

Recommended build order

C2 (#363) field-level capture + source plumbing + pruning job (extends MN-231; land with a write-path benchmark) → C3 (#364) whole-record restore UX + source badges (backend already exists) → C4 (#365) rich-text document_versions (debounced snapshots) → C5 (#366) structural undelete (deleted_at on databases/views/spaces). One migration in flight at a time (hard rule #1) — these serialize.

Risks / open decisions flagged for the founder

Write amplification (mitigated by short retention + Free=off + batched inserts), rich-text snapshot size, relation revert semantics (relations live in record_links, not values — a whole-record restore leaves relations untouched), avoiding double-counting agent writes, and activity_events retention (separate from the paid history feature — product call).

Verification: pnpm docs:check (0 broken links) and pnpm lint both pass locally. Docs-only; no SDK/migration surface touched. Workers Builds: storyos-docs is informational.

Refs #321. Part of #362.

…#362)

Design + codebase-inventory ADR gating the version-history build (C2-C5,
#363-#366) for initiative #321. Docs only; no feature code.

Chosen model: field-level change-event log (record_field_changes), one row
per changed field per write, each badged by source (human/agent/automation/
mcp) via the #330 AgentPrincipal; debounced whole-content rich-text snapshots
(document_versions); whole-record restore first with per-field revert as a
documented fast-follow. Retention is plan-gated and tiny (Free none, Pro 1d,
Business 7d, Enterprise 30d), Free = capture off. Structural undelete extends
the #229 trash to databases/views/spaces. Scope is history/restore, NOT
point-in-time workspace backup (#320/#322).

Inventory: MN-231/PR #115 already shipped whole-record record_versions +
list/restore API (RecordVersionsController) and the transactional capture hook
in RecordsService.update() — C2-C5 EXTEND this, they do not replace it. The
field-level log, source attribution, rich-text history, structural undelete,
and the (MN-231-deferred) pruning job are additive.

Indexed from CLAUDE.md per the repo ADR convention.

Signed-off-by: ikrasovytskyi <i.krasovytskyi@owox.com>
@ikrasovytskyi
ikrasovytskyi enabled auto-merge July 25, 2026 20:55
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
storyos-docs a27f706 Commit Preview URL

Branch Preview URL
Jul 25 2026, 08:55 PM

@ikrasovytskyi
ikrasovytskyi added this pull request to the merge queue Jul 25, 2026
Merged via the queue into main with commit d41f631 Jul 25, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant