diff --git a/docs/03-data-model.md b/docs/03-data-model.md index 4c6c44a..9f634f7 100644 --- a/docs/03-data-model.md +++ b/docs/03-data-model.md @@ -16,7 +16,8 @@ Default root: `%LOCALAPPDATA%\WhispAssist\` (user-configurable, FR-STORE-2). └── \ # one folder per meeting (uuid) ├── audio.wav # canonical recording — present ONLY if "Record" was on (ADR-0009) ├── transcript.json # canonical transcript (segments+speakers+timings) - ├── notes.md # user-editable Markdown notes + ├── manual_notes.json # raw user-authored notes captured live during recording + ├── notes.md # the final notes document: manual notes + transcript, merged at finalize ├── summary.json # LLM summary, decisions, action items (if generated) └── briefs/ # feature briefs distilled from this meeting (ADR-0011), if any └── .json # agent-ready spec served via the MCP `get_feature_brief` tool @@ -24,9 +25,42 @@ Default root: `%LOCALAPPDATA%\WhispAssist\` (user-configurable, FR-STORE-2). Rule: while a meeting is in progress a working WAV is the source of truth for crash recovery. On finalize, it is **kept** as `audio.wav` if "Record this meeting" was on, or **deleted** if not -(FR-REC-1/4) — deletion happens only after `transcript.json` is finalized. `transcript.json`, -`notes.md`, and `summary.json` are **derived** and regenerable (regenerable only while the audio -still exists — i.e. for recorded meetings). +(FR-REC-1/4) — deletion happens only after `transcript.json` is finalized. `transcript.json` and +`summary.json` are **derived** and regenerable (regenerable only while the audio still exists — +i.e. for recorded meetings). + +`notes.md` is **generated once, at finalize**, by merging `manual_notes.json` (freeform notes +typed live during the recording, plus any per-moment annotations — see below) with the rendered, +speaker-tagged transcript (`notes::MarkdownNotes::merge`). After that it is the user's own +document, freely editable via `update_notes` exactly like before this changed — nothing +re-renders or overwrites it afterward. In particular, renaming or merging a speaker after finalize +updates the `speakers` table and the live UI display, but does **not** retroactively rewrite text +already baked into `notes.md` (same as any other manual edit isn't retroactively touched either — +this was a pre-existing clobber bug this redesign also fixes: renaming a speaker used to silently +overwrite the whole file). A crash-recovery finalize (T2.8) and a post-finalize batch +re-transcription (T3.8) both re-render `notes.md` from scratch and so both re-read +`manual_notes.json` from disk to fold the same manual notes back in. + +### `manual_notes.json` + +```jsonc +{ + "schema": 1, + "freeform_md": "string — the user's running notes, typed live in the Notes pane while recording", + "segment_notes": [ + { "anchor_ms": 12345, "text": "string", "created_at": 1735000000, "updated_at": 1735000010 } + ] +} +``` + +`segment_notes[].anchor_ms` is a timestamp into the recording (a clicked transcript segment's +`start_ms`), not a segment id — a later batch re-transcription can renumber/regenerate segment +ids, but never moves the moment in time a note was attached to. At merge time, each note is placed +right after whichever transcript paragraph's time span contains its `anchor_ms`; a note whose +anchor doesn't land inside any paragraph surfaces under an "Other notes" section instead of being +silently dropped. Written to disk on every edit via `update_live_notes`/`set_segment_note` +(`04-api-contracts.md`) — live-session only, same write-through-for-crash-safety spirit as +`transcript.json` accumulating during recording. ## SQLite schema (`wa.db`)