# Milestones

## v1.6 Tag System Completion & Authoring Polish (Shipped: 2026-07-02)

**Phases completed:** 7 phases (31–37), 7 plans — two tracks (T: tag-system completion; E: authoring polish)
**Git range:** `b45879f..4b5c71f` on `main` (build), closed at `248e401`
**Audit:** [`milestones/v1.6-MILESTONE-AUDIT.md`](milestones/v1.6-MILESTONE-AUDIT.md) — **COMPLETE** (all 9 requirements TF-01…05 + EP-01…04 met against code reality; grounded in a direct re-read of the system + re-run suites, not the phase SUMMARYs)

**Key accomplishments:**

- **Bulk multi-tag operations (Phase 31, TF-01):** `handleTagBulk` + `POST /admin/tags/bulk` (admin-RBAC + nosurf) routes N pages → **1** byte-stable commit through the EXISTING `buildTagApplyItems` + `ApplyTagsBatch` seam (frontmatter-only, no body rewrite); `computeBulkTags = (current ∪ add) \ remove`; page set re-resolved server-side; added tags re-validated (`ValidateTagCharset`); per-page stale (409) excluded without sinking the batch; `ActionTagBulk` audited. No new write path.
- **Tag metadata store — color/description (Phase 32, TF-02):** a NET-NEW committed on-disk store `internal/tagmeta/` — `Tags/{tag}.md` frontmatter (co-driver-chosen shape over `.okf-workspace/tags.json`) via the SEC-01 resolver + single-writer commit; `tag_meta` rebuildable SQLite cache + migration `0011` (delete-cache→rebuild=identical, `TestRebuildParity`); `handleTagMeta` + `POST /admin/tags/meta`; `ValidateColor` (hex/palette subset, rejects url()/var()/expression) + `ValidateDescription` (single-line, ≤200, HTML-safe); `HashtagWidget` applies color via `span.style.color` (createElement+textContent, NO innerHTML — XSS invariant held); `Tags/` skipped by page-tree + graph/search rebuilds. Files-as-truth preserved.
- **Tag hierarchy (Phase 33, TF-03):** `Meta.Parent` + migration `0012`; `CheckCycle` (O(depth) walk, cap 100, rejects self/indirect cycles; non-existent parent = root) runs before write (400 on cycle); grouped admin rendering (roots→children, alphabetical). Display-only — zero page bytes changed by a hierarchy edit; rebuild parity holds with parent.
- **Tag usage analytics (Phase 34, TF-04):** `handleTagAnalytics` + `GET /admin/tags/analytics` (read-only) reuses `graph.TagPageCounts` + a lightweight `TaggedPageCount`; AnalyticsPanel with summary cards, sortable per-tag table, most/least/orphans, and a scope note. No new heavy scan.
- **Tag-operation undo (Phase 35, TF-05):** migration `0013` (co-driver-chosen dedicated SQLite op-journal over the metadata store); `journalOp` hooked into all 4 handlers records `{op_type, op_detail, pages:[{path, pre_op_tags, body_affected}]}`; `handleTagUndo` + `POST /admin/tags/undo` reads the last row, builds inverse items, reads FRESH revisions (TOCTOU-safe), replays via `ApplyTagsBatch`; forward-commit (never a history rewrite); undo journals itself (undo-of-undo=redo); `ActionTagUndo` audited. **Honest limitation surfaced (not hidden):** delete body-`#tag` bytes are not invertible (`RewriteHashtags` removed the span) — undo restores frontmatter tags; body self-heals on next edit.
- **Rendering polish (Phase 36, EP-01/02/04):** EP-01 `web/src/lib/remark-hashtag.ts` renders body `#tag` as a **sanitized hast `span`** (typed element, NOT raw HTML) in the two `MarkdownProse` surfaces (`HistoryPanel` + `AgentAnswer`) — `rehype-raw` OFF / `rehype-sanitize` ON preserved, AgentAnswer stored-XSS test still passes, false-`#` cases stay literal. EP-02 copy-to-clipboard button on the read-mode `CodeBlockWidget` (`createElement`+`textContent`, `navigator.clipboard` w/ fallback, `user-select:none` so select-all excludes "Copy"). EP-04 frontmatter `description` indexed (keyword, no relevance change) + returned (`omitempty`) + rendered in `SearchResultRow`; absent falls back to today's card.
- **Insert-at-cursor templates (Phase 37, EP-03):** `TemplatePicker` + `PageEditor.insertTemplateAtCursor` lists via `listTemplates`, fetches body via `getPage`, substitutes `{{title}}/{{date}}/{{time}}` client-side, inserts via a normal CM6 `replaceSelection` transaction (`externalSeed` NOT used — it's a user edit). Byte-stability preserved by construction.

**Quality gates at close:**

- Every phase: engineer built → independent **qa** goal-backward verification (7 VERIFICATION.md on disk, all passed); gaps routed UP to the architect (judge≠doer held). Phase-36's three unrelated features verified independently per red-team MIN-05.
- Independent milestone **security review** (`.planning/v1.6-SECURITY-REVIEW.md`) — **SHIP**, 0 high/medium/low; 1 informational (copy-button "Copy" leak into `<pre>.textContent`) found + closed in-milestone. Supply chain clean: zero new Go deps, zero new npm deps across the whole range.
- **The architect's close-time full-suite smoke was the net:** three regressions escaped the per-phase scoped runs (copy-button DOM ×2 — `livePreview` + `widgets.adversarial` INV-2; Phase-33 alphabetical sort vs v1.3 position-based `TagManagement` selectors) and were caught + fixed (`1653933`, `e17dbca`, `4b5c71f`). **Lesson banked:** a phase touching a shared component should run that component's FULL existing suite, not just its new tests.
- Final suites at build HEAD `4b5c71f`: `go build ./...` exit 0; `go test ./...` 19 packages ok / 0 failures; `cd web && npx vitest run` 66 files / **815 tests** passed; `npx tsc --noEmit` exit 0. Working tree clean. Docs + codebase maps refreshed (new `MAP-tagmeta-subsystem.md` + `MAP-page-templates.md`; independent drift-check ZERO findings).
- **Substrate note:** SMTC daemon OFFLINE + native agent-teams spawn unavailable this run — spans delegated via the `task` tool; cert tiers capped at Structural/Empirical (never Decision-tier). The gates genuinely occurred — 7 VERIFICATION + 1 SECURITY-REVIEW + 1 MILESTONE-AUDIT artifacts on disk.

**Known deferred items at close:** TipTap rich-block editor (track R, phases 38–41) **split to v1.7** by the independent roadmap red-team (SPLIT-REQUIRED, co-driver-accepted) — R requirements + red-team findings preserved in `REQUIREMENTS.md` §R so v1.7 starts warm. TF-05 delete-body-`#tag` byte-inversion (self-heals on edit; git history retains originals). Carried from v1.5/v1.4: global JSON body `MaxBytesReader` cap (F-02), pin mermaid deps + CI `npm audit` (F-01), `govulncheck` re-run when the Go 1.26 toolchain panic is fixed.

---

## v1.5 Tag Regression Fix, Reading-Shell Fold-In & v1.3 Closure (Shipped: 2026-07-01)

**Phases completed:** 3 phases (28–30), an assess-and-fix milestone
**Git range:** `95ca67d..HEAD` — 22 commits on 2026-07-01
**Audit:** [`milestones/v1.5-MILESTONE-AUDIT.md`](milestones/v1.5-MILESTONE-AUDIT.md) — COMPLETE (all 3 intents met against code reality; central drift risk retired with a CI-enforced offset-parity gate)

**Key accomplishments:**

- **Reading-shell fold-in (Phase 28, RS-01…04):** committed a ~65-file uncommitted Obsidian-parity refactor as a verified-before-committed baseline — reading column as a document (Breadcrumb + PropertiesPanel + DocStatusBar; TagBadgeBar retired), ⌘K modal search → inline navrail full-text search (NavSearchResults + navSearch), per-page local graph removed end-to-end (global `/app/graph` retained), CM6 selection/coordinate fix (heading margin→padding height-oracle + drawSelection + lineWrapping) as its own revertable commit. Nav-search test gap closed; scope reductions documented with future re-intro paths; CM6 change confirmed in a real browser (deterministic posAtCoords↔coordsAtPos round-trip).
- **Tag-regression fix, server-authoritative (Phase 29, TR-01…06):** a NEW code-region-aware `okf.RewriteHashtags` body-`#tag` rewrite primitive (modeled on `okf.RewriteLinks`), pinned to the TS Lezer grammar by an **offset-level, single-sourced, CI-enforced parity test** (independently confirmed to fail on drift). `okf.ValidateInlineTag` validator; rename/merge/delete now rewrite body `#tags` + frontmatter in one byte-stable batched commit (body-only pages included; TOCTOU-safe body channel); body-inclusive enumeration in the pages service (`PagesWithBodyTag`, SEC-01-resolver-gated, graph layer's no-body invariant intact); TR-06 stale-body detect+report (`DetectStaleBodyTags`); preview surfaces body-rewrite scope. Closes the confirmed regression where v1.4's inline-`#tag` materialization silently reverted v1.3 tag ops.
- **v1.3 closure (Phase 30, TC-01…03):** the closure v1.3 Tag Management never received — independent qa verification of TM-01…05 + the integrated fix (30-VERIFICATION.md, PASSED), independent security review of the tag-admin + body-rewrite + enumeration surface (v1.5-SECURITY-REVIEW.md, SHIP, 0 critical/high), and planning-doc reconciliation (v1.3 shipped `9de5077`, closed retroactively in v1.5 — no longer "deferred"; archive annotated).

**Quality gates at close:**

- Each phase independently verified by a different role than built it (engineer→qa; build→security); gaps routed UP to the architect and dispositioned (judge≠doer held throughout). Phase-28 qa PASSED (no coverage loss); Phase-29 qa PASSED (drift-fails-CI confirmed via corpus perturbation); Phase-30 qa PASSED (v1.3 TM-01…05 + holistic).
- Independent milestone **security review** (`.planning/v1.5-SECURITY-REVIEW.md`) — **SHIP**, 0 critical/high; block-on-high not triggered. 1 LOW fixed (SEC-v1.5-F01 nested-tag target 500→400), 1 LOW tracked (F-02 uncapped JSON body — folded into v1.4-F02), 1 INFO (F-03 govulncheck env panic — zero new Go deps).
- Final suites at HEAD: `go build/vet/test ./...` — 18 pkgs ok; web **804 tests / 65 files**; `npm run build` clean with `assertLazyChunks` active. `anvil-cc debt query` = debt=0.
- **Substrate note:** SMTC daemon OFFLINE + native agent-teams spawn unavailable this run — spans delegated via the `task` tool; typed `gate_result` ledger emission inactive (so `measure refusal-rate` reads 0 gates), but the gates genuinely occurred — four verdict-bearing VERIFICATION/SECURITY artifacts on disk, two recording fail→fix→pass loops. Cert tiers capped at Structural/Empirical.

**Known deferred items at close:** SEC-v1.5-F02 / v1.4-F02 (global JSON body `MaxBytesReader` cap), F-01 (pin mermaid deps + CI `npm audit`), `govulncheck` re-run when the Go 1.26 toolchain panic is fixed, the TC-01 LOW (a dedicated rename conflict/dedupe seeded test), and the v1.3-original deferred tag features (bulk multi-tag, metadata, hierarchy, undo, analytics).

---

## v1.4 Editor Enhancements & Authoring Polish (Shipped: 2026-07-01)

**Phases completed:** 7 phases (21–27), 7 plans
**Git range:** v1.0..HEAD — 91 commits over 2026-06-27 → 2026-07-01
**Audit:** [`milestones/v1.4-MILESTONE-AUDIT.md`](milestones/v1.4-MILESTONE-AUDIT.md) — passed (7/7 phases qa-verified, every ED-01…ED-06 requirement delivered, security review SHIP)

**Key accomplishments:**

- **Inline `#tag` parser + badge render (Phase 21, ED-02a):** a `@lezer/markdown` `Hashtag` inline parser + a badge decoration rendering `#tag` on the CM6 live-preview surface (a purely additive client-side parser — the server's Goldmark never sees a `#tag`; decoration-only, so stored bytes are unchanged).
- **Model-B tag materialization + tag UI (Phase 22, ED-02b/02c):** on save, body `#tags` reconcile into the canonical frontmatter `tags:` **client-side** (frontmatter-canonical model); a read-only `TagBadgeBar` shows effective tags. Indent-/quote-hardened tag I/O.
- **LLM tag suggestions (Phase 23, ED-03a):** the shipped suggest→approve flow re-homed into the live editor with union de-dup over the LIVE body+frontmatter, applied via the server apply-tags path, with an **autosave-safe merge-first reconcile** — the load-bearing pattern (merge approved value into local frontmatter BEFORE the post-apply refresh) that Phase 24 reused.
- **LLM-generated description (Phase 24, ED-01a/01b):** removed the manual Description input; an on-demand, never-auto agent generator (`GenerateDescription` single-shot read-only mode + generate/apply-description endpoints, editor+CSRF, server re-validation, byte-stable `okf.SetField`, revision-checked 409) with an editable/regenerable review surface and the shared merge-first `reconcileApplied`.
- **Code syntax highlighting (Phase 25, ED-04a):** ONE shared theme-aware `HighlightStyle` (new `--syntax-*` tokens) drives both CM6 surfaces — the editor via `syntaxHighlighting`, the read `CodeBlockWidget` via `highlightCode` (token spans built `textContent`-only). The 12-language curated set is **code-split**; the read widget renders plain then re-highlights when the lazy grammar resolves. Shipped the reusable `assertLazyChunks` build guard (module-id-level) proving no per-fence grammar reaches the entry chunk.
- **Mermaid diagrams (Phase 26, ED-05a):** ` ```mermaid ` blocks render as inline SVG on **read + live** (Obsidian-style active-line reveal) via a lazy-loaded, strict-sandboxed `MermaidWidget` (`securityLevel:'strict'` + `suppressErrorRendering`, SVG injected via DOMParser+appendChild — never `innerHTML` of page content), with a raw-code fallback on any parse/render error. `assertLazyChunks` extended to prove mermaid + its heavy dep tree (d3/dagre/cytoscape/katex/…) stay out of the entry chunk.
- **Page templates (Phase 27, ED-06a):** new pages seed from Obsidian-style `.md` templates in a `Templates/` folder — a list endpoint + a create-page picker (blank default), client-side `{{title}}`/`{{date}}`/`{{time}}` substitution, and a **robust server-side frontmatter merge** via `okf` (single valid block, user title wins, required-field repaired). `okf.ValidateFrontmatter` fail-closes on duplicate-key/malformed YAML.
- **Close-time fix:** `encodePagePath` now segment-encodes page paths across all client API URLs (`web/src/lib/url.ts`), fixing a pre-existing app-wide raw-interpolation bug for `#`/`?`/`%` filenames.

**Quality gates at close:**

- Every phase ran the engineer's `anvil-code-reviewer` + `anvil-adversarial-tester` gates AND an independent `qa` goal-backward verification — all **passed**, zero gaps. Adversarial highlights: P25 held under 40 attacks (2 defects fixed), P26 49 tests/0 defects, P27 39-case table + `FuzzTemplateMerge` ~279k execs/0 defects.
- Independent milestone **security review** (`.planning/v1.4-SECURITY-REVIEW.md`) — **SHIP**, no critical/high; 2 LOW findings accept-for-ship (mermaid XSS defense delegated to upstream strict+DOMPurify — verified sound; unbounded `POST/PUT /pages` JSON body — pre-existing, add a global cap).
- Final suites: `go build/vet/test ./...` green; web **785 tests / 64 files**; `npm run build` clean with the bundle assertion active. Docs + codebase maps refreshed with a doc-verifier pass.

**Known deferred items at close:** F-02 (global JSON body cap — DoS hardening), F-01 (pin mermaid deps + `npm audit` in CI), 2 Phase-26 manual UAT items (concurrent multi-diagram render; embedded-script inertness), a `blast_radius` re-run for the 2 new CM-editor maps when SMTC is back, and the REQUIREMENTS "Future" features (`#tag` in react-markdown, copy-code button, insert-at-cursor templates, description in search cards).

---

## v1.0 Knowledge Graph & LLM Auto-Tagging (Shipped: 2026-06-24)

**Phases completed:** 5 phases, 14 plans, 34 tasks
**Git range:** v0.9.9..HEAD — 85 commits over 2026-06-23 → 2026-06-24
**Audit:** [`milestones/v1.0-MILESTONE-AUDIT.md`](milestones/v1.0-MILESTONE-AUDIT.md) — passed (14/14 requirements, 5/5 integration seams, security review passed)

**Key accomplishments:**

- **Derived link/tag store (Phase 8, LINK-01/03):** a new `internal/graph` package with SQLite `page_links`/`page_tags` derived-cache tables and a `KindGraph` job (cloning `search.KindIndex`) wired into the single jobs worker beside search at every one of the eight page-mutation sites — kept fresh incrementally, fully rebuildable from on-disk `.md` files (byte-identical adjacency, `-race` clean), with an admin `POST /admin/graph/reindex` backstop. Never source of truth.
- **Graph endpoints + backlinks (Phase 9, LINK-02):** a read-only query layer (`GraphData`/`Neighborhood`/`Backlinks`) exposed as three authed reads (`/graph`, `/graph/local`, `/graph/backlinks`) returning a lean bipartite typed-edge payload with a popular-tag hairball cap, plus a collapsible "Referenced by (N)" backlinks panel on the page read view.
- **Obsidian-style graph UI (Phase 10, GRAPH-01..05):** a lazy-loaded `/app/graph` global force-directed view (single Canvas-only `react-force-graph-2d` dep, code-split into its own chunk; three.js provably absent) — degree-sized nodes, orphan distinction, edge-type toggle chips (shared-tag OFF by default), hover-neighbor highlight, click-to-open — plus a per-page collapsible Local-graph dock with a 1/2/3-hop depth control.
- **Per-page LLM tag suggestion (Phase 11, TAG-01..04):** a byte-stable `okf.SetTags` frontmatter primitive (`yaml.Marshal`, only the `tags` region changes) feeding an on-demand suggest→review→approve chain through the existing single-writer commit path — vocabulary-biased, capped at 5, normalized on write, stale-revision 409, model output always re-validated server-side. Live-verified end-to-end against real DeepSeek.
- **Bulk sweep + batch review queue (Phase 12, TAG-05/06):** an admin bulk untagged-pages sweep that enqueues per-page `KindTagSuggest` jobs on the async worker (writing nothing automatically) into a review queue, approved per page through the SAME byte-stable apply path with batched commits (N pages → 1 commit), per-page stale 409 that doesn't sink the batch.

**Quality gates at close:**

- Independent cross-phase integration check — `integration_ok` (5/5 seams wired, both E2E chains connect; `go build ./...` + `tsc -b` green).
- Independent v1.0 security review (ASVS L1, block-on-high) — **passed**, zero HIGH/CRITICAL; all declared mitigations (path resolver on graph paths, server-side `ValidateTags`, byte-stable `SetTags`, session RBAC, stale-revision 409) confirmed in code. 3 informational hardening notes only.

**Known deferred items at close: 3** (see STATE.md Deferred Items) — P10 canvas-pixel visual UAT (human browser), optional GraphCanvas bundle lazy-load, and the standing-team `docs/` refresh (security review was run; docs deferred by choice).

---

## v0.9.9 MVP (Shipped: 2026-06-23)

**Phases completed:** 8 phases, 36 plans, 82 tasks

**Key accomplishments:**

- A single CGO-free Go binary that bootstraps an admin (one-time logged password), serves an embedded React login -> AppShell, and authenticates against SQLite via Argon2id with SCS HttpOnly+SameSite sessions and nosurf CSRF.
- The load-bearing storage + safety floor: a fuzz-tested single safe-path resolver (SEC-01), a mutex-serialized single-writer Git commit service with stale-lock self-heal and ff-only pull, a SQLite-persisted async job-worker spine, and a first-run seed that commits the SPEC §9 starter layout through the Git service — with repo health surfaced in the AppShell.
- Server-side `RequireRole` RBAC enforced from the session (never client input), an admin user-management screen + API (create / set-role / reset / deactivate), self-service profile that can change everything but the caller's own role, a forced first-login password change that gates the app, a logout control reachable from any page, and a CLI `admin reset-password` recovery path — plus a verification-found Dialog caret-stealing bug fixed.
- The cross-cutting security floor and the self-host delivery vehicle: a write-only SEC-05 audit log that dual-writes every key Phase-0 action to a SQLite `audit_log` mirror AND a structured slog line (never recording a secret, never able to break a request), the completed SPEC §20.3 config schema with deployment env overrides and a redacted-on-print resolved LLM API key, and runnable systemd + multi-stage Docker packaging that builds a non-root, CGO-free single static binary + data directory.
- Delete is now a recycle bin, not destruction: deleting a page git-mvs it into `.okf-workspace/trash/` as a real hidden commit (D-08) with full provenance (original path + who + when, D-10), and restore moves it back to its original folder — auto-suffixing `(restored)` when a live page already occupies that name so a live page is never clobbered.
- End-to-end attachment slice: editor drag-drops a file → server caps + MIME-sniffs it, assigns a ULID, writes binary + JSON meta sidecar through the existing single-writer CommitJob in one commit, and the file downloads byte-for-byte with the SEC-02 disposition — plus the internal/attachments foundation (types/id/meta/refs/service) for slices 02-02/03/04.
- Turned the minimal 02-01 filename card into the full ATT-03 attachment card (64×64 image thumbnail or lucide type icon, emphasised filename, human `size · uploader · date` meta line, Download) and added ATT-04 inline image preview: clicking an image thumbnail opens a focus-trapped full-size Dialog that renders the image via `<img src>` only, so an uploaded SVG cannot execute script — pinned by a dedicated inline-disposition test.
- Async PDF/DOCX/TXT text extraction (ATT-08): a new `KindExtract` job on the existing single jobs worker reads the committed binary with pure-Go parsers (`ledongthuc/pdf` / `fumiama/go-docx` / stdlib), recovers any parser panic so one bad file can't kill the drain goroutine, and commits the (possibly empty) `<id>.txt` sidecar through the one `KindCommit` path — surfaced live to the card via an SSE endpoint and an `ExtractionStatus` chip that distinguishes the non-alarming empty-but-succeeded "No text extracted" case (scanned PDF → `status=empty` + empty `.txt`) from a genuine "Couldn't extract text" failure (`status=failed` + no `.txt`).
- Closed the attachment lifecycle loop: an editor can Replace an attachment (ATT-05 — the SAME opaque ULID id is reused, the new bytes + updated meta are written through the existing single-writer CommitJob in one commit so the prior version is retained in history, and text is re-extracted), and Remove an attachment's link from a page (ATT-06 — the canonical `DownloadRefPath(id)` link is stripped from the page Markdown); when the removed link was the LAST reference across ALL pages, the binary + JSON meta + TXT sidecar are deleted in ONE commit (ATT-07), while a file still referenced by another page is never deleted — all behind editor-only, focus-trapped confirm dialogs with the "Replace file"/"Remove file" labels and hidden-Git retention copy.
- Completed search coverage: attachments findable by original filename and by extracted text (linking to the OWNING page), page headings findable and deep-linking to the rendered section — via a new ATX heading scanner whose GitHub-style anchors match rehype-slug byte-for-byte, with page_headings-backed stale-heading cleanup verified against the real SQLite schema.
- Wired the INCREMENTAL search layer: every page mutation (create/save/createfolder/rename/move/delete/restore), every attachment mutation (upload/replace/orphan-remove), and the extraction-done handler now enqueue a fire-and-forget `search.KindIndex` job so search stays live with the workspace without a restart — with a named CR-01 test proving the extraction-done re-index never deadlocks the drain goroutine, a `-race` concurrency test proving reads and writes don't race, and an admin "Rebuild search index" button wired to the existing reindex endpoint.
- The four single-shot modes (Summarize page/attachment, Rewrite selection, Draft new page) wired via direct `ChatModel.Generate` with a 60s timeout + per-mode token caps, plus the `validateProposedBody`+retry body-output contract that rejects fenced/empty/frontmatter-mangled bodies — all proven by a key-free `TestDispatch` with a fake model.
- `ProposePatch` returns the FULL proposed new body plus the page revision captured at proposal time; `/propose-patch` (editor) hands the frontend `{old_body, new_body, base_revision}` for a real diff; `/apply-patch` (editor + CSRF) is a SEPARATE non-tool endpoint that re-validates the body then reuses `pages.Save(baseRevision)` → the single-writer `gitstore.Commit(approved_agent_patch)`, blocking a moved revision with a 409 — proven by a key-free D4 round-trip/churn test and a D8 stale-revision-409 test, with the read-only 5-tool allow-list (TestToolSet) unchanged.
- The user-facing half of the Eino agent: a persistent bottom PromptBar (mode + auto-context + Whole-workspace toggle + fail-closed disabled states), a right-side collapsible AgentPanel/AgentAnswer that streams the answer token-by-token through the sanitized MarkdownProse surface (no stored XSS) over a net-new POST-body fetch-stream SSE reader, and the load-bearing DiffReviewDialog trust gate — a REAL diff (react-diff-viewer-continued, never prose) whose Approve is accent-primary but deliberately NOT auto-focused, whose stale state removes Approve, and whose 409 from /apply-patch surfaces the "page changed — re-run" block — wired into AppShell with editor-gated propose/apply react-query mutations and exactly one additive token.
- Frontend-only wiring that makes AGNT-02/03/06/07 reachable: a new ephemeral agentContext store carries the live CM6 selection and the chosen attachment up to the AppShell agent session, which now dispatches rewrite through DiffReviewDialog (never auto-applies), selection-scope Ask, attachment-scope Ask, and summarize-attachment.
- Server-authoritative, file-backed, clock-injected soft-lock store (`internal/locks`) with a deterministic 7-test suite, a `lock_gc` reaper job, `SessionConnectionIDKey`, and a ctx-gated GC ticker wired into `main.go` — the COLL-02 foundation for soft locks and presence.
- Per-page editing presence delivered end-to-end: a GET `.md/presence` SSE stream that pushes a full editors snapshot every ~2s from the soft-lock store (`lockStore.EditorsFor`) with a `ctx.Done()` teardown + absolute max-duration cap so a forgotten tab can't leak a goroutine, consumed by a `subscribePresence` EventSource and rendered as the quiet, muted, aria-live `PresenceIndicator` in the editor toolbar — "{name} is editing", connecting/reconnecting states, never showing your own session — additive to and non-clobbering of Plan 02's lock lifecycle.
- Swapped PageEditor's @uiw/react-md-editor for a CodeMirror 6 surface (LivePreviewEditor) with a byte-stable persisted Live/Source toggle (Compartment + Cmd/Ctrl-E), GFM-only markdown config, token-only theme, and the whole phase's Wave-0 test scaffolds + pure security/anchor gates.
- A CodeMirror 6 live-preview ViewPlugin that walks the Lezer markdown tree over the visible ranges and renders headings/bold/italic/inline-code/fenced-code/links inline as you type — hiding the syntax markers everywhere except the active line (Obsidian-style, layout-neutral reveal), with the decoration classes themed to match read mode byte-for-byte.
- Completes EDIT-01's render set with sanitized inline image widgets and a GFM-table block grid, plus internal `.md` link click-navigation on the CodeMirror 6 surface — every widget built from createElement+textContent (no innerHTML) and every image src / link href passed through the 06-01 scheme allowlists (EDIT-04).
- Unifies read mode onto the CodeMirror 6 live-preview surface (a read-only `LivePreviewEditor`, pixel-identical to edit Live) while preserving the search→heading deep-link via `headingAnchors` line decorations that stamp each heading with its github-slugger id (matching `okf.ScanHeadings` byte-for-byte) plus a scroll-to-`#hash`-on-mount effect — and removes the legacy `@uiw/react-md-editor` dependency.
- Atomic folder rename/move that relocates a dir/index.md plus every descendant and rewrites all inbound links in ONE byte-stable commit, rejecting target-dir collisions with a clean 409 (ErrFolderExists) before any disk write.
- Grouped folder delete/restore layered on the existing per-page trash: a nullable `delete_group_id` (migration 0008) tags every row of one folder delete; `DeleteFolder` loops the existing per-page delete under one crypto/rand group id, and `RestoreGroup` loops the existing per-page restore index.md-first with per-page collision auto-suffix — per-page delete/restore stay byte-identical (group NULL).
- Pinned the Clean-Rebuild Behavior Inventory as a 22-test regression net GREEN against the current components, then cleanly rebuilt LeftTree, TreeContextMenu, RenameModal, and MoveDialog (decomposed into focused sub-components + hooks, dialogs parameterized by node kind) with zero shipped-behavior regression and no new folder feature.
- Layered the net-new folder operations onto the Plan 03 base: a centralized optimistic `["tree"]` mutation hook (onMutate snapshot → applyMove → onError rollback → onSettled invalidate) whose pure `applyMove` mirrors the server's literal prefix swap, native folder drag-and-drop with a dragover-time self/descendant/same-parent guard, the 5-action folder context menu wired to the 07-01/07-02 backend, a `DeleteFolderDialog` naming the affected page count N, and a grouped `TrashView` "Restore folder" row — all green against the 07-03 regression net with no new deps or tokens.

---
