39. Generated content keeps only its current version#
Date: 2026-10-28 (#425, #413)
Status#
Accepted. Partly supersedes 4. Originals are kept; everything else is derived, versioned or disposable (derived data is append-only) for a model’s readings of photos and files, 27. Claude’s write-ups of boards, apart from the text (versioned write-ups, Restore) and 28. Claude-maintained topic pages (a synthesis restores like a write-up). ADR 11, a drawing’s versions, History and Restore, is unchanged.
Context#
A board’s write-up, a topic’s synthesis and a model’s reading of a photo or file (its OCR text and
description) were each kept as numbered versions, the older ones superseded by triggers. Nobody
could see the readings’ history, and the write-ups’ was a Versions fold with Restore.
That history cost a table with immutability triggers, a second API, a fold in the PWA, a
restored_from exemption in three outdated checks, and large model_run payloads that retention
had to keep because an old row pointed at them. It bought little: a bad write-up is mended with
guidance and Regenerate, and a bad reading by Reprocess. The owner has no use for the old
generated text. The history of what a person wrote (page_rev, page_meta_rev,
page_trash_rev) and of a drawing is a different matter and stays.
Decision#
Write-ups and syntheses.
writeupholds one row per page (page_idis its primary key). Regenerate, and every write-up or synthesis the worker makes, overwrites it in place (INSERT ... ON CONFLICT (page_id) DO UPDATE), with its producer, run, prompt version, summary, text, the guidance it was written with and its time.writeup_guidanceis unchanged.Readings.
put_deriveddeletes the page’s last row of that photo and kind (ocrordescription) before it inserts the new one. The reading’s chunk goes with it (ON DELETE CASCADE), and the search entry through thechunk_adtrigger. Its version number goes on counting, so a first reading is still version 1.Drawings keep their versions.
derivedkindexcalidrawis untouched: saves, Claude’s redraws, a redraw kept non-current when the owner chose Keep mine, History and Restore (viewer,drawing.py, MCPbase_version). Drawings are not folded intopage_rev: a drawing belongs to a photo, not a page, andpage_rev.revis the page text’s edit token, so a drawing save would turn open editors away with a 409.Removed.
GET .../writeup/versions,POST .../writeup/restore,StaleWriteupError, the PWA Versions fold, Restore button andv2 · restored from v1byline, therestored_fromandsuperseded_atclauses, andversioninread’s write-up.Outdated. A write-up or synthesis is no longer exempt from
is:outdatedor the weekly topic pass because the owner restored it: there is nothing to restore.Migration 0019. Deletes superseded write-ups, drops the three triggers and two indexes, rebuilds
writeup(SQLite cannot drop a column that is in aUNIQUEconstraint) and deletes supersededocranddescriptionrows. A superseded row has no chunk already, so search is unchanged. No backup or check of the old versions is needed: the owner has no concern for them.
Consequences#
A bad Regenerate cannot be undone. Write guidance and Regenerate again.
A restored synthesis that has an old prompt version is remade by the next weekly pass.
Retention no longer keeps a
model_runfor a superseded reading: only for the current one, a drawing version or a write-up.Roughly 400 fewer lines, and one write-up row per page makes the queries plain.
The migration is irreversible, which is why 1.0 holds only the current generated content.