This document defines the behavior Marginalia must not regress.
Every review session should feel trustworthy:
- edits remain editable,
- saved notes stay attached or become clearly stale,
- recovery restores real working state,
- bundle output is explicit and versioned,
- the UI never invents state transitions on the user’s behalf.
- Diffing runs on rendered plain text.
- Visible changes exclude whitespace-only fragments that are not shown inline.
- Clicking inserted text must behave like normal editing.
- Only deletion affordances are click-intercepted in the manuscript.
- Selecting an edit must not automatically focus or reopen the rationale composer.
- Compose mode is explicit: button press or
⌘/.
Annotations are stable records with target metadata, not ephemeral UI state.
Each saved note must either:
- resolve exactly to the same change,
- reattach conservatively to one clearly best candidate,
- or become
stale.
Marginalia must never silently move a note when the remap is ambiguous.
- stable annotation ID
- prior change ID
- excerpt
- line hint
- surrounding line context
- block key
- the old change no longer exists,
- the best candidate is below the reattach threshold,
- or multiple candidates are too close to call.
- Persistent manuscript markers are rendered from resolved saved annotations only.
- Marker identity is keyed by annotation ID, not geometry.
- Marker stacking is grouped by resolved block, not rounded pixel buckets.
- Marker refresh must respond to document/layout changes, not every keystroke in the rationale UI.
Snapshots live under ~/.marginalia/sessions/.
Recovery should restore:
- original and edited content
- plain-text projections
- saved annotations
- selected change / selected annotation
- general notes
- in-progress rationale drafts
If highlight or diff subsystems fail, Marginalia should fall back to degraded mode and still capture final text plus notes.
Current output:
original.mdfinal.mdchanges.jsonannotations.jsonchanges.patchprovenance.jsonsummary_for_agent.md
Version markers:
changes.json.bundle_format_version = "3.0"annotations.json.schema_version = "3.0"provenance.json.schema_version = "1.0"
Default trigger behavior:
- file ends with
-draft.md, or - file contains
<!-- REVIEW -->, or MARGINALIA_REVIEW_REGEXoverrides both.
Operational guarantees:
- one active review at a time
- queued launches instead of window storms
- sync and async modes through the same hook
Run all of these before shipping:
pnpm run check:diffpnpm run check:annotationspnpm run check:semanticpnpm run check:bundlepnpm run check:hookpnpm run check:lintpnpm run checkpnpm run build
- Diff reconciliation is still heuristic in long sessions with many repeated similar edits.
- Richer structural anchoring may eventually need ProseMirror-step lineage, not just text-context scoring.
- Compact-layout compose/recovery flows need periodic real-device QA because they are easier to regress than desktop.