diff --git a/.agents/skills/ln-spec/SKILL.md b/.agents/skills/ln-spec/SKILL.md
index 89bcba06..23dfadf0 100644
--- a/.agents/skills/ln-spec/SKILL.md
+++ b/.agents/skills/ln-spec/SKILL.md
@@ -30,6 +30,20 @@ The feature or problem: $ARGUMENTS
Write or update `memory/SPEC.md` following the [spec template](assets/spec-template.md). If the file already exists, read it first — preserve existing content, evolve sections that need change.
+### Identifier scheme
+
+Before adding any new cross-referenceable item, derive the session's author suffix from the local user name: take `basename "$HOME"`, then uppercase its first character. Example: `/Users/lunelson` → `L`. Append this suffix to every new item identifier: `A47-L`, `D12-L`, `I47-L`, etc.
+
+When assigning the numeric part for a new item:
+
+1. Scan existing identifiers with the same prefix (`A`, `D`, `I`, requirement/oracle prefixes if present).
+2. Compute the next number from legacy unsuffixed IDs plus IDs with the same author suffix.
+3. Ignore IDs with other author suffixes for incrementing, so parallel sessions can safely produce `I47-L` and `I47-K`.
+4. Do not rename or renumber existing IDs just to add a suffix; only preserve and update them unless a deliberate cleanup is requested.
+5. Use the full suffixed ID in every cross-reference (`Depends on: D12-L`, `Proves: R3-L / D8-L`).
+
+If `$HOME` is unavailable or the basename is empty, ask the user for the suffix instead of inventing one.
+
### SPEC shape
Use the mature SPEC shape unless the existing project clearly predates it and the user only asked for a narrow patch:
@@ -86,9 +100,9 @@ Large cleanup is `ln-sync` work. When writing or patching, keep the touched area
Every amendment must close its reference chain as far as the current lifecycle stage allows. After editing, verify:
- **New requirement** → has: product capability area and PLAN/frontier references if it changes upcoming work
-- **New assumption** → has: dependent decision(s) or invariant(s), validation approach, and implicated frontier item(s) in `memory/PLAN.md` **if `memory/PLAN.md` already exists**
-- **New decision** → has: dependent assumption(s) where relevant, supersession note, and enough rationale to identify the chosen seam
-- **New invariant** → has: establishing frontier item in `memory/PLAN.md` **if known** (or scoped slice if already defined), protecting test/oracle (or `planned` / `manual (outer loop)`), proved decision or requirement
+- **New assumption** → has: suffixed identifier, dependent decision(s) or invariant(s), validation approach, and implicated frontier item(s) in `memory/PLAN.md` **if `memory/PLAN.md` already exists**
+- **New decision** → has: suffixed identifier, dependent assumption(s) where relevant, supersession note, and enough rationale to identify the chosen seam
+- **New invariant** → has: suffixed identifier, establishing frontier item in `memory/PLAN.md` **if known** (or scoped slice if already defined), protecting test/oracle (or `planned` / `manual (outer loop)`), proved decision or requirement
- **New future direction** → has: PLAN frontier/horizon pointer or design-doc pointer; not full acceptance detail unless already active
- **New constraint** → has: rationale for exclusion
- **New inner-loop oracle item** → names the invariant(s) it protects
diff --git a/.agents/skills/ln-spec/assets/spec-template.md b/.agents/skills/ln-spec/assets/spec-template.md
index 83164183..70ebb4e1 100644
--- a/.agents/skills/ln-spec/assets/spec-template.md
+++ b/.agents/skills/ln-spec/assets/spec-template.md
@@ -46,7 +46,7 @@
| # | Assumption | Confidence | Status | Depends on | Validation approach |
| --- | --- | --- | --- | --- | --- |
-| A1 | [hypothesis] | low/medium/high | open | [D# / I# / Requirement #] | [how to falsify] |
+| A1-U | [hypothesis] | low/medium/high | open | [D#-U / I#-U / Requirement #] | [how to falsify] |
### Active Decisions
@@ -56,7 +56,7 @@
live in code/design docs or be omitted. Group decisions by subsystem when useful.
Leave concise retirement comments for removed ID ranges when helpful. -->
-1. **[Decision]** — [rationale]. Depends on: [A1]. Supersedes: [—|D#].
+- **D1-U — [Decision]** — [rationale]. Depends on: [A1-U]. Supersedes: [—|D#-U].
### Critical Invariants
@@ -67,7 +67,7 @@
| # | Invariant | Protected by | Proves |
| --- | --- | --- | --- |
-| I1 | [property] | [test/manual oracle/planned oracle] | [Requirement # / D#] |
+| I1-U | [property] | [test/manual oracle/planned oracle] | [Requirement # / D#-U] |
## Future Direction Register
diff --git a/docs/archive/PLAN_HISTORY.md b/docs/archive/PLAN_HISTORY.md
index 7316d797..e561cb51 100644
--- a/docs/archive/PLAN_HISTORY.md
+++ b/docs/archive/PLAN_HISTORY.md
@@ -23,6 +23,8 @@ Archived from the legacy phase-ledger form of `memory/PLAN.md` on 2026-04-14 dur
## Recent Frontier Archives
+- 2026-05-15 — **Side-chat persistence V4a retired as an independent frontier** — persistent side-chat history was absorbed into Conversational Workspace Runtime Track 2. After the chat/thread reconciliation, the near-term runtime uses durable secondary chats over the existing chat/turn substrate; schema-level `thread` is deferred until chat/turn proves insufficient.
+- 2026-05-08 — **Side-chat V3.0 hard-impact cascade** — FE-674 / PR #115 + #116 + #117 shipped hard-impact cascade through `reconciliation_need`, Pending review listing, and idempotent resolve. Verified: `npm run verify` (1063 tests, 0 lint warnings). Watch moved forward to V3.1 / reconciliation-runtime walkthroughs.
- 2026-04-27 — **Runtime JSON payload hardening (FE-625)** — Express API parsing now accepts chat-sized request bodies above the default parser ceiling and returns a JSON 413 response instead of Express HTML when a payload exceeds the app limit. Verified: `npm run verify`. Watch: if real chat requests still exceed the 5 MB limit, investigate client history / tool-result pruning rather than only raising the ceiling.
- 2026-04-24 — **Distribution hardening release path (FE-531)** — `package.json` now declares the Node 22+ engine floor, explicit shipped files, and public scoped publish config; `npm run release` drives release-it at repo root, rebuilds and dry-runs the packaged artifact, and documents npm auth prerequisites. Verified: `npm run verify`. Watch: CI trusted publishing is still intentionally out of scope.
- 2026-04-23 — **Interviewer-autonomous question format with phase-aware gating** — revised D115: the interviewer now chooses whether to include options per-question based on conversational trajectory; observer interprets selections as resonance (grounding) or commitment (design); ActiveQuestionCard has phase-aware submit gating and "none of the above" copy.
diff --git a/docs/design/CONTINUOUS_WORKSPACE_HYBRID.md b/docs/design/CONTINUOUS_WORKSPACE_HYBRID.md
index fefa4777..b821e4e8 100644
--- a/docs/design/CONTINUOUS_WORKSPACE_HYBRID.md
+++ b/docs/design/CONTINUOUS_WORKSPACE_HYBRID.md
@@ -1,7 +1,7 @@
# Continuous Workspace Hybrid Design
> Design exploration from 2026-04-20.
-> Status: **proposed direction** — hybrid continuous workspace with preserved phase addressability.
+> Status: **selected and shipped in FE-709** — hybrid continuous workspace with preserved phase addressability; deeper route collapse remains deferred.
> Canonicality: this is a focused design note for the interview workspace shape, not the live product authority. For what is true now and what should happen next, prefer `memory/SPEC.md` and `memory/PLAN.md`.
## Why this note exists
diff --git a/docs/design/CONVERSATIONAL_WORKSPACE_RUNTIME.md b/docs/design/CONVERSATIONAL_WORKSPACE_RUNTIME.md
index 56d6f08d..696acb37 100644
--- a/docs/design/CONVERSATIONAL_WORKSPACE_RUNTIME.md
+++ b/docs/design/CONVERSATIONAL_WORKSPACE_RUNTIME.md
@@ -1,54 +1,56 @@
# Conversational Workspace Runtime — Umbrella Design
-> Status: **active synthesis** — consolidated runtime-cluster concept. Output of brainstorm 2026-05-12, anchored on the two sync calls of 2026-05-11 (UX review of V3.1 side-chat) and 2026-05-12 (architecture review, post-V3.1 direction); audited during FE-705 reconciliation cleanup on 2026-05-13.
+> Status: **active synthesis** — reconciled with `memory/SPEC.md` / `memory/PLAN.md` on 2026-05-15 after Track 1 shipped in FE-709.
>
-> Scope: the next major architectural arc after FE-674's V3.1 closes. Synthesizes [MULTI_CHAT.md](./MULTI_CHAT.md), [SIDE_CHAT.md](./SIDE_CHAT.md), [PATCH_LEDGER.md](./PATCH_LEDGER.md), and [CONTINUOUS_WORKSPACE_HYBRID.md](./CONTINUOUS_WORKSPACE_HYBRID.md) into a single concept for the conversational workspace runtime.
+> Scope: the runtime-cluster architecture following FE-674/V3.1 and FE-709. This doc synthesizes [MULTI_CHAT.md](./MULTI_CHAT.md), [SIDE_CHAT.md](./SIDE_CHAT.md), [PATCH_LEDGER.md](./PATCH_LEDGER.md), and [CONTINUOUS_WORKSPACE_HYBRID.md](./CONTINUOUS_WORKSPACE_HYBRID.md) into the current **chat/turn-first** Conversational Workspace Runtime.
>
-> Authority: this doc owns the cross-subsystem synthesis. The sibling docs remain subsystem/source references for shipped substrate details, user-surface history, algorithms, and open questions. Build slices fall out of this map via `/ln-plan`; this doc deliberately does **not** sequence implementation.
+> Authority: this doc owns cross-subsystem synthesis. `memory/SPEC.md` owns product/architecture truth; `memory/PLAN.md` owns frontier sequencing. Sibling docs remain subsystem/source references for shipped substrate details, UI history, algorithms, and design pressure.
## 1. Purpose and positioning
-This is the **umbrella design** for what follows FE-674. It does three things:
+The **Conversational Workspace Runtime** is the architectural umbrella for turning the shipped continuous workspace shell into a durable multi-chat workspace:
-1. Names the umbrella as **Conversational Workspace Runtime** — the user-visible workspace shell hosts a single unified chat surface; threads and sub-runs are reified data rendered inline; reconciliation and changesets attribute conversationally to that surface.
-2. Resolves cross-subsystem decisions that the four sibling docs left open, captured deltas from the 2026-05-11 (UX review) and 2026-05-12 (architecture review) calls.
-3. Names the umbrella's **sub-tracks** so the umbrella Linear issue is legible without prescribing slice sequence.
+1. The workspace hosts a primary interview chat plus inline/collapsible **secondary chats** for side, reconciliation, QA, and strategy work.
+2. Existing `chat` + `turn` persistence is the near-term runtime primitive. A schema-level `thread` table is explicitly deferred until chat/turn proves insufficient.
+3. Reconciliation, proposal turns, and future agent-mediated work stay conversationally visible while semantic mutations remain server-authoritative through changesets.
+4. Prompt context is **transcript-first**: extra graph/workspace context enters the transcript as explicit context snapshot artifacts stored on turns. Graph-item handles track explicit anchors/mentions, but freshness waits for real item versions from the changeset ledger; context is not a hidden persisted context-spec table.
-### What this doc is *not*
+### What this doc is not
-- Not an implementation plan. The sub-tracks in §5 each enter `/ln-plan` separately when picked up.
-- Not a re-derivation of the sibling docs. Where MULTI_CHAT / SIDE_CHAT / PATCH_LEDGER / CONTINUOUS_WORKSPACE_HYBRID already settle a question, this doc points there.
-- Not a UX spec. The shipped V3.1 surface, the UX review feedback, and any subsequent design pass own that.
-- Not the FE-674 polish backlog (raised in UX review). Those flow into the existing branch sequence; see §7.
+- Not an implementation plan. The sub-tracks in §5 enter `/ln-plan` as frontier items.
+- Not a UX spec. It names runtime ownership and cutover targets, not final visual design.
+- Not a new authority for product ontology, changeset semantics, or prompt/context pack policy; those live in SPEC/PLAN and the relevant sibling docs.
-### Relationship to the sibling docs
+### Relationship to sibling docs
| Sibling doc | Role going forward |
-|---|---|
-| [MULTI_CHAT.md](./MULTI_CHAT.md) | Shipped Phase 1 substrate reference; the `chat` table and `reconciliation_need` queue it introduced are primitives this synthesis inherits. Its schema/migration details remain useful, but future thread and reconciliation product shape is governed here. |
-| [SIDE_CHAT.md](./SIDE_CHAT.md) | User-surface history and phasing for V1 / V2 / V3.0 / V3.1, plus V4 notes. Future persistent side-chat history is folded into the unified chat/thread runtime here. |
-| [PATCH_LEDGER.md](./PATCH_LEDGER.md) | Historical design pressure for semantic mutation history and reconciliation ordering. Its target-ordering algorithm remains useful; target vocabulary is **changeset/change** going forward, per SPEC/PLAN. |
-| [CONTINUOUS_WORKSPACE_HYBRID.md](./CONTINUOUS_WORKSPACE_HYBRID.md) | Workspace-shell shape exploration. It still owns the route-alias / workspace-controller / chart-backed-supervisor choice; this doc treats that shell as the host prerequisite for runtime work. |
-
-### Runtime-cluster supersession map
-
-| Claim type | Current authority | Retained source detail | Superseded / historical |
-|---|---|---|---|
-| Runtime concept and cross-track direction | This document | Sync-call deltas captured here plus PLAN sequencing constraints | Reading MULTI_CHAT / SIDE_CHAT / PATCH_LEDGER as independent future roadmaps |
-| Phase 1 chat substrate | [MULTI_CHAT.md](./MULTI_CHAT.md) | Schema, migration, compatibility invariants, and the `reconciliation_need` primitive | Any implication that MULTI_CHAT owns future thread hierarchy or unified-chat UX |
-| Side-chat user-surface history | [SIDE_CHAT.md](./SIDE_CHAT.md) | V1–V3.1 shipped behavior, UI language, V4 persistence notes | Treating the popover, top-bar patch list, or standalone Pending review section as the long-term surface |
-| Semantic mutation history | This document + SPEC/PLAN vocabulary; [PATCH_LEDGER.md](./PATCH_LEDGER.md) for algorithmic pressure | Reconciliation bases, target grouping, topological ordering, phase-two ledger rationale | New schema/operation names using `patch` / `patch_change` instead of `changeset` / `change` |
-| Workspace shell shape | [CONTINUOUS_WORKSPACE_HYBRID.md](./CONTINUOUS_WORKSPACE_HYBRID.md) | Route-alias / workspace-controller / chart-backed-supervisor alternatives | Re-deciding shell architecture inside runtime/thread work |
-| Reconciliation vs graph review | SPEC/PLAN + this document's cross-document audit | PATCH_LEDGER reconciliation-flow mechanics; SPEC_EVOLUTION_STRATEGIES graph-review distinctions | Using `reconciliation_need` as the table for all graph quality findings |
-| Agent mutation authority | [AGENT_MUTATION_SURFACE.md](./AGENT_MUTATION_SURFACE.md) | Capability/handler boundary and changeset-centered mutation vocabulary | Agents writing directly through ORM helpers or harness-specific route wrappers |
-
-Open questions that remain live: thread substrate shape, reconciliation thread lifecycle, direct-edit thread-opening UX, `thread_context_item` ownership, `#` mention disambiguation, TOON implementation choice, async classifier scheduling, and migration of existing client patch terminology.
+| --- | --- |
+| [MULTI_CHAT.md](./MULTI_CHAT.md) | Shipped substrate reference for `chat`, chat-owned turns, primary-chat transition invariants, and `reconciliation_need`. Future runtime work builds on that substrate rather than adding schema-level threads by default. |
+| [SIDE_CHAT.md](./SIDE_CHAT.md) | User-surface history and V1–V3.1 behavior. Its V4 persistent-history direction is superseded by durable secondary chats rendered inline in the workspace. |
+| [PATCH_LEDGER.md](./PATCH_LEDGER.md) | Historical design pressure for semantic mutation history and reconciliation ordering. Future-facing vocabulary is `changeset` / `change`; target-ordering mechanics remain useful. |
+| [CONTINUOUS_WORKSPACE_HYBRID.md](./CONTINUOUS_WORKSPACE_HYBRID.md) | Source note for the shipped Track 1 workspace shell and deferred route-collapse question. Runtime work builds on FE-709 rather than re-deciding the shell. |
+| [INTENT_GRAPH_SEMANTICS.md](./INTENT_GRAPH_SEMANTICS.md) | Authority for relation-policy directionality, endpoint-relative labels, and neighborhood snapshot modes used by context provision and reconciliation impact. |
+| [SUBSTRATE_STRANGLER_COORDINATION.md](./SUBSTRATE_STRANGLER_COORDINATION.md) | Coordination forecast for what backend/server functions and capability contracts frontend work should expect as FE-700/FE-701/Track 5 land. |
+
+### Supersession map
+
+| Claim type | Current authority | Superseded / historical |
+| --- | --- | --- |
+| Runtime concept and cross-track direction | This document + SPEC/PLAN | Reading MULTI_CHAT / SIDE_CHAT / PATCH_LEDGER as independent future roadmaps. |
+| Secondary conversation persistence | `chat` + `turn` substrate, with secondary chats as product/runtime usage | Treating a `thread` table, `turn.thread_id`, or `thread_context_item` as accepted near-term schema. |
+| Side-chat user surface | Inline/collapsible secondary chats in the workspace | `SideChatPopover`, top-bar staged patch list, and standalone Pending review as long-term surfaces. |
+| Semantic mutation history | Changeset/change ledger | New durable schema or operation names using `patch` / `patch_change`. |
+| Prompt context | Transcript-first snapshots stored as turn artifacts; item handles are lightweight anchor/mention references refreshed only with real item versions | Hidden persisted context-spec records as the default context authority; temporary content fingerprints as a durable refresh oracle. |
+| Reconciliation vs graph review | Reconciliation needs are process debt from known disturbances; graph-review findings are critique artifacts | Using `reconciliation_need` as the table for all graph quality findings. |
+| Agent mutation authority | Brunch-owned capability/handler contracts | Agents writing directly through ORM helpers or harness-specific route wrappers. |
+
+Live open questions are now narrower: secondary-chat lifecycle/rendering shape over chat/turn, reconciliation chat lifecycle, direct-edit chat-opening UX, `#` mention disambiguation, context-handle storage/expiry, compact snapshot serialization, async classifier scheduling, endpoint-relative relation-label UI affordances, and migration of existing client patch terminology.
## 2. The shift, at a glance
```mermaid
flowchart LR
- subgraph Today
+ subgraph Previous
S1[spec route] --> SLV[structured-list view]
S1 --> GV[graph view]
SC1[side-chat popover anchored per item] -.-> SLV
@@ -57,14 +59,12 @@ flowchart LR
end
subgraph Target
- WS[continuous workspace shell] --> CR[unified chat surface]
- CR --> IT[interview thread main spine]
- CR --> ST[side threads item-anchored]
- CR --> RT[reconciliation thread target-grouped]
- CR --> QT[Q&A threads explicit-set]
- IT -.-> ST
- IT -.-> RT
- IT -.-> QT
+ WS[continuous workspace shell] --> PS[primary interview chat]
+ WS --> SS[inline secondary chats]
+ SS --> SIDE[side chat item anchored]
+ SS --> REC[reconciliation chat target grouped]
+ SS --> QA[QA chat explicit context]
+ SS --> STR[strategy chat proposal turns]
SLV2[structured-list view] --> WS
GV2[graph view] --> WS
end
@@ -72,276 +72,280 @@ flowchart LR
**What changes for the user**
-- One main chat surface per spec, not many popovers. Threads / sub-runs render inline as collapsibles.
-- Reconciliation absorbs into the chat surface as a target-grouped thread, not a separate review section.
-- The side-chat popover and the Pending review section both retire into in-stream threads over the umbrella's lifetime.
-- Direct edits stay fast-path. They open a thread automatically only when impact exceeds `soft`.
-- Auto-confirmed reconciliation never surfaces. Only `auto-edit` and `substantive` reach the user.
+- One workspace surface can show the primary interview and secondary chats inline, usually collapsed until relevant.
+- Reconciliation becomes an in-stream secondary chat, not a separate review section.
+- The side-chat popover and Pending review section retire after parity exists over durable secondary chats.
+- Direct edits stay fast-path. Hard-impact edits create reconciliation needs and may focus a side/reconciliation chat depending on context.
+- Auto-confirmed reconciliation never surfaces. Only `auto-edit` and `substantive` need user attention.
**What changes for the substrate**
-- The `chat` table stays the durable primitive; the umbrella adds a substrate seam for threads (one of three shapes — see §3.2 / §8).
-- `reconciliation_need.caused_by_changeset_id` becomes real once changesets land (§3.4). The `caused_by_*` placeholders already in MULTI_CHAT.md §3.4 are the seam.
-- The `changeset` / `change` records (PATCH_LEDGER.md Phase 2) become first-class. The transient client-side "patch" list in the V3.1 side-chat surface goes away with the popover.
-- Context-provision becomes a typed thread-scoped concern with TOON notation, # mention as a substrate-level mutation, and turn-zero seeding (§3.5).
+- The `chat` table stays the durable conversational primitive; turns remain chat-owned.
+- Secondary chat kinds (`side`, `reconciliation`, `qa`, `strategy`) are represented through chat metadata / strategy state over chat+turn unless a later RFC proves a `thread` table is necessary.
+- Changeset/change records become the semantic mutation spine; existing client “patch” state is transitional.
+- Context provision becomes explicit transcript content: context snapshots are inserted into turns, and context handles track explicitly referenced graph items. Stale-handle refresh waits for changeset-backed item versions rather than a temporary content fingerprint.
## 3. Architecture layers
-Top-down from the surface the user sees to the substrate underneath. Each layer is one sub-track in §5.
+### 3.1 Workspace shell — Track 1, shipped
-### 3.1 Workspace shell
+The spec route renders a continuous workspace: realized phase sections, sidebar navigation, scroll/focus behavior, primary chat, projected controls, graph/sidebar affordances, and future inline secondary chats. This shipped in FE-709 as `continuous-workspace`.
-The spec route renders a continuous workspace, not a stack of independent views. Phase sections, sidebar navigation, and scroll/focus behavior belong here. The chat runtime mounts inside the shell.
+The shell is the structural prerequisite for absorbing side-chat and pending-review surfaces. Runtime work should build on the shipped hybrid shell and preserve phase addressability, single actionable frontier semantics, and workspace/read-model authority.
-This is the [CONTINUOUS_WORKSPACE_HYBRID.md](./CONTINUOUS_WORKSPACE_HYBRID.md) frontier already in PLAN.md §Active. That doc owns the shape choice (route-alias / workspace controller / chart-backed supervisor). This umbrella names the workspace shell as a **structural prerequisite** for the chat runtime: the runtime needs a stable host before it can absorb side-chat / pending-review surfaces. That is a dependency constraint, not a ship-order commitment — `/ln-plan` decides actual sequencing (see the dependency arrows in §5). Structured-list view and graph view become workspace-aware peers, not standalone routes.
+### 3.2 Chat runtime — inline secondary chats over chat/turn
-### 3.2 Chat runtime — unified surface, threads as primitive
-
-One main chat per spec is visible. Threads, sub-runs, and side conversations are reified data rendered inline as collapsibles (Cursor-style). This is the user-visible commitment from Q3 of the brainstorm.
+Track 2 implements inline/collapsible secondary chats using existing `chat` + `turn` persistence.
**Primitives**
-- `chat` — already shipped per MULTI_CHAT.md. One interview chat per spec, addressable via `specification.primary_chat_id`.
-- **Thread** — a sub-run inside the interview chat. **Substrate shape is an open question** (§8). Three plausible options:
- - **(p) `parent_chat_id` on `chat`** — a thread is just a child `chat` row. Smallest delta from MULTI_CHAT.md; the chat table absorbs hierarchy.
- - **(q) New `thread` table** — chats own threads; threads own turns. Spec → chat → thread → turn. Most expressive, biggest schema delta.
- - **(r) Pure UI-rendering** — chats stay sibling-of-spec; UI renders one chat's children inline. Substrate unchanged.
+- `chat` — durable conversation container inside one specification. One primary interview chat exists; secondary chats are additional chat rows for side, reconciliation, QA, or strategy work.
+- `turn` — chat-owned conversational event or assistant/system-first proposal/kickoff. Each active/resumable chat has at most one open assistant/system-first frontier turn.
+- `chat.kind` / chat-local strategy metadata — distinguishes `side`, `reconciliation`, `qa`, and `strategy` behavior without creating semantic truth.
+- **Turn-zero** — an assistant/system kickoff turn that seeds a secondary chat with explicit context snapshots and options before the user responds. The first Track 2 version can render snapshots supplied by server fixtures/builders without owning the full Track 5 refresh lifecycle.
+
+**Explicit deferral**
- This umbrella does **not** pick yet. A follow-up RFC (sub-track 2 in §5) decides based on what the in-stream rendering and # mention substrate actually need.
-- **Thread kinds** — `interview` (the spine), `side` (item-anchored), `reconciliation` (target-grouped), `qa` (explicit-set, user-initiated). Kind determines context-spec defaults (§3.5) and turn-zero behavior. Kinds are metadata, not hard constraints on what happens inside. These thread kinds are **conceptually distinct from the existing `chat.kind` enum** (currently `interview | side_chat` per MULTI_CHAT.md §3) — how they're persisted (a new `thread.kind` column, an extension of `chat.kind`, or UI-only metadata) is part of the substrate choice deferred below.
-- **Turn-zero** — every thread starts with an `assistant` turn that prompts the user with kind-appropriate options. Existing `turn_kind = 'kickoff'` is the seam.
+Do not add a `thread` table, `turn.thread_id`, or schema-level thread hierarchy in Track 2. The follow-up question is not “which thread schema?” but “what, if anything, can chat/turn not express after secondary-chat rendering, one-open-frontier semantics, strategy state, and context snapshots are implemented?”
-**What retires when this lands**
+**Cutover targets**
-- The `SideChatPopover` UI surface (per-item floating popover) retires. Side threads render inline in the main chat.
-- The transient client-side "patch list" / staged-patches strip retires. Staged-but-unapplied changes become a property of an in-flight thread, not a separate surface.
-- The standalone `PendingReviewSection` retires. Its content surfaces as the reconciliation thread (§3.3).
+- Retire `SideChatPopover` as the long-term side-chat surface after durable inline secondary chats reach parity.
+- Retire the transient staged-patches strip as a semantic source of truth. In-flight proposals may remain turn artifacts, but accepted mutations flow through changesets.
+- Preserve existing primary interview behavior during the transition.
-### 3.3 Reconciliation runtime
+### 3.3 Reconciliation runtime — in-stream secondary chat
-Reconciliation is **async-by-default with an explicit "Reconcile Now" trigger** (Q5 of the brainstorm).
+Track 3 absorbs reconciliation into the workspace as a target-grouped secondary chat.
**Trigger model**
-- **Async (observer-like)** — when `reconciliation_need` rows enter the queue (Path 1 deterministic, Path 2 observer; see MULTI_CHAT.md §5.1), a background runner processes `agent_status = null` rows through the V3.1 classifier. Auto-confirmed rows resolve invisibly. Auto-edit rows queue with a proposal awaiting one-click apply. Substantive rows accumulate, surfaced as badge state.
-- **User trigger** — "Reconcile Now" in the workspace shell. Materializes (or refocuses) the current reconciliation thread. Useful when the user wants to batch-review accumulated substantive rows, retry failed rows, or force-classify a backlog.
+- **Async by default** — when `reconciliation_need` rows enter the queue, a background runner/classifier processes unclassified rows. Auto-confirmed rows resolve invisibly. Auto-edit rows queue one-click suggestions. Substantive rows accumulate for judgment.
+- **User trigger** — “Reconcile Now” materializes or refocuses the reconciliation chat so the user can batch-review, retry, or force classification.
+
+**Chat shape**
-**Reconciliation thread shape**
+A reconciliation chat is a durable secondary `chat`, grouped by target and sorted upstream-first using the PATCH_LEDGER target-ordering pressure. Classifier labels (`auto-confirm`, `auto-edit`, `substantive`) are metadata on needs inside target groups, not the primary grouping axis.
-One thread per outstanding reconciliation batch (current shape: open and unresolved). Grouped by target — topologically sorted upstream-first, per PATCH_LEDGER.md §Target Ordering. The V3.1 classifier output (`auto-confirm` / `auto-edit` / `substantive`) is metadata shown on each need within its target node, **not** the primary grouping axis. Auto-confirmed never surfaces; the user sees only `auto-edit` (with one-click apply) and `substantive` (with judgment affordances).
+The reconciliation chat can host a conversation about substantive needs, but it does not own semantic truth. Accepted resolutions route through Brunch-owned handlers and, once Track 4 lands, durable changesets.
-The thread is a real `chat` (or `thread`, pending §3.2's choice) — durable, replayable, and able to host a conversation if the user wants to discuss a substantive need rather than just resolve it.
+**Surfacing rules**
-**Subtle surfacing rules**
+- Auto-confirmed rows do not surface.
+- Open non-auto-confirmed needs may show subtle badges on structured-list / graph items.
+- The workspace shell may show an active reconciliation count and Reconcile Now affordance without stealing focus.
-- Items in the structured-list and graph views carry a small badge when they have open non-auto-confirmed needs against them. Badge is informational, never blocking.
-- The workspace shell exposes the active reconciliation thread's count and a "Reconcile Now" affordance, but does not steal focus.
+### 3.4 Changeset ledger — semantic mutation spine
-### 3.4 Changeset ledger
+Track 4 introduces durable semantic mutation history.
-Changesets become a first-class durable record of semantic mutation. This is PATCH_LEDGER.md Phase 2 reified.
+**Vocabulary**
-**Vocabulary** — canonical going forward: `changeset` (a durable record bundling 1+ atomic changes) and `change` (a single mutation). "Patch" is historical: it survives in the existing client-state code for transient staged-changes-in-side-chat, and in PATCH_LEDGER.md as historical text, but is **not** part of the target architecture.
+- `changeset` — one coherent submitted semantic mutation bundle.
+- `change` — one atomic mutation inside a changeset.
+- “Patch” is historical/transitional. It may remain in legacy client code until migrated, but it is not target vocabulary.
**Attribution**
-- Every `change` is attributed to its originating `changeset`.
-- Every `changeset` carries provenance: the originating `turn_id` (when produced inside a thread), the originating `chat_id` / thread (always), the `caused_by_action` (user-direct-edit / chat-mediated / agent-proposed / reconciliation-resolution).
-- `reconciliation_need.caused_by_changeset_id` becomes real. Each need points back to the changeset whose change opened it. The MULTI_CHAT.md §3.4 placeholder gets typed.
+- Every change belongs to one changeset.
+- Every changeset records provenance: originating turn/chat where applicable, action source, actor, and base semantic state.
+- `reconciliation_need.caused_by_changeset_id` replaces/connects the historical patch placeholder.
+- Proposal turns are not mutations until accepted.
-**Direct edits in the target state**
+**Direct edits**
-A direct edit on a knowledge item from the structured-list view writes a `changeset` with one `change`. Path 1 deterministic reconciliation runs as today. If impact > `soft`, the system either:
-- opens (or appends to) a side thread anchored to the edited item, surfacing the cascade conversationally, or
-- adds rows to the active reconciliation thread's queue.
+A direct graph/list edit writes a changeset and then opens/deduplicates reconciliation needs according to relation policy. The UX may focus an item-anchored side chat, append to a reconciliation chat, or remain in-place; that is a Track 3/4 interaction decision, not a semantic-history decision.
-Which of these depends on the user's recent context (was the edit invoked from chat, or from the spec view alone?). This is a UX decision deferred to per-track design; the changeset's substrate position is unaffected.
+### 3.5 Context provision — transcript-first snapshots and handles
-### 3.5 Context provision
+Track 5 provides prompt context for primary and secondary chats without a hidden persisted context-spec table.
-Threads carry a **context spec** at inception. Established via turn-zero. Mutated through `# mention` and explicit add-to-context affordances.
+**Model**
-**Context spec record (per thread)**
+- A chat primarily uses its own transcript as prompt context.
+- Extra graph/workspace context is inserted into the transcript as explicit **context snapshot** artifacts.
+- A **context handle** records that a chat is tracking explicit graph subjects across turns, usually because a chat was anchored on an item or the user mentioned one with `#`. Before new assistant turns, stale handles can trigger fresh snapshots when the subject's changeset-backed item version has advanced. Do not bless temporary content fingerprints as the durable freshness oracle.
+- Snapshots are historical: they do not mutate when source truth changes.
-- `scope` — `full-graph` | `neighborhood` | `explicit-set`
-- `root_anchors` — knowledge item ids anchoring the context
-- `include_edges` — boolean (always true for `full-graph` and `neighborhood`)
-- `include_open_needs` — boolean
-- `include_phase_outcomes` — boolean
-- `spec_metadata` — always true
+**Turn-zero**
-**Kind-defaults**
+Secondary chats begin with a kickoff turn that inserts kind-appropriate snapshots and offers options. Track 2 can create/render turn-zero artifacts before Track 5 fully lands, but the snapshots should already follow the transcript-first artifact model. Example defaults:
-- **`interview`** — `full-graph` + open needs + phase outcomes. The spine sees everything.
-- **`reconciliation`** — `explicit-set` seeded with the needs-batch's targets and their 1-hop neighborhoods. Open needs scoped to those targets.
-- **`side`** (item-anchored) — `neighborhood` rooted at the anchor item; 1-hop typed edges and connected items; open needs against the anchor.
-- **`qa`** — `explicit-set` seeded by the user's first message and any `#` mentions; expandable through further mentions.
+- `side` — anchor item snapshot plus relation-policy-rendered neighborhood and open needs against the anchor.
+- `reconciliation` — target group snapshots plus relevant needs and relation-policy context.
+- `qa` — user-selected / `#`-mentioned items and enough graph metadata to answer safely.
+- `strategy` — current phase/workflow state plus the fixed premise and proposal constraints.
-**Format**
+**Snapshot builder family**
-- Item *content* serializes as markdown.
-- Graph *structure* (items + typed edges) serializes as **TOON notation** — the token-efficient compact format named in the architecture review. Established as the canonical format primitive for graph-shaped context. [toonformat.dev](https://toonformat.dev/) is one candidate implementation.
-- `reconciliation_need` rows serialize as a compact list with kind, source, target, and `agent_classification` if present.
+The server-side context layer should expose reusable builders; frontend runtime code should consume their artifacts rather than reconstruct graph meaning locally:
-**`#` mention as a substrate mutation**
+| Builder shape | Purpose |
+| --- | --- |
+| `buildIntentItemContextSnapshot({ specificationId, itemIds })` | Explicit item inclusion and `#` mention context. |
+| `buildIntentNeighborhoodContextSnapshot({ specificationId, anchorItemIds, mode })` | Side-chat, QA, edit-impact, and reconciliation context around anchors. Initial modes: `immediate`, `dependencies`, `dependents`, `evidence`, `reconciliation`. |
+| `buildEconomicIntentGraphContextSnapshot({ specificationId, budget })` | Compact whole-graph briefing for unanchored chats in existing specifications. |
+| `buildHistoricalIntentNeighborhoodSnapshot({ itemId, basis })` | Later, once changesets can identify original-capture and last-update surroundings. |
+| `resolveIntentItemReferences({ specificationId, refs })` | Server-owned `#` reference-code/name resolution scoped to one specification. |
-In any thread, the user types `#AS-12` or `#requirement-foo`. This:
-1. Resolves the reference code or name against the spec's `knowledge_item` rows.
-2. Inserts a durable row into the thread's context-item join (working name: `thread_context_item`).
-3. Triggers a context-spec change visible to the next turn's prompt assembler.
+Neighborhood labels and buckets (`dependencies`, `dependents`, `evidence`, etc.) come from relation policy endpoint-relative labels. They are not string reversals of `knowledge_edge.from_item_id` / `to_item_id`.
-Mentions are not just text. They are durable, replayable, and contribute to the thread's effective context across turns. The user can revoke a mention from the thread.
+**`#` mention**
-**Turn-zero**
+A mention such as `#AS-12` resolves against intent items through a server-owned resolver scoped to the specification. Resolution inserts a context snapshot and, once real item versions exist, activates or refreshes a handle for the mentioned subject. Ambiguity should produce an explicit disambiguation/recovery artifact rather than silently omitting context. Revocation, expiry, and storage shape are Track 5 design details, but the transcript remains the durable replay surface.
-Every thread starts with an `assistant` turn (existing `turn_kind = 'kickoff'`) that prompts the user with kind-appropriate options. The prompt assembler reads the context spec and renders the kickoff question accordingly. The user replies; the conversation proceeds. This pattern is explicit because today the user starts most chat surfaces with a blank textarea, and the architecture review called this out as backwards for an assistant-led tool.
+**Serialization**
-## 4. Cross-cutting decisions
+Context-pack builders own compact rendering. TOON or another compact graph serializer may format inserted snapshots, but the serializer is an implementation choice, not an authority boundary.
-Decisions that don't fit any single layer.
+## 4. Cross-cutting decisions
### 4.1 Vocabulary
-- `changeset` / `change` — canonical (durable mutation records).
-- `chat` — substrate primitive (already shipped). One per spec at minimum; many over the umbrella's lifetime.
-- `thread` — user-visible primitive for sub-runs in the unified chat surface. Substrate shape TBD (§3.2).
-- `reconciliation_need` — unchanged from MULTI_CHAT.md.
-- `Annotate` → `Note` and `Edit mode` (FE-only vocabulary, already shipped in Card 4 of CARDS.md). No type renames.
-- "Patch" — historical only. Not part of target architecture.
+- `chat` — durable conversation container inside a specification.
+- `secondary chat` — non-primary chat rendered inline/collapsible in the workspace; product/runtime use of `chat`, not a separate thread table.
+- `turn-zero` — kickoff turn that seeds a secondary chat.
+- `context snapshot` — explicit turn artifact recording inserted graph/workspace context at a point in time.
+- `neighborhood snapshot` — context snapshot centered on one or more intent items, with relation-policy-selected modes such as immediate, dependencies, dependents/impact, evidence, reconciliation, and later historical.
+- `context handle` — lightweight active reference to explicit graph subjects, causing future freshness checks and new snapshots only when changeset-backed item versions advance.
+- `changeset` / `change` — durable semantic mutation vocabulary.
+- “Thread” — historical or generic UI language only in this doc. It is not target schema vocabulary.
+- “Patch” — historical/transitional client vocabulary only.
### 4.2 What never surfaces to the user
-- Auto-confirmed reconciliation rows. Resolved invisibly.
-- Async classifier runs that succeed without producing substantive output. Status is visible if asked (via the chip), but no notification, no focus steal.
-- Successful `changeset` writes from agent-driven reconciliation resolution. The user sees the resulting state, not the bookkeeping.
+- Auto-confirmed reconciliation rows.
+- Successful classifier runs that produce no user-relevant work.
+- Changeset bookkeeping as a separate user-facing object when the resulting semantic state is enough.
### 4.3 What surfaces subtly
-- Open non-auto-confirmed needs against an item. Small badge in the structured-list / graph views, with count.
-- Active reconciliation thread count in the workspace shell. Visible, not blocking.
-- Failed classifier rows. Visible as a state, not a notification.
+- Open non-auto-confirmed reconciliation needs against an item.
+- Active reconciliation chat count / Reconcile Now affordance.
+- Failed classifier rows as recoverable state.
### 4.4 What surfaces actively
-- Substantive reconciliation items. The thread surfaces them with judgment affordances.
-- Hard-impact direct edits that opened a thread. Thread becomes the active focus.
-- Cursor-style sub-agent runs invoked by the interview chat (e.g. "summarize what's open"). Inline in the main stream, collapsed by default once complete.
+- Substantive reconciliation needs with judgment affordances.
+- Hard-impact direct edits when user attention is needed.
+- Assistant/system-first proposal turns in strategy, graph-review, or reconciliation chats.
## 5. Umbrella structure — sub-tracks
-The umbrella Linear issue contains the following sub-tracks. Each is a candidate frontier item; ordering and slicing are for `/ln-plan` to settle. The dependency arrows below are the only ordering constraints baked in.
-
```text
-Track 1: Workspace shell
- ├─ Decide shape (CONTINUOUS_WORKSPACE_HYBRID Design A/B/C)
- ├─ Mount center pane as cumulative phase sections
+Track 1: Workspace shell — shipped FE-709
+ ├─ Cumulative phase sections
├─ Sidebar section-active behavior
- └─ Structured-list and graph views become workspace-aware peers
+ └─ Structured-list and graph views as workspace-aware peers
-Track 2: Chat runtime — thread substrate + in-stream rendering
- ├─ Decide thread substrate (parent_chat_id / new table / UI-only)
- ├─ Render threads inline as collapsibles in the main chat
- ├─ Retire SideChatPopover (cutover, not immediate)
- └─ Retire transient staged-patches strip (replaced by in-thread mutation state)
+Track 2: Chat runtime — inline secondary chats
+ ├─ Represent side/reconciliation/qa/strategy chats over chat+turn
+ ├─ Render secondary chats inline/collapsible in the workspace
+ ├─ Preserve one open assistant/system-first frontier turn per active chat
+ ├─ Seed secondary chats with turn-zero kickoff + context snapshots
+ └─ Retire SideChatPopover after parity
Track 3: Reconciliation runtime
- ├─ Reconciliation thread (target-grouped, topo-sorted)
- ├─ Async-by-default classifier scheduling (background runner)
- ├─ "Reconcile Now" trigger in workspace shell
- ├─ Retire standalone PendingReviewSection (cutover)
- └─ Auto-edit one-click apply + substantive judgment affordances inside the thread
+ ├─ Target-grouped reconciliation chat
+ ├─ Async-by-default classifier scheduling
+ ├─ Reconcile Now trigger in workspace shell
+ ├─ Retire standalone PendingReviewSection after parity
+ └─ Auto-edit one-click apply + substantive judgment affordances
Track 4: Changeset ledger
- ├─ changeset / change tables (PATCH_LEDGER Phase 2 schema)
+ ├─ changeset / change tables and mutation handlers
+ ├─ latest/base changeset identity for proposal staleness
├─ reconciliation_need.caused_by_changeset_id wiring
- ├─ Direct-edit path writes a changeset
- ├─ Agent-resolution path writes a changeset
- └─ Migration of existing in-memory "patch" client state to durable changesets
+ ├─ Direct-edit and agent-resolution paths write changesets
+ └─ Migrate existing client patch vocabulary/state
-Track 5: Context provision
- ├─ thread_context_item join (or equivalent — depends on Track 2's substrate choice)
- ├─ TOON notation serializer
- ├─ Per-kind context-spec defaults in the prompt assembler
- ├─ # mention parser + resolver + UI affordance
- └─ Turn-zero kickoff prompt assembly per kind
+Track 5: Chat context provision
+ ├─ Context snapshot turn artifacts
+ ├─ Active graph-item handles and stale-handle refresh after real item versions exist
+ ├─ # mention parser/resolver/disambiguation
+ ├─ Item, neighborhood-mode, economic graph, and later historical snapshot builders
+ ├─ Turn-zero prompt assembly per chat kind/strategy
+ └─ Structured assertions + selected golden renderings for snapshots
Dependencies
- Track 1 (shell) —enables→ Track 2 (chat runtime)
- Track 2 (chat runtime) —enables→ Track 3 (reconciliation in-stream)
- Track 2 (chat runtime) —enables→ Track 5 (# mention, turn-zero)
- Track 4 (changeset) ←—needs→ existing reconciliation_need (already shipped)
- Track 4 (changeset) —enables→ richer attribution in Track 3
- Track 5 (context) ←—needs→ Track 2 (thread substrate)
+ Track 1 (shell) —enables→ Track 2 (secondary chats)
+ Track 2 —enables→ Track 3 (in-stream reconciliation)
+ Track 2 —enables→ Track 5 (turn-zero, mentions, handles)
+ Track 4 (changeset) —parallel with→ Track 2
+ Track 4 —enables→ richer attribution in Track 3
+ Track 4 —enables→ real item versions and historical neighborhoods in Track 5
```
**Why this order**
-- The shell must come first because the chat runtime needs a stable host. CONTINUOUS_WORKSPACE_HYBRID is already in §Active for this reason.
-- The chat runtime is the unblocker for both reconciliation absorption and # mention / context-provision.
-- The changeset ledger can run in parallel with the chat runtime once the shell exists; it has its own scope independent of in-stream rendering.
-- Context provision and reconciliation in-stream both ride on the chat runtime substrate; they parallelize once Track 2 has its first cut.
+- The shell came first because secondary chats need a stable host.
+- The chat runtime is the unblocker for reconciliation absorption and transcript-first context provision.
+- The changeset ledger can run in parallel because semantic history is independent of inline rendering.
+- Context provision and reconciliation in-stream parallelize once Track 2 settles the initiating chat/anchor shape.
## 6. Cross-document audit
-This synthesis has to respect parallel design work that happened outside the runtime cluster.
-
| Parallel design | Implication for the runtime cluster |
-|---|---|
-| [INTENT_GRAPH_SEMANTICS.md](./INTENT_GRAPH_SEMANTICS.md) | Reconciliation and direct-edit cascade must consult relation-policy directionality and edge support/status. The runtime cannot infer affected endpoints from raw `knowledge_edge` source/target direction. |
-| [SPEC_EVOLUTION_STRATEGIES.md](./SPEC_EVOLUTION_STRATEGIES.md) | Strategy is chat-local process state. Scenario options, graph-review findings, and reconciliation suggestions are proposal turns until accepted; accepted candidate bundles become coherent changesets, not loose item-by-item mutations. |
-| [AGENT_MUTATION_SURFACE.md](./AGENT_MUTATION_SURFACE.md) | Agent-originated writes must enter through Brunch-owned capability/handler contracts. The runtime may host agent runs, but those runs do not get direct ORM or route-wrapper mutation authority. |
-| [BEHAVIORAL_KERNELS.md](./BEHAVIORAL_KERNELS.md) | Kernel-driven questions produce typed artifacts that the intent graph stores; the runtime provides thread/context affordances but should not invent a separate artifact ontology. |
-| [ln-skills/EVOLUTION.md](./ln-skills/EVOLUTION.md) | Dev-layer file-backed registry ideas are separate from product runtime persistence. Do not mix product `changeset` tables with the future `memory/` registry experiment. |
+| --- | --- |
+| [INTENT_GRAPH_SEMANTICS.md](./INTENT_GRAPH_SEMANTICS.md) | Reconciliation, direct-edit cascade, and context snapshots must consult relation-policy directionality, endpoint-relative labels, and edge support/status. Runtime code cannot infer affected endpoints or dependency/dependent labels from raw edge direction. |
+| [SPEC_EVOLUTION_STRATEGIES.md](./SPEC_EVOLUTION_STRATEGIES.md) | Strategy is chat-local process state. Scenario options, graph-review findings, and reconciliation suggestions are proposal turns until accepted; accepted bundles become coherent changesets. |
+| [AGENT_MUTATION_SURFACE.md](./AGENT_MUTATION_SURFACE.md) | Agent-originated writes enter through Brunch-owned capability/handler contracts, not direct ORM or route-wrapper mutation authority. |
+| [SUBSTRATE_STRANGLER_COORDINATION.md](./SUBSTRATE_STRANGLER_COORDINATION.md) | Existing frontend REST/SSE contracts remain stable while backend work produces shared handlers, relation-policy functions, context snapshot builders, and capability tools. |
+| Prompt/context substrate (SPEC D139/D140/D154, A84/A85/A95) | Chat context provision consumes prompt/context-pack policy. Snapshots are built by context-pack builders and stored on turns; handles organize refresh once changeset-backed item versions exist. |
+| [BEHAVIORAL_KERNELS.md](./BEHAVIORAL_KERNELS.md) | Kernel-driven questions produce typed intent artifacts; the runtime provides chat/context affordances but not a separate artifact ontology. |
+| [ln-skills/EVOLUTION.md](./ln-skills/EVOLUTION.md) | Dev-layer file-backed registry ideas are separate from product runtime persistence. |
-Audit result: the runtime concept stays coherent if it treats `chat`/thread as conversational process, `changeset`/`change` as semantic mutation history, `reconciliation_need` as process debt from a known disturbance, and graph review as a separate quality oracle. That matches the current SPEC/PLAN reconciliation.
+Audit result: the runtime is coherent when `chat` is conversational process, chat-local strategy remains turn/proposal state, prompt/context packs assemble context snapshots, relation policy owns endpoint-relative labels and impact direction, changesets own semantic mutation history and item versions, reconciliation needs represent process debt, and graph review remains a separate quality oracle.
## 7. Out of scope / explicit deferrals
-- **FE-674 polish** (raised in UX review) — tactical V3.1 surface improvements that flow into the existing FE-674 branch sequence; not absorbed into this umbrella. They make the V3.1 surface more demo-legible but are tactical, not architectural.
-- **Designer consultation** (UX review) — visual UX directions for the new in-stream surfaces are out of scope until the design discussion lands. This doc commits to architecture, not pixel-level UI patterns.
-- **Demo-bound prioritization** (architecture review) — orthogonal. The umbrella's sub-tracks may be re-ordered for demo readiness, but the architectural map doesn't change.
-- **Thread substrate shape** (§3.2) — explicitly deferred to a sub-RFC under Track 2. Three options on the table.
-- **Continuous workspace shape** (CONTINUOUS_WORKSPACE_HYBRID Design A / B / C) — owned by that doc; not re-decided here.
-- **Architect / generator loop** (PLAN.md Horizon) — autonomous agent over the intent graph. Still horizon; depends on changeset ledger landing first via Track 4.
-- **Persistent side-chat history (SIDE_CHAT V4)** — superseded by Track 2. The user-visible "history" of side-chats is the main chat stream itself, where threads stay collapsed.
-- **Two-axis interview framing, progressive detail, candidate-spec completion assist, first-run provider setup, workspace hygiene gitignore assist, productized web research** — all PLAN.md Horizon items unrelated to the umbrella. Unaffected.
+- Pixel-level secondary-chat UX and designer consultation.
+- Demo-bound prioritization; PLAN sequencing owns frontier order.
+- Schema-level `thread` tables or `turn.thread_id`; deferred until chat/turn insufficiency is proven.
+- Hidden persisted context-spec tables; deferred unless transcript-first snapshots/handles fail.
+- Temporary content/edge fingerprints as the durable context-handle freshness oracle; handle freshness waits for changeset-backed item versions.
+- Continuous-workspace route collapse; FE-709 hybrid shell remains the host.
+- Architect/generator loop; horizon until changesets and reconciliation surfaces stabilize.
+- Provider setup, gitignore assist, and productized web research; separate PLAN frontiers.
## 8. Open questions
-- **Thread substrate** — (p) `parent_chat_id`, (q) new `thread` table, (r) UI-only rendering. To be decided by a Track 2 sub-RFC.
-- **Direct-edit thread-opening UX** — when a direct edit on the structured-list view triggers hard-impact cascade, does the system open (a) a fresh side thread anchored to the edited item, (b) append to the active reconciliation thread, or (c) both, contextually? Deferred to Track 3 / Track 4 design.
-- **`thread_context_item` join shape** — depends on §3.2. If threads are child `chat` rows, this join hangs off `chat`. If threads are a new table, off `thread`. If UI-only, the join is per-`chat`. Settled with Track 2.
-- **# mention disambiguation** — what does `#requirement-foo` resolve to when multiple items share a reference fragment? Track 5 design.
-- **TOON notation library** — adopt an external implementation ([toonformat.dev](https://toonformat.dev/) is one candidate) or write a minimal serializer? Track 5 spike. The choice affects token budget and test coverage but not architecture.
-- **Async-classifier scheduling primitive** — in-process loop / BullMQ-style queue / pg-boss / inline scheduler. PATCH_LEDGER.md and CARDS.md Card 5 both punt this to "promote to a queue substrate only if outer-loop walkthroughs surface user-visible blocking." Stays deferred under Track 3.
-- **Reconciliation thread lifecycle** — is there one persistent reconciliation thread per spec (always exists, always reflects current queue state), or one per Reconcile Now invocation (transient, archived when resolved)? Track 3 design.
-- **Cursor-style sub-agent runs in the interview chat** — does the chat runtime own a generic "spawn a sub-agent run" affordance, or is reconciliation thread the only sub-run kind for V1? Track 2 design.
-- **Continuous-workspace shape choice** — Design A / B / C in CONTINUOUS_WORKSPACE_HYBRID.md. Settled by Track 1, not this doc.
-- **Migration of existing client `patch` state** — the V3.1 transient staged-patches surface still uses "patch" terminology in code. Track 4 includes renaming the client state to `changeset` / `change` and folding it into durable storage, but the transition needs a stepwise plan.
+- **Secondary-chat lifecycle** — when to create, refocus, collapse, archive, or resume side/reconciliation/qa/strategy chats.
+- **Direct-edit attention UX** — when hard-impact direct edits focus an item side chat, a reconciliation chat, both, or neither.
+- **Context-handle storage and expiry** — whether handles are explicit rows, turn-derived state, or both; how revocation and expiry are represented once real item versions exist.
+- **`#` mention disambiguation** — reference-code/name matching and ambiguous-result UX.
+- **Compact snapshot serialization** — TOON vs a minimal internal serializer; structured assertions plus selected golden renderings are the oracle, not exact prose everywhere.
+- **Async-classifier scheduling** — in-process loop vs queue substrate; promote only if outer-loop behavior needs it.
+- **Reconciliation chat lifecycle** — one persistent reconciliation chat per spec vs batch/invocation chats.
+- **Generic sub-agent runs** — whether Track 2 owns a general sub-agent affordance or only the named secondary chat kinds for now.
+- **Client patch-state migration** — stepwise renaming/folding into durable changesets.
## 9. Traceability
-SPEC.md anchors that this umbrella inherits or extends. Identifiers are listed pending the next `/ln-sync` pass.
-
-**Inherits**
+**Anchors**
-- A48, A80, A82, A83, A88 — multi-chat substrate sufficiency, HITL contract, V3.0 Path-1 mechanical sufficiency, V3.1 grouping validation.
-- D86, D87, D110, D113, D114 — chat substrate and continuous-workspace decisions.
-- D135, D137, D138, D139, D140, D141 — cascade through `reconciliation_need`, multi-chat substrate phase one, deferred apply contract removal, semantic changeset ledger horizon.
-- I102, I112, I113, I114 — active path, cascade-open-per-edge, V3.1 classifier lifecycle.
-- Requirement 10 — HITL reconciliation contract.
+- Requirements 10, 39, 42, 44, 45.
+- Assumptions A49, A88, A94, A95, A96.
+- Decisions D135, D137, D138, D139, D140, D143, D146, D148, D149, D153, D154.
+- Invariants I111, I112, I113, I114, I116, I117, I118, I120.
+- PLAN frontier items: `chat-runtime-secondary-chats`, `reconciliation-runtime`, `changeset-ledger`, `chat-context-provision`.
-**Likely to introduce (when `/ln-plan` slices Track 1–5)**
+**Likely future decisions when Tracks 2–5 are scoped**
-- New assumptions: thread substrate sufficiency under in-stream rendering; async classifier scheduling correctness; # mention as substrate mutation correctness; turn-zero pattern adequacy across kinds.
-- New decisions: thread substrate shape; reconciliation thread lifecycle; changeset migration sequence; direct-edit thread-opening UX.
-- New invariants: changeset attribution coverage; auto-confirmed never reaches the user; thread context spec is replayable.
+- Secondary-chat lifecycle and anchor policy.
+- Reconciliation chat lifecycle.
+- Changeset migration sequence.
+- Direct-edit attention/focus policy.
+- Context-handle persistence/expiry policy after changeset-backed item versions exist.
+- Snapshot-builder API and artifact schema boundaries for item, neighborhood, economic graph, and historical neighborhoods.
**Cross-references**
- [MULTI_CHAT.md](./MULTI_CHAT.md) §3 substrate, §4 context model, §5 reconciliation primitive
- [SIDE_CHAT.md](./SIDE_CHAT.md) §5 edit-patch routing, §13 substrate alignment
-- [PATCH_LEDGER.md](./PATCH_LEDGER.md) §Proposed Concepts (historical patch/patch_change vocabulary), §Reconciliation Flow, §Target Ordering, §Phase 2 Patch Ledger
-- [CONTINUOUS_WORKSPACE_HYBRID.md](./CONTINUOUS_WORKSPACE_HYBRID.md) §Design A/B/C, §Recommended direction
-- [memory/PLAN.md](../../memory/PLAN.md) §Active (continuous workspace), §Horizon (semantic changeset ledger, architect loop)
-- [memory/PLAN.md](../../memory/PLAN.md) Recently Completed — FE-674 V3.1 closing note; provides the shipped V3.1 surface that this umbrella will absorb
+- [PATCH_LEDGER.md](./PATCH_LEDGER.md) §Reconciliation Flow, §Target Ordering, §Phase 2 Patch Ledger
+- [CONTINUOUS_WORKSPACE_HYBRID.md](./CONTINUOUS_WORKSPACE_HYBRID.md) §Recommended direction
+- [memory/SPEC.md](../../memory/SPEC.md) Future Direction Register and Lexicon
+- [memory/PLAN.md](../../memory/PLAN.md) Sequencing, Dependencies, and runtime frontier definitions
+- [SUBSTRATE_STRANGLER_COORDINATION.md](./SUBSTRATE_STRANGLER_COORDINATION.md) §Upcoming substrate waves and expected interfaces
+- [INTENT_GRAPH_SEMANTICS.md](./INTENT_GRAPH_SEMANTICS.md) §Relation-policy registry and endpoint-relative labels
diff --git a/docs/design/INTENT_GRAPH_SEMANTICS.md b/docs/design/INTENT_GRAPH_SEMANTICS.md
index 78042e62..d59e2609 100644
--- a/docs/design/INTENT_GRAPH_SEMANTICS.md
+++ b/docs/design/INTENT_GRAPH_SEMANTICS.md
@@ -244,7 +244,7 @@ type KnowledgeEdge = {
## Relation-policy registry
-Not every visible graph edge should drive cascade, staleness, export explanation, or criteria generation. The relation-policy registry assigns capabilities per relation, gated by edge `support` and `status`.
+Not every visible graph edge should drive cascade, staleness, export explanation, criteria generation, or the same compact-context wording. The relation-policy registry assigns capabilities per relation, gated by edge `support` and `status`, and owns both operational directionality and endpoint-relative display labels. Code must not infer downstream/upstream impact or dependency/dependent wording from raw source/target coordinates alone.
| Axis | Meaning |
| --- | --- |
@@ -255,6 +255,9 @@ Not every visible graph edge should drive cascade, staleness, export explanation
| `reconciliation` | Generate a `reconciliation_need` when source changes |
| `criteria_help` | Used by interviewer to suggest criteria for the target |
| `weak_suggestion` | LLM-only signal; never user-visible by default |
+| `source_label` | Phrase used when rendering the edge from the source item's perspective. |
+| `target_label` | Phrase used when rendering the same edge from the target item's perspective. |
+| `source_change` / `target_change` | Which endpoint may require reconciliation when either endpoint changes. |
A row in the registry might say:
@@ -270,6 +273,55 @@ A row in the registry might say:
The actual registry should evolve through corpus probes. The point is that **policy is per-relation, per-axis**, not a binary "this edge counts."
+### Endpoint-relative labels for compact snapshots
+
+Compact context snapshots need both readable directions for an edge. A single canonical triple is not enough when the snapshot is centered on either endpoint.
+
+For an item-centered snapshot, relation policy should be able to render edges into buckets such as `dependencies` and `dependents` with phrases that make sense from the anchored item's perspective:
+
+```text
+X123: Lorem ipsum...
+ dependents:
+ constrains X200: Lorem ipsum...
+ motivates X198: Lorem ipsum...
+ dependencies:
+ presumes X2: Lorem ipsum...
+ is conditioned by X78: Lorem ipsum...
+ proves X45: Lorem ipsum...
+```
+
+The bucket and phrase are relation-policy outputs, not string reversals. Some relations have natural canonical source-to-target wording (`constraint constrains requirement`), while others naturally point from a dependent claim to a premise (`decision assumes assumption`) or from an oracle to a claim (`criterion verifies requirement`). The registry must therefore store endpoint-relative labels and operational source-change/target-change behavior separately.
+
+Neighborhood snapshots can be selected by task rather than by one universal radius:
+
+- **Immediate adjacency** — all relation-policy-visible incident edges around the anchor; good default for side chat orientation.
+- **Dependencies** — premises, constraints, assumptions, motivating goals, and evidence the anchor relies on; useful for “why does this item stand?” questions.
+- **Dependents / impact** — claims likely to be affected if the anchor changes; useful for edit preview, cascade, and reconciliation.
+- **Evidence** — examples, criteria, witnesses, counterexamples, and checkability context; useful for QA and verification discussion.
+- **Reconciliation** — open needs, affected targets, source changes, and relation-policy rationale; useful for reconciliation chats.
+- **Historical** — once changesets exist, the neighborhood around the changeset that originally captured an item or last updated it; useful for reviving the context in which a claim was made, not just its current graph surroundings.
+
+Historical neighborhoods should be changeset-derived, not approximated from current graph order. Before the changeset ledger, snapshot builders should avoid pretending they can answer “what was around this item when it was captured?” with precision.
+
+A relation policy row should support at least:
+
+```ts
+type RelationPolicy = {
+ relation: RelationKind
+ canonicalLabel: string
+ sourceLabel: string
+ targetLabel: string
+ sourceRole: string
+ targetRole: string
+ sourceBucketForTargetSnapshot: 'dependencies' | 'dependents' | 'evidence' | 'contextual'
+ targetBucketForSourceSnapshot: 'dependencies' | 'dependents' | 'evidence' | 'contextual'
+ onSourceChange: 'affects_source' | 'affects_target' | 'affects_both' | 'none' | 'contextual'
+ onTargetChange: 'affects_source' | 'affects_target' | 'affects_both' | 'none' | 'contextual'
+}
+```
+
+The exact bucket enum can be narrower in implementation, but the invariant is that context packs and reconciliation never recover directionality from verb names alone.
+
## Edge-local neighborhoods
For LLM collaboration the most important practical change is to provide **edge-local neighborhoods**, not only grouped item lists. A neighborhood pack for one claim:
diff --git a/docs/design/SUBSTRATE_STRANGLER_COORDINATION.md b/docs/design/SUBSTRATE_STRANGLER_COORDINATION.md
index f319b5f2..b65e4f3b 100644
--- a/docs/design/SUBSTRATE_STRANGLER_COORDINATION.md
+++ b/docs/design/SUBSTRATE_STRANGLER_COORDINATION.md
@@ -39,7 +39,9 @@ Owns:
- shared application-service / command-handler seam under existing routes and new capability adapters
- capability parity tests for route path vs capability path
-- minimal relation-policy directionality needed by cascade and changesets
+- minimal relation-policy directionality needed by cascade, context snapshots, and changesets
+- endpoint-relative relation labels for dependency/dependent snapshot rendering
+- item/neighborhood/economic graph context snapshot builders
- `changeset` / `change` schema and stores
- `specification.latest_changeset_id`
- proposal-turn opened/base changeset identity
@@ -63,6 +65,7 @@ Owns:
- review status badges and proposal-artifact presentation states
- read-only graph/workspace improvements
- mocked or artifact-only scenario-options UI probes
+- UI rendering for snapshot artifacts and endpoint-relative dependency/dependent groups when backed by server fixtures
Acceptance posture:
@@ -82,6 +85,7 @@ Coordinate before touching these:
- turn completion / chat transition logic
- shared API types when changing existing frontend DTOs
- prompt/context pack contracts that become canonical mutation inputs
+- context snapshot artifact schemas and mention-resolution contracts
Lower-conflict frontend work usually lives in:
@@ -89,6 +93,65 @@ Lower-conflict frontend work usually lives in:
- Ladle stories and fixtures
- read-only graph/workspace route presentation
- candidate/proposal/graph-review renderers backed by static artifacts
+- context snapshot artifact renderers backed by server-generated fixtures
+
+## Upcoming substrate waves and expected interfaces
+
+This section is a coordination forecast, not an implementation commitment. The rule remains: existing frontend REST/SSE contracts stay stable until a scoped product slice cuts over. The backend work should first produce server-owned functions and capability contracts that the frontend can treat as future affordances, static fixtures, or debug/probe inputs.
+
+### Wave 1 — Intent graph semantics and relation policy
+
+What the substrate lane should provide first:
+
+| Interface shape | Projected names | Expected use |
+| --- | --- | --- |
+| Server relation-policy functions | `getRelationPolicy(relation)`, `validateIntentEdge(input)`, `renderIntentEdgeEndpoint(edge, anchorItemId)`, `bucketIntentEdgeForSnapshot(edge, anchorItemId)` | Frontend/context packs can display mixed-direction edges without guessing from `from_item_id` / `to_item_id`. |
+| Server graph read/query helpers | `readIntentGraph(specificationId)`, `readIntentItemsById(specificationId, itemIds)`, `readIntentNeighborhood(input)` | Read-only graph and snapshot builders; no mutation authority. |
+| Capability contracts | `intentGraph.validateEdge`, later `intentGraph.query`, `intentGraph.renderNeighborhood` | Agent/probe tools for graph reads and edge validation. |
+
+Frontend expectation: relation wording, dependency/dependent grouping, and reconciliation direction should come from server policy or fixtures generated by that policy. UI code should not hard-code inverse labels such as “is constrained by” by reversing the verb.
+
+### Wave 2 — Context snapshot builders for chats
+
+What the substrate lane should provide around chat context:
+
+| Interface shape | Projected names | Expected use |
+| --- | --- | --- |
+| Item snapshot builder | `buildIntentItemContextSnapshot({ specificationId, itemIds })` | `#` mentions and explicit item inclusion. |
+| Neighborhood snapshot builder | `buildIntentNeighborhoodContextSnapshot({ specificationId, anchorItemIds, mode })` where `mode` starts with `immediate`, `dependencies`, `dependents`, `evidence`, `reconciliation` | Side-chat turn-zero, graph-launched QA, edit-impact previews, reconciliation context. |
+| Economic graph snapshot builder | `buildEconomicIntentGraphContextSnapshot({ specificationId, budget })` | New unanchored secondary chats in an existing spec. |
+| Snapshot renderer | `renderContextSnapshotArtifact(snapshot)` / context-pack renderer | Produces transcript-visible turn artifacts and compact prompt text. |
+| Mention resolver | `resolveIntentItemReferences({ specificationId, refs })` | Server-owned resolution for `#D7` / reference-code mentions. |
+
+Frontend expectation: new chats or mentions should request/receive replayable snapshot artifacts, not mutate a hidden chat-context table. Whole-graph snapshots are historical context only; they should not create handles for every graph item. Item handles and stale refresh wait for real item versions from the changeset ledger.
+
+### Wave 3 — Changeset ledger and mutation tools
+
+What the substrate lane should provide once semantic mutations become first-class:
+
+| Interface shape | Projected names | Expected use |
+| --- | --- | --- |
+| Changeset application handlers | `submitChangeset(input)`, `applyAcceptedChangeset(input)`, `readLatestChangeset(specificationId)` | One semantic mutation spine for graph edits, proposal acceptance, reconciliation, and future agent edits. |
+| Change variants | `intentItem.create`, `intentItem.updateContent`, `intentItem.retire`, `intentEdge.create`, `intentEdge.delete`, later `contextHandle.refresh` only as process/replay state if needed | Frontend submits product intent, not raw DB updates. |
+| Capability contracts | `changeset.submit`, later `changeset.apply`, `changeset.get`, `reconciliationNeed.list`, `reconciliationNeed.proposeResolution`, `reconciliationNeed.applyResolution` | Agent tools stay proposal-only until user/HITL acceptance applies truth. |
+| Version reads | `getIntentItemVersion(itemId)` backed by latest applied changeset / item revision | Enables chat handles to refresh only changed subjects. |
+| Historical neighborhood builders | `buildHistoricalIntentNeighborhoodSnapshot({ itemId, basis: 'original_capture' | 'last_update' })` | Revives the graph context around the changeset that captured or last updated an item. |
+
+Frontend expectation: do not implement real `accept`, `apply`, `resolve`, or agent graph-edit flows against ad hoc route writes. Once this wave lands, accepted semantic mutations should return changeset identity, updated graph projection, and any created/updated reconciliation needs.
+
+### Wave 4 — Agent-facing tool projection
+
+Capability contracts should project the same server handlers used by routes. Likely agent tool families:
+
+| Tool family | Authority | Notes |
+| --- | --- | --- |
+| `intentGraph.*` reads / validation / snapshot rendering | `read_only` | Safe for probes and chat context. |
+| `chat.*` start/read/ensure/submit operations | `read_only` / `commit_truth` depending on operation | Existing `chat.getPrimary`, `chat.read`, `chat.ensureReady`, and `turn.submitResponse` are the current foundation. Secondary-chat start/focus should follow this shape. |
+| `changeset.submit` | `proposal_only` initially | Lets agents propose graph mutations without committing truth. |
+| `changeset.apply` / reconciliation apply tools | `commit_truth` / `commit_process_debt` | Should require explicit user/HITL authority. |
+| `workspace.*` / `web.*` context tools | `read_only` | Existing capability registry already names these as safe adapter targets. |
+
+Adapters may expose different tool names for AI SDK, JSONL, Pi, or CLI ergonomics, but those names must remain projections over Brunch-owned capability ids.
## Backend migration sequence
@@ -129,4 +192,5 @@ A frontend flow may switch to the new substrate only when all are true:
- `MULTI_CHAT.md` owns shipped chat/reconciliation schema rationale.
- `PATCH_LEDGER.md` owns changeset/change algorithmic pressure under historical patch vocabulary.
- `CONVERSATIONAL_WORKSPACE_RUNTIME.md` owns the umbrella runtime synthesis.
+- `INTENT_GRAPH_SEMANTICS.md` owns relation-policy directionality, endpoint-relative labels, and neighborhood snapshot modes.
- `memory/PLAN.md` owns actual frontier ordering.
diff --git a/memory/PLAN.md b/memory/PLAN.md
index b860f0cc..ea0e48b8 100644
--- a/memory/PLAN.md
+++ b/memory/PLAN.md
@@ -15,7 +15,7 @@
The interaction model is mature: four-phase interview, interviewer-autonomous question format, phase-agnostic preface cards with workspace exploration, structured review with per-item commenting, observer knowledge extraction, workflow ownership extraction, distribution hardening, graph view's structured-list peer route, the first relation-first observer capture seam, the multi-chat substrate, side-chat V3.0 hard-impact cascade, and side-chat V3.1 agent-grouped reconciliation resolution all ship as working product.
-The next product arc is a **continuous conversational workspace** plus a stronger semantic/generative substrate. Continuous workspace is active in a parallel lane and gives the chat runtime a stable phase-addressable host. The FE-705 branch contributes an integration substrate — a local agent capability CLI and external LLM-as-user probe harness — that should be reconciled into main before graph-review and scenario-options work depends on generated completed-spec fixtures. After that, the highest-coordination work is intent-graph semantics and the semantic changeset ledger; FE-701 should follow soon after the FE-705 reconciliation because the current schema already carries transitional multi-chat / reconciliation placeholders that only become coherent once `changeset` / `change` owns semantic mutation history. Lower-coordination provider, gitignore, and web-research work can proceed in parallel.
+The next product arc is the **Conversational Workspace Runtime** umbrella (`docs/design/CONVERSATIONAL_WORKSPACE_RUNTIME.md`) plus a stronger semantic/generative substrate. The umbrella synthesizes MULTI_CHAT, SIDE_CHAT, PATCH_LEDGER, and CONTINUOUS_WORKSPACE_HYBRID into five sub-tracks: workspace shell (Track 1, shipped as `continuous-workspace` / FE-709), inline secondary-chat runtime over the existing chat/turn substrate (`chat-runtime-secondary-chats`), reconciliation runtime absorption (`reconciliation-runtime`), changeset ledger (`changeset-ledger`), and transcript-first chat context provision (`chat-context-provision`). The shell is now the stable host; schema-level `thread` is deferred until chat/turn proves insufficient. Secondary chats are the near-term runtime primitive for side, reconciliation, qa, and strategy conversations. The chat runtime is the critical unblocker for reconciliation absorption; chat context provision can proceed against chat/turn with explicit transcript snapshots and graph-item handles. The changeset ledger runs in parallel. The umbrella supersedes the independent side-chat V4a persistence horizon — persistent side-chat history becomes inline secondary chats in the workspace. The FE-705 branch contributes an integration substrate — a local agent capability CLI and external LLM-as-user probe harness — that should be reconciled into main before graph-review and scenario-options work depends on generated completed-spec fixtures. After that, the highest-coordination work is intent-graph semantics and the semantic changeset ledger; FE-701 should follow soon after the FE-705 reconciliation because the current schema already carries transitional multi-chat / reconciliation placeholders that only become coherent once `changeset` / `change` owns semantic mutation history. Lower-coordination provider, gitignore, and web-research work can proceed in parallel.
The May 2026 intent-spec, multi-chat, changeset-ledger, prompt/context, and agent-mutation design notes are reconciled into one direction. `docs/design/MULTI_CHAT.md` is the substrate document. `docs/design/SIDE_CHAT.md` describes side-chat V1 / V2 / V3.0 / V3.1 / V4 phasing on top of that substrate. `docs/design/PATCH_LEDGER.md` remains historical deeper design pressure for semantic mutation history, but canonical future-facing vocabulary is `changeset` / `change`. The product-layer ontology trajectory is split out as `docs/design/INTENT_GRAPH_SEMANTICS.md` and `docs/design/BEHAVIORAL_KERNELS.md`; broader synthesis lives in `docs/archive/design/INTENT_SPEC_EVOLUTION.md`. FE-705's branch-local strategy/proposal notes add scenario options, graph-review oracle, chat-local strategies, and concern/dependency mapping; those notes should become a canonical design doc when the branch is integrated. Coordination uses a substrate-strangler posture: keep existing frontend REST/SSE contracts stable while route adapters and capability adapters converge on shared server-owned handlers, then cut over UI flows only after parity and changeset-backed authority exist. The dev-layer self-tooling trajectory lives in `docs/design/ln-skills/EVOLUTION.md`.
@@ -23,15 +23,17 @@ The May 2026 intent-spec, multi-chat, changeset-ledger, prompt/context, and agen
### Active
-1. `continuous-workspace` — in progress in parallel lane — stable phase-addressable host for the chat runtime.
-2. `agent-fixture-substrate` — branch-complete off main, reconciling — FE-705 integration substrate for JSONL agent capability CLI and LLM-as-user probes.
+1. `agent-fixture-substrate` — branch-complete off main, reconciling — FE-705 integration substrate for JSONL agent capability CLI and LLM-as-user probes.
### Next
-1. `intent-graph-semantics` — highest-coordination semantic substrate after FE-705 reconciliation.
-2. `changeset-ledger` — schedule soon after FE-705 reconciliation; semantic history spine needed before canonical proposal acceptance, direct-edit atomicity, and productized scenario options.
-3. `graph-review-scenario-options` — artifact-only critique/probe lane; can advance in parallel with FE-700 if it does not commit canonical graph truth.
-4. `productized-scenario-options` — user-facing acceleration surface after FE-700 semantics, FE-701 changesets, and graph-review probes.
+1. `chat-runtime-secondary-chats` — Track 2 of the runtime umbrella; immediate successor to continuous-workspace. Implement inline/collapsible secondary chats over existing chat/turn; explicitly defer a `thread` table.
+2. `intent-graph-semantics` — highest-coordination semantic substrate after FE-705 reconciliation.
+3. `changeset-ledger` — Track 4 of the runtime umbrella; parallel with Track 2; semantic history spine needed before canonical proposal acceptance, direct-edit atomicity, and productized scenario options.
+4. `chat-context-provision` — Track 5 of the runtime umbrella recast as transcript-first context; can proceed against chat/turn once secondary-chat entry/anchor shape is settled.
+5. `reconciliation-runtime` — Track 3 of the runtime umbrella; after Track 2 + Track 4 provide the secondary-chat surface and durable attribution.
+6. `graph-review-scenario-options` — artifact-only critique/probe lane; can advance in parallel with FE-700 if it does not commit canonical graph truth.
+7. `productized-scenario-options` — user-facing acceleration surface after FE-700 semantics, FE-701 changesets, and graph-review probes.
### Parallel / Low-conflict
@@ -44,8 +46,7 @@ The May 2026 intent-spec, multi-chat, changeset-ledger, prompt/context, and agen
- `relation-first-observer-enrichment`
- `architect-generator-loop`
- `server-mini-library-compartmentalization`
-- `side-chat-persistence-v4a`
-- `side-chat-v4b-item-versioning`
+- `side-chat-v4b-item-versioning` (depends on `changeset-ledger`)
- `dashboard-summaries`
- `spatial-graph-layout`
- `graph-view-active-path-filter`
@@ -59,16 +60,55 @@ The May 2026 intent-spec, multi-chat, changeset-ledger, prompt/context, and agen
### continuous-workspace
-- **Name:** Continuous workspace / phase-addressable interview surface
-- **Linear:** unassigned in this plan snapshot
+- **Name:** Continuous workspace / phase-addressable interview surface (Conversational Workspace Runtime — Track 1)
+- **Linear:** FE-709
- **Kind:** structural
-- **Status:** in-progress
+- **Status:** done
- **Objective:** Replace per-phase rendering boundaries with a cumulative center pane, realized phase sections, one chat runtime per specification, sidebar section navigation, scroll/focus behavior, and preservation of the single actionable frontier at the current reachable phase.
- **Why now / unlocks:** Workflow read/write ownership is extracted, the multi-chat substrate ships chat containers below the specification, and side-chat V3.0/V3.1 closed the cascade surface. This gives future side-chat persistence, strategy chats, and graph/workspace routes a stable host without introducing a second durable workflow model.
- **Acceptance:** Realized phase sections remain legible, future sections stay unreachable until valid, navigation is focus/scroll state only, and the current phase retains exactly one actionable frontier/recovery/handoff/completion affordance.
- **Verification:** Manual workspace walkthroughs across kickoff-ready, active, review-active, recovery, close-to-next-phase, resume/reload, and future-phase deep-link states; regression tests around route/workflow state where available.
- **Traceability:** A58; D86, D87, D110, D113, D114; I24, I102.
-- **Design docs:** `docs/design/CONTINUOUS_WORKSPACE_HYBRID.md`; umbrella synthesis in `docs/design/CONVERSATIONAL_WORKSPACE_RUNTIME.md`.
+- **Design docs:** `docs/design/CONTINUOUS_WORKSPACE_HYBRID.md`; umbrella synthesis in `docs/design/CONVERSATIONAL_WORKSPACE_RUNTIME.md` (Track 1).
+
+### chat-runtime-secondary-chats
+
+- **Name:** Chat runtime — inline secondary chats (Conversational Workspace Runtime — Track 2)
+- **Linear:** FE-710 if retitled; otherwise unassigned in this plan snapshot
+- **Kind:** structural
+- **Status:** not-started / replanned
+- **Objective:** Render side, reconciliation, qa, and strategy chats inline as collapsible secondary chats in the workspace using the existing chat/turn substrate. Defer schema-level `thread`; do not add `thread` / `turn.thread_id` unless a later RFC proves chat/turn insufficient. Retire the SideChatPopover as a UI surface only after parity exists over durable secondary chats.
+- **Why now / unlocks:** Track 1 (workspace shell) ships, providing the stable host. Inline secondary chats are the critical unblocker for reconciliation absorption (Track 3) and give chat-context provision (Track 5) stable initiating anchors without creating a competing strategy/context substrate. Supersedes the prior side-chat V4a persistence horizon — persistent side-chat history becomes durable secondary chats rendered inline.
+- **Acceptance:** Secondary chat kinds (`side`, `reconciliation`, `qa`, `strategy`) are representable with chat/turn; each active/resumable chat preserves one open assistant/system-first frontier turn; secondary chats render inline/collapsible in the unified workspace; SideChatPopover retires as cutover; transient staged-patches strip does not become a new source of semantic truth; turn-zero (`turn_kind='kickoff'`) seeds secondary chats with explicit context snapshots.
+- **Verification:** Chat/turn persistence and reload tests, inline secondary-chat rendering tests, one-open-frontier-per-chat tests, manual walkthroughs for side/qa/strategy chat creation/display/collapse, and regression on existing interview flow.
+- **Traceability:** Requirement 45; A49, A94; D86, D87, D110, D114, D138, D153; I111, I116, I120.
+- **Design docs:** `docs/design/CONVERSATIONAL_WORKSPACE_RUNTIME.md` §3.2 + §5 Track 2; `docs/design/MULTI_CHAT.md`; `docs/design/SIDE_CHAT.md`; `docs/design/SPEC_EVOLUTION_STRATEGIES.md`.
+
+### reconciliation-runtime
+
+- **Name:** Reconciliation runtime — async-by-default with in-stream secondary chat (Conversational Workspace Runtime — Track 3)
+- **Linear:** unassigned in this plan snapshot
+- **Kind:** structural
+- **Status:** not-started
+- **Objective:** Absorb reconciliation into the unified chat surface as a target-grouped secondary chat with async-by-default classifier scheduling and a "Reconcile Now" user trigger. Retire the standalone PendingReviewSection. Auto-confirmed rows resolve invisibly; only `auto-edit` (one-click apply) and `substantive` (judgment affordances) reach the user.
+- **Why now / unlocks:** Tracks 2 (chat runtime) and 4 (changeset ledger) provide the secondary-chat surface and durable attribution. The reconciliation chat replaces the V3.1 Pending review section and the side-chat popover's reconciliation surface with a conversational target-grouped chat inside the workspace.
+- **Acceptance:** Reconciliation chat renders target-grouped (topologically sorted upstream-first per PATCH_LEDGER target ordering); async classifier runs in background; auto-confirmed never surfaces; auto-edit has one-click apply; substantive has judgment affordances; "Reconcile Now" trigger in workspace shell; standalone PendingReviewSection retired as cutover.
+- **Verification:** Reconciliation chat rendering tests, classifier scheduling tests, target-ordering tests, manual walkthroughs for async classification + Reconcile Now trigger, regression on existing reconciliation flow.
+- **Traceability:** Requirement 45; A49, A88, A96; D135, D137, D138, D146, D153; I111, I113, I114, I120.
+- **Design docs:** `docs/design/CONVERSATIONAL_WORKSPACE_RUNTIME.md` §3.3 + §5 Track 3; `docs/design/MULTI_CHAT.md` §5; `docs/design/PATCH_LEDGER.md` §Target Ordering, §Reconciliation Flow.
+
+### chat-context-provision
+
+- **Name:** Chat context provision — transcript-first snapshots, handles, `#` mention, turn-zero (Conversational Workspace Runtime — Track 5)
+- **Linear:** unassigned in this plan snapshot
+- **Kind:** structural
+- **Status:** not-started
+- **Objective:** Implement transcript-first context provision for chats: turn-zero inserts explicit context snapshots stored on turns and derived from chat kind/strategy/anchors; `#` mention resolves to item ids, an inserted context snapshot, and an active chat handle; before new assistant turns, stale handles detect newer graph item versions/fingerprints and insert fresh snapshots only for changed subjects. Do not persist a hidden context-spec table by default. TOON or another compact graph serializer may format inserted snapshots/context packs.
+- **Why now / unlocks:** Secondary chats and strategy chats need stable, replayable prompt context that survives multi-chat edits without ambient graph rehydration. Transcript-first snapshots let prompt/context engineering remain the authority while preserving replay and audit.
+- **Acceptance:** Chat prompts use transcript context first; initial anchors and mentions insert visible/replayable context snapshot artifacts on turns; active chat handles store referenced item ids plus last-snapshotted version/fingerprint and refresh changed graph subjects by inserting new snapshots before the next assistant turn; unchanged handles do not duplicate snapshots; snapshots preserve old versions rather than mutating; context builders can render one-or-more item snapshots, item-neighborhood snapshots, and economic whole-graph snapshots via typed context packs; neighborhood modes cover immediate adjacency, dependencies, dependents/impact, evidence, and reconciliation, with changeset-historical neighborhoods added once the ledger can identify original-capture and last-update surroundings; handles are revocable or expire by explicit transcript event/policy.
+- **Verification:** Context snapshot artifact tests; changeset-backed stale-handle refresh tests across changes from another chat; no-refresh tests for unchanged item versions; `#` mention resolution/disambiguation tests; structured JSON assertions plus selected golden renderings for item-list, neighborhood-mode, and economic-graph context builders; historical-neighborhood tests once changesets can identify original capture / last update context; turn-zero prompt assembly tests per chat kind/strategy; and manual walkthroughs for side/qa/strategy chat context. Handle freshness waits on real item versions from `changeset-ledger` rather than temporary fingerprints.
+- **Traceability:** Requirement 45; A80, A81, A84, A85, A95; D136, D137, D139, D140, D154; I112, I120.
+- **Design docs:** `docs/design/CONVERSATIONAL_WORKSPACE_RUNTIME.md` §3.5 + §5 Track 5; `docs/design/SPEC_EVOLUTION_STRATEGIES.md`; prompt/context pack docs.
### agent-fixture-substrate
@@ -91,8 +131,8 @@ The May 2026 intent-spec, multi-chat, changeset-ledger, prompt/context, and agen
- **Status:** not-started
- **Objective:** Refine the ontology and relation policy so the graph can represent invariants, examples/counterexamples, constraint subtypes, narrowed decisions, witness strength, checkability gaps, and operational edge behavior as source/destination material for future generative features.
- **Why now / unlocks:** Candidate generation, behavioral kernels, graph review, scenario-options acceleration, architect proposals, direct-edit cascade, and downstream verification-aware decomposition all need a sharper semantic target than the current exploration/review ontology. This semantic-layer lane is most likely to collide with parallel work, so it should land before broad observer enrichment or canonical candidate-bundle acceptance.
-- **Acceptance:** `invariant` and `example` are first-class durable kinds; examples are subtyped; `decision` is narrowed; `constraint`, `criterion`, and `invariant` semantics are enriched; `checkability` and witness strength are represented; relation families, negative relations, edge epistemic metadata, and relation-policy directionality are explicit.
-- **Verification:** Corpus/fixture observer probes comparing old vs refined ontology; relation-policy unit tests for mixed-direction relations; graph-review manual assessment for precision/noise; context-pack probe outputs show authority, witness, relation support, and directionality labels.
+- **Acceptance:** `invariant` and `example` are first-class durable kinds; examples are subtyped; `decision` is narrowed; `constraint`, `criterion`, and `invariant` semantics are enriched; `checkability` and witness strength are represented; relation families, negative relations, edge epistemic metadata, relation-policy directionality, and endpoint-relative display labels for dependency/dependent context snapshots are explicit.
+- **Verification:** Corpus/fixture observer probes comparing old vs refined ontology; relation-policy unit tests for mixed-direction relations and endpoint-relative labels; graph-review manual assessment for precision/noise; context-pack probe outputs show authority, witness, relation support, dependency/dependent grouping, and directionality labels.
- **Traceability:** Requirement 38; A77, A78, A80, A81, A84; D134, D136, D137, D139, D140.
- **Design docs:** `docs/design/INTENT_GRAPH_SEMANTICS.md`; `docs/archive/design/INTENT_SPEC_EVOLUTION.md`; FE-705 strategy/proposal notes for relation directionality.
@@ -215,19 +255,6 @@ The May 2026 intent-spec, multi-chat, changeset-ledger, prompt/context, and agen
- **Traceability:** code organization convention in `AGENTS.md`.
- **Design docs:** none.
-### side-chat-persistence-v4a
-
-- **Name:** Side-chat persistence — V4a (multi-chat Phase 2 substrate)
-- **Linear:** FE-675 umbrella, V4a half
-- **Kind:** structural
-- **Status:** horizon
-- **Objective:** Persist side-chat client turns into the existing `chat` / `turn` tables with `chat.kind='side_chat'`, load prior side-chat sessions on remount, and surface an "Old chats" affordance per pinned item/spec.
-- **Why now / unlocks:** Deprioritized below continuous workspace and semantic/generative substrate. Phase 1 substrate already ships schema support; the remaining decision is the anchor model (`chat` row anchor fields vs deferred `chat_focus` table).
-- **Acceptance:** Side-chat sessions survive remount/reload and remain coherent with graph truth without introducing a second workflow model.
-- **Verification:** Persistence/reload tests and manual side-chat walkthroughs.
-- **Traceability:** Requirement 39; D138; I111.
-- **Design docs:** `docs/design/MULTI_CHAT.md` §10 Phase 2; `docs/design/SIDE_CHAT.md` §9 V4 row.
-
### side-chat-v4b-item-versioning
- **Name:** Side-chat V4b — item versioning + branched exploration
@@ -347,19 +374,24 @@ The May 2026 intent-spec, multi-chat, changeset-ledger, prompt/context, and agen
## Recently Completed
+- [2026-05-13] `continuous-workspace` — Done: FE-709 / PR #134. Replaced per-phase InterviewView with ContinuousWorkspaceView (cumulative center pane), extracted `useContinuousWorkspaceController`, added sidebar scroll-spy via WorkspaceFocusContext, extracted shared controller helpers to core, retired route-first test assumptions. Verified: `npm run verify` 1213 / 1214 pass (1 pre-existing flake). Watch: Step 5 route-collapse decision deferred — hybrid works as intended.
- [2026-05-11] `side-chat-v3-1-agent-grouped-reconciliation` — Done: FE-674 / PR #124 + downstack closed the V3.x arc end-to-end with spec-level classifier route, per-row reset route, agent classification lifecycle, chips, per-class actions, and bulk Confirm-all / Apply-all-suggested. Verified: `npm run verify` 1178 / 1179 pass with one unrelated `side-chat-route` flake. Watch: A88 outer-loop walkthrough on a dense spec remains open to assess legibility vs V3.0's flat list.
- [2026-05-11] `fe-698-reconciliation-context-pack` — Done: added proposal-only reconciliation prompt/context scenario rendering open reconciliation needs with source/target anchors, reason/status, prompt/context fingerprints, and read-only capability metadata. Verified: `npm run verify`. Watch: next FE-698 work can broaden read-only/proposal-only probes and Pi adapter spike without treating this pack as a resolution agent.
-- [2026-05-08] `side-chat-v3-0-hard-impact-cascade` — Done: FE-674 / PR #115 + #116 + #117 shipped hard-impact cascade through `reconciliation_need`, Pending review listing, and idempotent resolve. Verified: `npm run verify` (1063 tests, 0 lint warnings). Watch: A88 mechanical grouping remains only partially validated until outer-loop walkthrough on dense graphs.
-
Older history: `docs/archive/PLAN_HISTORY.md`
## Dependencies
```text
-TRACK A — Workspace shell (parallel colleague lane)
-continuous-workspace
- ├──→ stable host for side-chat-persistence-v4a
- └──→ workspace-aware graph / structured-list peer routes
+TRACK A — Conversational Workspace Runtime umbrella
+continuous-workspace (Track 1, done — FE-709)
+ └──→ chat-runtime-secondary-chats (Track 2; no schema-level thread)
+ ├──→ reconciliation-runtime (Track 3, also needs Track 4)
+ └──→ chat-context-provision (Track 5; transcript-first snapshots/handles)
+changeset-ledger (Track 4, parallel with Track 2)
+ ├──→ richer attribution in reconciliation-runtime (Track 3)
+ ├──→ real item versions for chat-context-provision handle freshness (Track 5)
+ ├──→ original-capture / last-update historical neighborhoods for context snapshots (Track 5)
+ └──→ unlocks architect-generator-loop and side-chat-v4b-item-versioning
TRACK B — Agent fixture substrate / strangler handler seam
prompt/context scenario substrate foundation (completed)
@@ -395,10 +427,13 @@ workspace-gitignore-assist
productized-web-research
LOWER-PRIORITY / DEFERRED
-side-chat-persistence-v4a / side-chat-v4b-item-versioning
+side-chat-v4b-item-versioning (depends on changeset-ledger)
spatial-graph-layout + graph-view-active-path-filter
dashboard-summaries
mcp-adapter / file-based-persistence / typed-fixture-builder-convergence
structured-development-spec-registry
portability-boundaries
+
+RETIRED
+side-chat-persistence-v4a — superseded by chat-runtime-secondary-chats (Track 2)
```
diff --git a/memory/SERVER_REFACTOR_NOTES.md b/memory/SERVER_REFACTOR_NOTES.md
new file mode 100644
index 00000000..951bc418
--- /dev/null
+++ b/memory/SERVER_REFACTOR_NOTES.md
@@ -0,0 +1,60 @@
+# Temporary Review Notes — Remaining `src/server/` Structuring Findings
+
+Captured from the `src/server/` structure review after the `db.ts` extraction was completed. This is a temporary working note, not canonical architecture truth; reconcile durable decisions back into `memory/SPEC.md` / `memory/PLAN.md` if selected for implementation.
+
+## Already addressed in this thread
+
+- `db.ts` now acts as a public persistence facade over private `src/server/db/*-store.ts` modules:
+ - `annotation-store.ts`
+ - `edit-impact-store.ts`
+ - `entity-projection-store.ts`
+ - `intent-graph-store.ts`
+ - `reconciliation-store.ts`
+ - `review-materialization-store.ts`
+ - `specification-store.ts`
+ - `workflow-store.ts`
+
+## Remaining findings
+
+1. **`app.ts` is both route registry and workflow orchestrator** — category: depth / seam — impact: high
+ - **Files:** `src/server/app.ts`, `*-route.ts`, `chat-route-transition.ts`, `turn-response-transition.ts`, `phase-intent-runtime.ts`
+ - **Problem:** `app.ts` still wires Express routes, parses params, maps errors, manages observer capture concurrency, validates AI SDK messages, runs chat transitions, streams interviewer output, persists artifacts, and registers unrelated route families. Some route families have their own `*-route.ts` handlers while specification/chat routes remain inline.
+ - **Possible direction:** Keep `createApp` as the public composition root, but move route families and shared request/error helpers behind `src/server/app/*` private modules. The chat streaming route likely deserves its own route module because it is already a substantial imperative shell.
+ - **Benefit:** Clearer HTTP ownership, smaller composition root, easier addition of provider/setup/gitignore routes, and less risk that route-local concerns become global `app.ts` state.
+
+2. **The capability adapter is not yet a clean adapter over product operations** — category: seam / coupling — impact: medium-high
+ - **Files:** `src/server/capabilities.ts`, `agent-jsonl.ts`, `capability-registry.ts`, `chat-route-transition.ts`, `turn-response-transition.ts`, `core.ts`, `schema.ts`
+ - **Problem:** SPEC/PLAN describe the agent capability CLI as an adapter over Brunch-owned capability contracts, but `capabilities.ts` still imports workflow transitions, core functions, DB helpers, and schema directly. That makes the agent path a parallel orchestration surface rather than a thin transport adapter.
+ - **Possible direction:** Split `capabilities.ts` into a public root plus `capabilities/*` private handlers. Route selected capability implementations through named application operations that are also usable by HTTP routes, with JSONL remaining protocol glue.
+ - **Benefit:** Prevents agent paths from bypassing server-owned mutation semantics and makes future MCP / external harness adapters safer.
+
+3. **Provider/model construction is scattered across server shells** — category: seam / model — impact: medium
+ - **Files:** `src/server/side-chat-route.ts`, `src/server/reconciliation-agent.ts`, likely interviewer / observer construction paths.
+ - **Problem:** Direct `@ai-sdk/anthropic` imports and env reads remain in route/agent modules. SPEC names an **AI runtime provider** seam and says interviewer/observer model creation should not encode direct provider imports or environment-variable reads as product truth.
+ - **Possible direction:** When `first-run-provider-setup` starts, make provider/model resolution a real server subsystem rather than patching each caller independently.
+ - **Benefit:** One credential/model precedence story, less duplicated provider knowledge, and a cleaner path to OpenRouter/provider-neutral routing.
+
+4. **Lexicon drift still makes server ownership harder to read** — category: naming — impact: medium
+ - **Canonical terms:** `specification`, `intent graph`, `intent item`, `intent edge`, `changeset/change`.
+ - **Remaining deviations:**
+ - Many tests and some helpers still use `project` variables for specification rows, e.g. `const project = createSpecification(...)`, `project.id`.
+ - `createLegacyKickoffTurnForTesting(db, projectId)` takes a specification id and should prefer `specificationId` if retained.
+ - API/path/function names still expose `knowledge-items` / `knowledge-edges`; persistence compatibility is acknowledged, but new server structure should prefer intent terminology at module boundaries.
+ - CLI/help/test vocabulary still contains historical `patch` wording; SPEC says `changeset/change` supersedes patch vocabulary.
+ - **Possible direction:** Run a targeted naming refactor once active semantic-schema work decides how aggressively to rename public API paths vs internal implementation.
+
+5. **Legacy test scaffolding preserves old workflow rows** — category: model / naming — impact: medium
+ - **Files:** `src/server/test-support/legacy-control-rows.ts`, usages in `app.test.ts`, `core.test.ts`
+ - **Problem:** The product is pre-release and SPEC says projection-only control cards are current truth, but tests still keep `createLegacyKickoffTurnForTesting` to fabricate older durable kickoff rows. It may be useful as regression coverage, but currently reads like supported compatibility.
+ - **Possible direction:** Either delete the legacy-path tests if no longer product-relevant, or quarantine them under an explicit legacy regression area with a narrow purpose.
+
+6. **Test files still mirror some of the flat spread** — category: testability / coupling — impact: medium
+ - **Files:** especially `src/server/app.test.ts`, `src/server/db.test.ts`, plus many top-level `*.test.ts`.
+ - **Problem:** The persistence implementation is now split, but the largest tests still exercise many seams through broad files. This makes it harder to tell which subsystem owns an invariant.
+ - **Possible direction:** As further modules are deepened, move or split tests around the public seams: route-family tests near route-family modules, store tests by semantic store, capability adapter tests around the adapter seam.
+
+## Suggested next refactor candidates
+
+1. `app.ts` private route modules — highest remaining structural payoff.
+2. `capabilities.ts` public root + private handlers — important for FE-705 / future adapter safety.
+3. Provider/model resolver seam — best handled under `first-run-provider-setup` rather than as a pure structure cleanup.
diff --git a/memory/SPEC.md b/memory/SPEC.md
index d5ac20a1..c518b1ff 100644
--- a/memory/SPEC.md
+++ b/memory/SPEC.md
@@ -72,17 +72,18 @@ Brunch operates inside a **workspace**: the cwd-backed software context whose lo
31. Users can request a turn-owned candidate-spec set during grounding or design; accepting a direction may steer the next interview move and materialize intent items, but does not itself close the phase.
32. Interview detail can proceed as a progressive broad-pass-to-detail flow with explicit `next level of detail` actions.
44. Specifications can evolve through multiple chat-local strategies rather than one global interviewer mode. Each active/resumable chat has at most one open assistant/system-first frontier turn waiting for user completion. Proposal turns use normalized completion semantics; only proposal acceptance may apply semantic changes.
+45. The workspace runtime can host secondary chats (`side`, `reconciliation`, `qa`, `strategy`) inline with the primary interview chat while keeping transcript replay, explicit turn-level context snapshots, graph-item handle refresh, and semantic mutations server-authoritative. Schema-level `thread` and hidden persisted context-spec tables are deferred.
#### Knowledge / intent graph
6. The observer extracts typed intent items and intent edges from answered turns.
7. The accumulated knowledge layer and readiness state stay visible during the interview.
-10. Users can revisit knowledge through edit mode, cascade preview, and reconciliation / secondary-thread surfaces.
+10. Users can revisit knowledge through edit mode, cascade preview, and reconciliation / secondary-chat surfaces.
22. Grounding and elicitation persist only the durable exploration ontology (`goal`, `term`, `context`, `constraint`, `decision`, `assumption`); `non-goal` is represented as a `constraint` subtype, and requirements / criteria become durable only through accepted review outputs.
23. The knowledge/intent ontology is defined once and projected consistently through schema, shared registries, observer prompts, API types, fixtures, and UI copy.
30. Observer extraction treats typed relationships as first-class across the ontology and records them when reasonably supported while abstaining when support is weak.
38. The product ontology should expand beyond current exploration + review kinds to support `invariant` and `example` as first-class durable knowledge kinds.
-39. Specifications can own multiple durable chat containers below the specification, with turns moving toward chat ownership while preserving temporary spec-scoped compatibility. Reconciliation needs remain process debt, separate from semantic intent edges.
+39. Specifications can own multiple durable chat containers below the specification; turns belong to chats while legacy spec-scoped pointers remain transitional. Reconciliation needs remain process debt, separate from semantic intent edges.
#### Review & export
@@ -108,42 +109,45 @@ Brunch operates inside a **workspace**: the cwd-backed software context whose lo
-| # | Assumption | Confidence | Status | Depends on | Validation approach |
-| --- | --- | --- | --- | --- | --- |
-| A15 | LLM readiness and closure recommendations can be useful, but closure authority must remain explainable and user-legible rather than model-owned. | medium | open | D65, D66 | Manual comparison of model recommendations vs user judgment across varied projects. |
-| A20 | Users experience observer capture as responsive when every eligible answered turn enters one turn-owned background capture backlog instead of blocking chat stream completion. | medium | open | D22, D113, I108 | Measure stream completion timing, backlog draining, and replay clarity. |
-| A48 | Intent graph edges are sufficient to drive accurate cascade preview for revisit work. | medium | open | D50, D137, D146 | Structural cascade tests plus manual judgment about scope. |
-| A49 | A modal or chat-shaped secondary thread can resolve revisit implications without forcing a full interview restart. | medium | open | D80, D138 | Manual revisit walkthrough once the thread lifecycle lands. |
-| A57 | A specification-scoped lifecycle seam can own duplicate-safe automatic phase entry/continue, late-event suppression, and route-independent in-flight operation identity without introducing a second durable workflow model. | medium | open | D113 | Prototype lifecycle edges; revisit if restart or duplicate-submit truth remains ambiguous. |
-| A58 | A cumulative workspace can preserve phase legibility if realized sections stay visible, future sections stay unreachable, and section focus remains navigation-only state. | medium | open | D86, D110, D113, D114 | Prototype continuous workspace deep links, scroll/focus transitions, close-to-next-phase motion, and resume/reload. |
-| A64 | Query-owned invalidation boundaries can eliminate scroll-jank cascades without stale-data bugs; the near-term boundary may be one specification bundle plus one entities domain. | medium | open | D87, I110 | Prototype bundle/entities decomposition and measure scroll stability plus data freshness during observer updates. |
-| A65 | The interviewer can adapt usefully to the full `greenfield <> brownfield` by `end-to-end build <> incremental feature` matrix without making kickoff feel bureaucratic. | medium | open | D124 | Manual walkthroughs across all four corners of the matrix. |
-| A66 | Relation-first observer capture will improve revisit, export grounding, and graph-view utility without flooding the graph with speculative or low-value edges. | medium | open | D50, D125 | Observer corpus probes plus manual graph/export review focused on edge precision, coverage, and usefulness. |
-| A67 | Users who are tired, rushed, or under-informed will converge faster by reacting to synthesized candidate directions than by continuing a long direct interview or force-closing early. | medium | open | D126, D127 | Manual comparison between direct questioning, skip-close, and candidate-spec reaction flows. |
-| A68 | Broad-pass interviewing followed by explicit deepen-detail actions will preserve coherence better than a single depth-first drill-down while still producing export-worthy specifications. | medium | open | D127 | Prototype broad-pass-first flows and compare knowledge completeness and user comprehension. |
-| A69 | A graph-centric refinement surface can launch side-chats without splitting durable specification truth. | medium | open | D128, D114 | Prototype graph-launched refinement with reload/resume checks. |
-| A70 | Structured-list graph view remains valuable even when edge density is low, provided relation footers gracefully collapse. | medium | open | A66, D128, D129 | Manual walkthroughs at low and high edge density. |
-| A71 | Semantic mutations will eventually need a changeset-ledger history distinct from conversational turn ancestry, but the first implementation should prove chat containers and reconciliation needs first. | medium | open | D135 | Revisit after chat containers plus reconciliation needs stabilize. |
-| A72 | Intent items can carry version history without breaking the active-path durable-truth contract. | low | future | A71, D135 | Prototype item versioning behind the changeset ledger. |
-| A73 | Autonomous architect/generator loops can propose useful graph mutations only after human-driven multi-chat and reconciliation surfaces prove the shared mutation pipeline. | low | future | A71, D135 | Run architect proposals in shadow mode after multi-chat/reconciliation seams stabilize. |
-| A74 | OpenRouter may reduce first-run friction, but capability parity and AI SDK support need proof before making it the default provider path. | medium | open | D130, D131 | Spike provider configuration against interviewer/observer calls. |
-| A75 | XDG-compliant user-scoped auth/config storage is acceptable for UI-entered API keys and safer than writing secrets to project workspace. | medium | open | D130, D132 | Prototype key save/load/delete precedence and inspect OS/XDG paths. |
-| A76 | Users will accept Brunch editing `.gitignore` when the action is explicit, previewable, and idempotent. | high | open | D133 | Unit-test ignore detection/append behavior and manual dashboard walkthroughs. |
-| A77 | Progressive checkability will improve generated specs more than a binary formal/not-formal framing. | medium | open | D134 | Prototype intent-item-to-witness review on a small corpus. |
-| A78 | Adding `invariant` and `example` as product ontology candidates will make intent drift easier to detect without overwhelming early interviews. | medium | open | D134 | Run transcript probes for examples, counterexamples, not-relevant cases, and state/transition rules. |
-| A79 | Once semantic truth can change through graph edits, side-chats, reconciliation, verifier feedback, or implementation feedback, turn ancestry alone will be insufficient as the semantic history spine. | medium | open | D135 | Revisit after chat containers and reconciliation needs. |
-| A80 | Behavioral kernels can generate higher-yield disambiguating questions than generic elicitation prompts if they emit checkable artifacts rather than user-visible formalism. | low | open | D134 | Try state/lifecycle and containment/topology prototypes first. |
-| A81 | Knowledge/intent edges can carry semantics without becoming noisy only if relation policy distinguishes semantic relations from reconciliation needs and operational participation. | medium | open | D137 | Design relation-policy semantics before broad observer edge expansion. |
-| A84 | Scenario-specific graph context packs can replace transcript-as-default prompt context without losing conversational nuance. | medium | open | D139, D140 | Build prompt/context probes over seeded graphs and compare outputs against transcript-heavy baselines. |
-| A85 | A lightweight prompt scenario substrate will validate LLM-heavy directions faster than UI-first development if it captures rendered prompts, context packs, model settings, raw outputs, parses, and review notes. | medium | open | D139 | Run multi-scenario prompt probes before productizing UI. |
-| A86 | Pi can serve as a useful pre-UI agent harness or tool-spike backend without forcing Brunch to adopt Pi as production runtime. | low | open | D142 | Spike Pi SDK/RPC with controlled prompts, tools, and graph context packs. |
-| A87 | Verification-aware post-spec decomposition can be explored as agent scenarios before it is a Brunch product surface. | low | future | D141 | Prototype decomposition and oracle-design probes. |
-| A88 | Deterministic enumeration over existing intent edges incident on a changed item can produce a useful cascade preview without requiring the reconciliation agent. | medium | open | D135, D137, D138, D146 | Manual hard-edit walkthroughs across side-chat V3.0 fixture matrix. |
-| A89 | A long-lived local JSONL agent capability CLI can drive the real Brunch interview flow well enough for external LLM-as-user probes to produce credible completed-spec fixtures. | medium | open | D143, D147, Requirement 43 | Prototype the minimal JSONL loop and run LLM-as-user scenarios end-to-end. |
-| A90 | Users who ask to speed up a long interview will prefer a side-chat that generates 2–3 reviewed scenario options completing the current direction. | medium | open | D126, D148, D151, Requirement 44 | Probe scenario-options against drilldown fixtures and run manual flow review. |
-| A91 | Graph-review critique can make scenario-generated candidate bundles safe enough for product use if readiness states and follow-on review work are explicit. | medium | open | D151, D152, Requirement 44 | Run candidate bundle probes with graph-review scoring and human review. |
-| A92 | A conservative global staleness rule for open proposal turns is acceptable before neighborhood-level staleness calculation exists. | medium | open | D149, I117 | Exercise multi-chat proposal flows where another chat applies a changeset while a proposal remains open. |
-| A93 | Relation-policy directionality lookup is safer than forcing all useful intent-edge verbs into one dependency direction. | medium | open | D137, D150 | Define canonical/inverse sentences and source/target change behavior for each relation. |
+| # | Assumption | Confidence | Status | Depends on | Validation approach |
+| --- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | ------ | -------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
+| A15 | LLM readiness and closure recommendations can be useful, but closure authority must remain explainable and user-legible rather than model-owned. | medium | open | D65, D66 | Manual comparison of model recommendations vs user judgment across varied projects. |
+| A20 | Users experience observer capture as responsive when every eligible answered turn enters one turn-owned background capture backlog instead of blocking chat stream completion. | medium | open | D22, D113, I108 | Measure stream completion timing, backlog draining, and replay clarity. |
+| A48 | Intent graph edges are sufficient to drive accurate cascade preview for revisit work. | medium | open | D50, D137, D146 | Structural cascade tests plus manual judgment about scope. |
+| A49 | A chat-shaped secondary surface can resolve revisit implications without forcing a full interview restart. | medium | open | D80, D138 | Manual revisit walkthrough once the secondary-chat lifecycle lands. |
+| A57 | A specification-scoped lifecycle seam can own duplicate-safe automatic phase entry/continue, late-event suppression, and route-independent in-flight operation identity without introducing a second durable workflow model. | medium | open | D113 | Prototype lifecycle edges; revisit if restart or duplicate-submit truth remains ambiguous. |
+| A58 | A cumulative workspace can preserve phase legibility if realized sections stay visible, future sections stay unreachable, and section focus remains navigation-only state. | medium | open | D86, D110, D113, D114 | Prototype continuous workspace deep links, scroll/focus transitions, close-to-next-phase motion, and resume/reload. |
+| A64 | Query-owned invalidation boundaries can eliminate scroll-jank cascades without stale-data bugs; the near-term boundary may be one specification bundle plus one entities domain. | medium | open | D87, I110 | Prototype bundle/entities decomposition and measure scroll stability plus data freshness during observer updates. |
+| A65 | The interviewer can adapt usefully to the full `greenfield <> brownfield` by `end-to-end build <> incremental feature` matrix without making kickoff feel bureaucratic. | medium | open | D124 | Manual walkthroughs across all four corners of the matrix. |
+| A66 | Relation-first observer capture will improve revisit, export grounding, and graph-view utility without flooding the graph with speculative or low-value edges. | medium | open | D50, D125 | Observer corpus probes plus manual graph/export review focused on edge precision, coverage, and usefulness. |
+| A67 | Users who are tired, rushed, or under-informed will converge faster by reacting to synthesized candidate directions than by continuing a long direct interview or force-closing early. | medium | open | D126, D127 | Manual comparison between direct questioning, skip-close, and candidate-spec reaction flows. |
+| A68 | Broad-pass interviewing followed by explicit deepen-detail actions will preserve coherence better than a single depth-first drill-down while still producing export-worthy specifications. | medium | open | D127 | Prototype broad-pass-first flows and compare knowledge completeness and user comprehension. |
+| A69 | A graph-centric refinement surface can launch side-chats without splitting durable specification truth. | medium | open | D128, D114 | Prototype graph-launched refinement with reload/resume checks. |
+| A70 | Structured-list graph view remains valuable even when edge density is low, provided relation footers gracefully collapse. | medium | open | A66, D128, D129 | Manual walkthroughs at low and high edge density. |
+| A71 | Semantic mutations will eventually need a changeset-ledger history distinct from conversational turn ancestry, but the first implementation should prove chat containers and reconciliation needs first. | medium | open | D135 | Revisit after chat containers plus reconciliation needs stabilize. |
+| A72 | Intent items can carry version history without breaking the active-path durable-truth contract. | low | future | A71, D135 | Prototype item versioning behind the changeset ledger. |
+| A73 | Autonomous architect/generator loops can propose useful graph mutations only after human-driven multi-chat and reconciliation surfaces prove the shared mutation pipeline. | low | future | A71, D135 | Run architect proposals in shadow mode after multi-chat/reconciliation seams stabilize. |
+| A74 | OpenRouter may reduce first-run friction, but capability parity and AI SDK support need proof before making it the default provider path. | medium | open | D130, D131 | Spike provider configuration against interviewer/observer calls. |
+| A75 | XDG-compliant user-scoped auth/config storage is acceptable for UI-entered API keys and safer than writing secrets to project workspace. | medium | open | D130, D132 | Prototype key save/load/delete precedence and inspect OS/XDG paths. |
+| A76 | Users will accept Brunch editing `.gitignore` when the action is explicit, previewable, and idempotent. | high | open | D133 | Unit-test ignore detection/append behavior and manual dashboard walkthroughs. |
+| A77 | Progressive checkability will improve generated specs more than a binary formal/not-formal framing. | medium | open | D134 | Prototype intent-item-to-witness review on a small corpus. |
+| A78 | Adding `invariant` and `example` as product ontology candidates will make intent drift easier to detect without overwhelming early interviews. | medium | open | D134 | Run transcript probes for examples, counterexamples, not-relevant cases, and state/transition rules. |
+| A79 | Once semantic truth can change through graph edits, side-chats, reconciliation, verifier feedback, or implementation feedback, turn ancestry alone will be insufficient as the semantic history spine. | medium | open | D135 | Revisit after chat containers and reconciliation needs. |
+| A80 | Behavioral kernels can generate higher-yield disambiguating questions than generic elicitation prompts if they emit checkable artifacts rather than user-visible formalism. | low | open | D134 | Try state/lifecycle and containment/topology prototypes first. |
+| A81 | Knowledge/intent edges can carry semantics without becoming noisy only if relation policy distinguishes semantic relations from reconciliation needs and operational participation. | medium | open | D137 | Design relation-policy semantics before broad observer edge expansion. |
+| A84 | Scenario-specific graph context packs can replace transcript-as-default prompt context without losing conversational nuance. | medium | open | D139, D140 | Build prompt/context probes over seeded graphs and compare outputs against transcript-heavy baselines. |
+| A85 | A lightweight prompt scenario substrate will validate LLM-heavy directions faster than UI-first development if it captures rendered prompts, context packs, model settings, raw outputs, parses, and review notes. | medium | open | D139 | Run multi-scenario prompt probes before productizing UI. |
+| A86 | Pi can serve as a useful pre-UI agent harness or tool-spike backend without forcing Brunch to adopt Pi as production runtime. | low | open | D142 | Spike Pi SDK/RPC with controlled prompts, tools, and graph context packs. |
+| A87 | Verification-aware post-spec decomposition can be explored as agent scenarios before it is a Brunch product surface. | low | future | D141 | Prototype decomposition and oracle-design probes. |
+| A88 | Deterministic enumeration over existing intent edges incident on a changed item can produce a useful cascade preview without requiring the reconciliation agent. | medium | open | D135, D137, D138, D146 | Manual hard-edit walkthroughs across side-chat V3.0 fixture matrix. |
+| A89 | A long-lived local JSONL agent capability CLI can drive the real Brunch interview flow well enough for external LLM-as-user probes to produce credible completed-spec fixtures. | medium | open | D143, D147, Requirement 43 | Prototype the minimal JSONL loop and run LLM-as-user scenarios end-to-end. |
+| A90 | Users who ask to speed up a long interview will prefer a side-chat that generates 2–3 reviewed scenario options completing the current direction. | medium | open | D126, D148, D151, Requirement 44 | Probe scenario-options against drilldown fixtures and run manual flow review. |
+| A91 | Graph-review critique can make scenario-generated candidate bundles safe enough for product use if readiness states and follow-on review work are explicit. | medium | open | D151, D152, Requirement 44 | Run candidate bundle probes with graph-review scoring and human review. |
+| A92 | A conservative global staleness rule for open proposal turns is acceptable before neighborhood-level staleness calculation exists. | medium | open | D149, I117 | Exercise multi-chat proposal flows where another chat applies a changeset while a proposal remains open. |
+| A93 | Relation-policy directionality lookup is safer than forcing all useful intent-edge verbs into one dependency direction. | medium | open | D137, D150 | Define canonical/inverse sentences and source/target change behavior for each relation. |
+| A94 | Durable secondary chats can replace independent side-chat persistence while preserving reloadable side, reconciliation, qa, and strategy conversations inside one workspace surface without introducing a `thread` table yet. | medium | open | D138, D153, Requirement 45 | In-stream secondary-chat rendering/reload walkthroughs over the existing chat/turn substrate. |
+| A95 | Transcript-first context with explicit context snapshots on turn rows plus active graph-item handles on chats can keep secondary chats useful across multi-chat item changes without a persisted context-spec table. Handles only need re-snapshotting when the referenced item's version/fingerprint advances. | medium | open | D139, D140, D154, Requirement 45 | Context-provision tests for snapshot insertion, item-list/neighborhood/economic-graph snapshot builders, stale-handle refresh, and prompt/context-pack rendering. |
+| A96 | Async-by-default reconciliation can move Pending review into an in-stream target-grouped reconciliation chat without hiding judgment work or surfacing auto-confirmed noise. | medium | open | D135, D137, D138, D146, D153 | Track 3 classifier scheduling, target-ordering tests, and dense reconciliation walkthroughs. |
### Active Decisions
@@ -178,12 +182,14 @@ Brunch operates inside a **workspace**: the cwd-backed software context whose lo
138. **Multi-chat substrate is the first concrete persistence slice before the full changeset ledger** — chat containers and minimal reconciliation needs precede canonical changeset history while legacy spec-scoped pointers remain transitional.
144. **Intent graph vocabulary supersedes knowledge graph vocabulary** — planning, product language, capability contracts, and context packs should prefer intent item/edge vocabulary; knowledge item/edge remains implementation language during transition.
145. **Changeset/change supersedes patch/patch_change** — new semantic mutation history vocabulary is changeset/change; patch vocabulary is historical.
-146. **Hard-impact edit cascade reads from the `reconciliation_need` queue, not from REVISIT walk state** — direct hard edits enumerate incident relations, open reconciliation needs, and resolve through the patch-list/Pending-review surface.
+146. **Hard-impact edit cascade reads from the `reconciliation_need` queue, not from REVISIT walk state** — direct hard edits enumerate incident relations, open reconciliation needs, and resolve through the current reconciliation review surface until Track 3 absorbs that work into an in-stream reconciliation chat.
148. **Spec evolution strategies are chat-local, turn-mediated process state** — strategy belongs to chats/turns, not specification-level semantic truth; broad acceleration should branch into strategy chats rather than mutate the primary interview chat in place.
149. **Changesets are the atomic semantic mutation boundary, while proposal turns are not mutations until accepted** — proposal actions other than accept create successor/process state rather than graph truth.
-150. **Relation policy owns operational directionality for intent edges** — cascade/reconciliation behavior is declared per relation, not inferred from raw source/target edge direction.
+150. **Relation policy owns operational and display directionality for intent edges** — cascade/reconciliation behavior and compact context labels are declared per relation, not inferred from raw source/target edge direction. Each relation needs canonical source→target wording plus endpoint-relative labels so snapshots can summarize an item's dependencies and dependents without reversing semantics ad hoc.
151. **Scenario-options acceleration is product-facing, but graph review is its safety oracle** — generated candidate bundles may become the user-facing alternative to long drilldown only with fixed-premise, tradeoff, checkability, provenance, and graph-review safeguards.
152. **Graph review and reconciliation are separate graph operations** — reconciliation repairs known disturbance debt; graph review critiques graph quality and starts as turn-owned structured artifacts unless independent lifecycle needs emerge.
+153. **Conversational Workspace Runtime supersedes independent side-chat persistence without adding schema-level threads now** — continuous workspace is the host; side, reconciliation, qa, and strategy work should converge into inline secondary chats over the existing chat/turn substrate, while `changeset` / `change` remains the semantic mutation spine. A future `thread` table is deferred until chat/turn proves insufficient.
+154. **Chat context is transcript-first with turn-level snapshots and chat-level handles** — a chat primarily uses its own transcript as prompt context. Additional graph/workspace context enters through explicit context snapshot artifacts stored on `turn` rows, so replay shows what the assistant saw at snapshot time. Active chat handles reference mentioned or anchored intent item ids and record the last snapshotted item version/fingerprint; they trigger fresh snapshots only when the referenced subject advances, including changes made by other chats. Do not introduce a persisted context-spec table by default; derive snapshots from intent graph truth via reusable context builders for item, neighborhood, economic whole-graph, and eventually changeset-historical neighborhoods.
#### Provider, prompt/context, and agent substrate
@@ -204,35 +210,43 @@ Brunch operates inside a **workspace**: the cwd-backed software context whose lo
Each invariant is a formalization candidate: the property is stated in human language, protected today by tests/manual oracles, and may later graduate to stronger runtime/model oracles.
-| # | Invariant | Protected by | Proves |
-| --- | --- | --- | --- |
-| I4 | Vite proxy routing and the runtime backend-port seam stay aligned through one explicit configuration path. | `runtime-config.test.ts` | Requirement 1 |
-| I17 | Data Part schema validation remains confined to true LLM / HTTP boundaries rather than mirrored internal seams. | `parts.test.ts` | Requirement 4 |
-| I24 | The routed interview surface preserves hydration, stream projection, lifecycle orchestration, mutation transport, phase projection, successor-frontier continuity, activity summaries, projected controls, preface/revision artifacts, and trailing observer attachment. | `InterviewView.test.tsx`, workspace stream / controller / app tests | D86, D87, D110, D113, D114 |
-| I44 | Structured turn responses round-trip through persistence, hydration, projection, and UI affordance state without collapsing back to scalar semantics. | `turn-response.test.ts`, `context.test.ts`, `InterviewView.test.tsx` | Requirement 4 |
-| I48 | Canonical intent/knowledge kinds persist with provenance and project through typed entity collections, stable reference codes, turn-linked capture projection, and graph edges without ontology drift. | `db.test.ts`, `core.test.ts`, `knowledge.test.ts`, sidebar/graph tests | D50, Requirements 22, 23 |
-| I54 | Phase-aware capture preserves the ontology boundary: grounding/design persist exploration knowledge, accepted review outputs materialize requirements/criteria, and both seams survive persistence and replay. | `observer.test.ts`, `context.test.ts`, `app.test.ts`, `InterviewView.test.tsx` | Requirements 22, 23 |
-| I72 | Explicit phase outcomes project shared workflow status, closeability, readiness, closure basis, and closed-phase markers through one durable seam. | `phase-close.test.ts`, `db.test.ts`, `app.test.ts` | D65, D66, D110 |
-| I87 | Requirements and criteria review persist interviewer-owned review metadata on the review turn, project stable reference codes, submit semantic review replies, and carry accepted outputs downstream without dead frontier states. | `interview.test.ts`, `db.test.ts`, `app.test.ts`, `InterviewView.test.tsx` | Requirements 11, 12; D110 |
-| I100 | Local-first distribution keeps `.brunch/` workspace resolution, package-bin startup, built-client serving, bound URL reporting, runtime ownership, and JSON request limits correct. | `project.test.ts`, `launcher.test.ts`, `cli.test.ts`, `runtime-config.test.ts`, `app.test.ts` | Requirement 1 |
-| I102 | File-route generation, directory-based nesting, three-shell route architecture, and phase addressability remain the runtime routing source of truth; graph view stays code-split. | `router.test.tsx`, `build-boundary.test.ts`, `GraphView.test.tsx` | D86, Requirement 33 |
-| I106 | Provider credential discovery, precedence, dashboard status, and model-provider resolution stay explicit without exposing raw secret values through `/api/config`, logs, persisted specification state, or client-visible payloads. | planned: config/app/dashboard tests | Requirements 34, 35, 36; D130, D131, D132 |
-| I107 | `.brunch/` gitignore hygiene is idempotent and confirmation-gated. | planned: project-gitignore/app/dashboard tests | Requirement 37; D133 |
-| I108 | Observer capture does not block chat stream completion for eligible answered turns; backlog state is re-derived from durable turns and persists results to the originating turn. | planned: app/controller tests | D22, D113 |
-| I109 | Observer prompts remain compact as relation extraction widens; candidates resolve only through validated existing ids or same-turn provisional references, and accepted reviews reuse relation policy. | `context.test.ts`, `observer.test.ts`, `db.test.ts`, `app.test.ts` | Requirement 30; D50, D125 |
-| I110 | Workflow read truth and write truth stay behind named seams instead of transport handlers owning workflow semantics. | workflow projector / transition / phase-close tests | D110, D113 |
-| I111 | Multi-chat substrate preserves primary-chat active-head equivalence during transition, same-spec/chat ancestry, and reconciliation-need dedupe without conflating process debt with semantic edges. | `chat-substrate.test.ts`, `reconciliation-need.test.ts`, `db.test.ts` | Requirement 39; D137, D138 |
-| I112 | Prompt/context scenarios render from packaged markdown prompts and typed context-pack builders, with deterministic fingerprints and reviewable golden coverage. | prompt loader/build/golden, context-pack, scenario-runner tests | Requirements 40, 41; D139, D140 |
-| I113 | Hard-impact direct edit opens reconciliation needs for affected relation-policy endpoints, records provenance, deduplicates idempotently, and no longer returns deferred placeholder responses. | planned: edit-applier/reconciliation/overlay/app tests | Requirement 10; A88; D146, D150 |
-| I114 | The reconciliation classifier lifecycle is explicit and recoverable; labels are constrained, failures persist parser/thrown errors, and proposals are never auto-applied. | reconciliation-agent tests | Requirement 10; A88; D139 |
-| I115 | The agent capability CLI remains an adapter over Brunch capability contracts: calls validate explicit resource ids/schemas, mutating calls dispatch through server-owned handlers, and probes exercise only the JSONL boundary. | planned: capabilities, agent-jsonl, probe-runner tests | Requirements 42, 43; A89; D143, D147 |
-| I116 | Each active/resumable chat has at most one open assistant/system-first frontier turn; user responses complete it through normalized semantics, and strategy is chat-local process state. | planned: chat/transition/capability tests | Requirement 44; D138, D148 |
-| I117 | Open proposal turns are stamped with the latest applied changeset id at creation and conservatively stale when the specification's latest changeset advances before completion. | planned: changeset/transition/app tests | A92; D149 |
-| I118 | Reconciliation/direct-edit cascade never infers affected endpoints from raw edge direction alone; it consults relation policy source-change / target-change behavior. | planned: relation-policy/edit-impact/reconciliation tests | A93; D137, D150 |
-| I119 | Scenario-option candidate bundles can become canonical only by accepting a coherent bundle changeset; accepted-with-issues candidates also create durable follow-on review/process debt. | planned: scenario-runner, turn-artifacts, changeset tests | A90, A91; D151, D152 |
+| # | Invariant | Protected by | Proves |
+| ---- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------ |
+| I4 | Vite proxy routing and the runtime backend-port seam stay aligned through one explicit configuration path. | `runtime-config.test.ts` | Requirement 1 |
+| I17 | Data Part schema validation remains confined to true LLM / HTTP boundaries rather than mirrored internal seams. | `parts.test.ts` | Requirement 4 |
+| I24 | The routed interview surface preserves hydration, stream projection, lifecycle orchestration, mutation transport, phase projection, successor-frontier continuity, activity summaries, projected controls, preface/revision artifacts, and trailing observer attachment. | `InterviewView.test.tsx`, workspace stream / controller / app tests | D86, D87, D110, D113, D114 |
+| I44 | Structured turn responses round-trip through persistence, hydration, projection, and UI affordance state without collapsing back to scalar semantics. | `turn-response.test.ts`, `context.test.ts`, `InterviewView.test.tsx` | Requirement 4 |
+| I48 | Canonical intent/knowledge kinds persist with provenance and project through typed entity collections, stable reference codes, turn-linked capture projection, and graph edges without ontology drift. | `db.test.ts`, `core.test.ts`, `knowledge.test.ts`, sidebar/graph tests | D50, Requirements 22, 23 |
+| I54 | Phase-aware capture preserves the ontology boundary: grounding/design persist exploration knowledge, accepted review outputs materialize requirements/criteria, and both seams survive persistence and replay. | `observer.test.ts`, `context.test.ts`, `app.test.ts`, `InterviewView.test.tsx` | Requirements 22, 23 |
+| I72 | Explicit phase outcomes project shared workflow status, closeability, readiness, closure basis, and closed-phase markers through one durable seam. | `phase-close.test.ts`, `db.test.ts`, `app.test.ts` | D65, D66, D110 |
+| I87 | Requirements and criteria review persist interviewer-owned review metadata on the review turn, project stable reference codes, submit semantic review replies, and carry accepted outputs downstream without dead frontier states. | `interview.test.ts`, `db.test.ts`, `app.test.ts`, `InterviewView.test.tsx` | Requirements 11, 12; D110 |
+| I100 | Local-first distribution keeps `.brunch/` workspace resolution, package-bin startup, built-client serving, bound URL reporting, runtime ownership, and JSON request limits correct. | `project.test.ts`, `launcher.test.ts`, `cli.test.ts`, `runtime-config.test.ts`, `app.test.ts` | Requirement 1 |
+| I102 | File-route generation, directory-based nesting, three-shell route architecture, and phase addressability remain the runtime routing source of truth; graph view stays code-split. | `router.test.tsx`, `build-boundary.test.ts`, `GraphView.test.tsx` | D86, Requirement 33 |
+| I106 | Provider credential discovery, precedence, dashboard status, and model-provider resolution stay explicit without exposing raw secret values through `/api/config`, logs, persisted specification state, or client-visible payloads. | planned: config/app/dashboard tests | Requirements 34, 35, 36; D130, D131, D132 |
+| I107 | `.brunch/` gitignore hygiene is idempotent and confirmation-gated. | planned: project-gitignore/app/dashboard tests | Requirement 37; D133 |
+| I108 | Observer capture does not block chat stream completion for eligible answered turns; backlog state is re-derived from durable turns and persists results to the originating turn. | planned: app/controller tests | D22, D113 |
+| I109 | Observer prompts remain compact as relation extraction widens; candidates resolve only through validated existing ids or same-turn provisional references, and accepted reviews reuse relation policy. | `context.test.ts`, `observer.test.ts`, `db.test.ts`, `app.test.ts` | Requirement 30; D50, D125 |
+| I110 | Workflow read truth and write truth stay behind named seams instead of transport handlers owning workflow semantics. | workflow projector / transition / phase-close tests | D110, D113 |
+| I111 | Multi-chat substrate preserves primary-chat active-head equivalence during transition, same-spec/chat ancestry on turn writes, and reconciliation-need dedupe without conflating process debt with semantic edges. Turns remain chat-owned; schema-level threads are not part of the current persistence model. | `chat-substrate.test.ts`, `reconciliation-need.test.ts`, `db.test.ts` | Requirements 39, 45; D137, D138, D153 |
+| I112 | Prompt/context scenarios render from packaged markdown prompts and typed context-pack builders, with deterministic fingerprints and reviewable golden coverage. | prompt loader/build/golden, context-pack, scenario-runner tests | Requirements 40, 41; D139, D140 |
+| I113 | Hard-impact direct edit opens reconciliation needs for affected relation-policy endpoints, records provenance, deduplicates idempotently, and no longer returns deferred placeholder responses. | planned: edit-applier/reconciliation/overlay/app tests | Requirement 10; A88; D146, D150 |
+| I114 | The reconciliation classifier lifecycle is explicit and recoverable; labels are constrained, failures persist parser/thrown errors, and proposals are never auto-applied. | reconciliation-agent tests | Requirement 10; A88; D139 |
+| I115 | The agent capability CLI remains an adapter over Brunch capability contracts: calls validate explicit resource ids/schemas, mutating calls dispatch through server-owned handlers, and probes exercise only the JSONL boundary. | planned: capabilities, agent-jsonl, probe-runner tests | Requirements 42, 43; A89; D143, D147 |
+| I116 | Each active/resumable chat has at most one open assistant/system-first frontier turn; user responses complete it through normalized semantics, and strategy is chat-local process state. | planned: chat/transition/capability tests | Requirement 44; D138, D148 |
+| I117 | Open proposal turns are stamped with the latest applied changeset id at creation and conservatively stale when the specification's latest changeset advances before completion. | planned: changeset/transition/app tests | A92; D149 |
+| I118 | Reconciliation/direct-edit cascade never infers affected endpoints from raw edge direction alone; it consults relation policy source-change / target-change behavior. | planned: relation-policy/edit-impact/reconciliation tests | A93; D137, D150 |
+| I119 | Scenario-option candidate bundles can become canonical only by accepting a coherent bundle changeset; accepted-with-issues candidates also create durable follow-on review/process debt. | planned: scenario-runner, turn-artifacts, changeset tests | A90, A91; D151, D152 |
+| I120 | Secondary chats remain conversational process containers, not workflow or semantic truth: inline rendering, collapse/reload state, turn-level context snapshot replay, and item-version-gated stale-handle refresh may organize discussion, but accepted mutations still flow through Brunch-owned handlers and changesets. | planned: chat-runtime, context-provision, changeset/app tests | Requirement 45; A94, A95; D143, D149, D153, D154 |
## Future Direction Register
+### Conversational workspace runtime
+
+- The Conversational Workspace Runtime is the next architectural umbrella after continuous workspace Track 1: the shipped shell hosts unified chat, inline secondary chats, reconciliation, changesets, and transcript-first context provision. See `docs/design/CONVERSATIONAL_WORKSPACE_RUNTIME.md` and PLAN items `chat-runtime-secondary-chats`, `reconciliation-runtime`, `changeset-ledger`, and `chat-context-provision`.
+- Persistent side-chat history is no longer an independent V4a frontier. It is absorbed by secondary chats over the existing chat/turn substrate; schema-level `thread` is explicitly deferred until chat/turn proves insufficient.
+- Context provision should be transcript-first: context builders may derive initial snapshots from chat kind/strategy/anchors, explicit item lists, item neighborhoods, or an economic whole-graph view, but durable prompt context is represented by context snapshot artifacts stored on turns and refreshed graph-item handles on chats rather than a hidden persisted context-spec table. Once changeset history exists, neighborhood builders may also derive historical neighborhoods around the changeset that originally captured or last updated an item.
+- Reconciliation absorption and context provision stay coordinated with the chat runtime; changeset/change history can proceed in parallel and remains the semantic mutation authority.
+
### Semantic / generative substrate
- Intent graph semantics, relation policy, examples/invariants, checkability, and witness strength are the next semantic substrate focus. See `docs/design/INTENT_GRAPH_SEMANTICS.md` and PLAN item `intent-graph-semantics`.
@@ -252,14 +266,14 @@ Each invariant is a formalization candidate: the property is stated in human lan
The center column is a **merged stream projection** over multiple artifact families. Only conversational turns participate in branch-bearing lineage; other artifacts anchor to that lineage or project from workflow state.
-| Artifact family | Durable | Branch-bearing | Examples | Rule |
-| --- | --- | --- | --- | --- |
-| Conversational turn cards | yes | yes | questions, review proposals, closure proposals, answered-turn replay | Ordered by active-path turn chain. |
-| Anchored workflow facts | yes | no | phase outcome | Anchored to turn ids; hidden/superseded if anchor leaves active path. |
-| Projected control cards | no | no | kickoff, recovery, proceed/handoff | Derived from workflow state plus nearby anchors. |
-| Activity cards | mixed | no | generation state, activity summary, trailing observer state | Adjacent to a turn/control boundary; not branch nodes. |
-| Phase markers | no | no | phase start/closed | Projected from workflow position and phase outcomes. |
-| Phase section headers | no | no | grounding purpose + captured knowledge kinds | Projected at the top of each realized phase section. |
+| Artifact family | Durable | Branch-bearing | Examples | Rule |
+| ------------------------- | ------- | -------------- | -------------------------------------------------------------------- | --------------------------------------------------------------------- |
+| Conversational turn cards | yes | yes | questions, review proposals, closure proposals, answered-turn replay | Ordered by active-path turn chain. |
+| Anchored workflow facts | yes | no | phase outcome | Anchored to turn ids; hidden/superseded if anchor leaves active path. |
+| Projected control cards | no | no | kickoff, recovery, proceed/handoff | Derived from workflow state plus nearby anchors. |
+| Activity cards | mixed | no | generation state, activity summary, trailing observer state | Adjacent to a turn/control boundary; not branch nodes. |
+| Phase markers | no | no | phase start/closed | Projected from workflow position and phase outcomes. |
+| Phase section headers | no | no | grounding purpose + captured knowledge kinds | Projected at the top of each realized phase section. |
## Layout Architecture
@@ -274,64 +288,69 @@ Detailed card styling, typography tokens, and legacy layout minutiae are impleme
## Lexicon
-| Term | Definition |
-| --- | --- |
-| **workspace** | The cwd-backed software context whose local `.brunch/` directory stores specifications and runtime state. |
-| **specification** | One elicitation run within a workspace. Canonical product term for what older code may still call a project. |
-| **project** | Deprecated older name for a specification record; remove rather than preserving as long-term compatibility language. |
-| **intent spec** | A specification optimized for preserving and validating meaning rather than sequencing downstream work. |
-| **planning spec** | A specification optimized for downstream work sequencing; in Brunch it should be a projection from intent truth, not the source artifact. |
-| **intent graph** | Canonical semantic substrate: typed intent items, intent edges, examples/counterexamples, validation status, and semantic mutation state. |
-| **intent item** | One durable typed semantic unit in the intent graph. Current implementation may still persist `knowledge_item`. |
-| **intent edge** | One durable typed semantic relation between intent items. Current implementation may still persist `knowledge_edge`. |
-| **reconciliation need** | Durable process debt saying existing intent truth may require renewed judgment because related truth changed. Not an intent edge. |
-| **changeset** | Future canonical term for one submitted semantic mutation bundle against the intent graph. Supersedes patch. |
-| **change** | One atomic semantic mutation inside a changeset. Supersedes patch_change. |
-| **chat** | A conversation container inside one specification; primary interview, side-chats, reconciliation chats, and review discussions may own turns without owning semantic truth directly. |
-| **turn** | One persisted authored conversational interaction with typed offer/reply parts and parent linkage. |
-| **frontier turn** | The single actionable durable conversational turn currently awaiting user completion. |
-| **proposal turn** | An assistant/system-first frontier turn offering a candidate bundle, graph-review finding, reconciliation suggestion, or other proposed action. It is not semantic truth until accepted. |
-| **workspace stream** | The merged center-column read model composed from active-path turns, anchored workflow facts, projected controls, phase markers, and activity cards. |
-| **projected control card** | A workflow affordance derived from durable state rather than authored conversational content. |
-| **preface card** | A turn-internal artifact presenting provisional context from context gathering, paired with a question card and captured only as part of the validated whole turn. |
-| **review set** | A synthesized candidate requirements or criteria list with stable reference codes and per-item/full-set review actions. |
-| **phase outcome** | Durable closure artifact for a phase, including summary and closure basis. |
-| **closeability** | Deterministic minimum bar for whether the user may close a phase now. |
-| **readiness band** | Coarse descriptive signal separate from closeability. |
-| **exploration knowledge** | Durable grounding/design knowledge: `goal`, `term`, `context`, `constraint`, `decision`, and `assumption`. |
-| **constraint** | A durable boundary on acceptable scope or solution space; `non-goal` is a subtype. |
-| **decision** | A chosen direction among plausible alternatives, with durable consequences. |
-| **assumption** | A material belief supporting a direction or decision that could later prove false. |
-| **invariant** | Planned ontology kind for a property that must remain true across relevant states, transitions, executions, versions, or semantic revisions. |
-| **example** | Planned ontology kind for concrete positive, negative/counterexample, edge-case, or not-relevant cases that disambiguate intent. |
-| **progressive checkability** | Represent each intent item at the weakest useful witness level today while preserving paths toward stronger witnesses. |
-| **checkability** | A typed field describing the strongest oracle currently witnessing an intent item. |
-| **witness strength** | The breadth/confidence of an item's oracle coverage, distinct from the oracle kind. |
-| **relation policy** | Per-relation registry deciding display, cascade, export, staleness, reconciliation, criteria-help, weak-suggestion participation, support/status semantics, and operational directionality. |
-| **context pack** | A scenario-specific semantic briefing derived from intent graph truth, workflow state, provenance, unresolvedness, relation neighborhoods, and authority labels. |
-| **prompt/context scenario substrate** | Foundation for markdown prompts, reusable doctrines, typed context packs, and repeatable prompt probes before UI commitment. |
-| **agent mutation surface** | Brunch-owned typed handler layer for any durable data mutation initiated by an agent. |
-| **agent capability contract** | Stable, typed read or mutation contract exposed to agents/harnesses with authority and replay metadata. |
-| **agent capability CLI** | Local JSONL adapter exposing Brunch capability contracts without defining its own product API or mutation authority. |
-| **AI runtime provider** | Shared server seam resolving configured LLM provider, model names, API-key source, and provider-specific options. |
-| **XDG auth state** | User-scoped credential/config storage outside the project workspace. |
-| **graph-review finding** | A turn-owned structured critique artifact; not itself semantic truth or reconciliation debt. |
-| **candidate graph bundle** | Coherent scenario-options commit/review unit with tradeoffs, generated intent items/edges, provenance, risks, and preconditions. |
-| **greenfield / brownfield** | Grounding strategies for new concepts vs existing-codebase work. |
-| **end-to-end build / incremental feature** | Delivery postures for whole-system shaping vs bounded changes. |
-| **output view** | Terminal route available when phases are closed; not a workflow phase. |
+| Term | Definition |
+| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| **workspace** | The cwd-backed software context whose local `.brunch/` directory stores specifications and runtime state. |
+| **specification** | One elicitation run within a workspace. Canonical product term for what older code may still call a project. |
+| **project** | Deprecated older name for a specification record; remove rather than preserving as long-term compatibility language. |
+| **intent spec** | A specification optimized for preserving and validating meaning rather than sequencing downstream work. |
+| **planning spec** | A specification optimized for downstream work sequencing; in Brunch it should be a projection from intent truth, not the source artifact. |
+| **intent graph** | Canonical semantic substrate: typed intent items, intent edges, examples/counterexamples, validation status, and semantic mutation state. |
+| **intent item** | One durable typed semantic unit in the intent graph. Current implementation may still persist `knowledge_item`. |
+| **intent edge** | One durable typed semantic relation between intent items. Current implementation may still persist `knowledge_edge`. |
+| **reconciliation need** | Durable process debt saying existing intent truth may require renewed judgment because related truth changed. Not an intent edge. |
+| **changeset** | Future canonical term for one submitted semantic mutation bundle against the intent graph. Supersedes patch. |
+| **change** | One atomic semantic mutation inside a changeset. Supersedes patch_change. |
+| **chat** | A conversation container inside one specification; primary interview, side, reconciliation, qa, and strategy chats may own turns without owning semantic truth directly. Current persistence uses chat + turn; schema-level thread is deferred. |
+| **secondary chat** | Non-primary chat rendered inline or as a collapsible surface inside the workspace. It is a product/runtime use of `chat`, not a separate `thread` table. |
+| **context snapshot** | Turn artifact that records graph/workspace context explicitly inserted into a chat transcript at a point in time, including subject id(s), version/fingerprint(s), snapshot content, reason, and provenance. Snapshots are derived from intent graph truth at snapshot time and do not mutate when source truth changes. |
+| **neighborhood snapshot** | Context snapshot centered on one or more intent items and their relation-policy-selected surroundings. Modes may include immediate adjacency, dependencies, dependents/impact, evidence, reconciliation, and later changeset-historical neighborhoods around original capture or last update. |
+| **context handle** | Lightweight chat-level or transcript-derived reference saying a chat is tracking one or more intent item ids across turns. Before new assistant turns, stale handles cause fresh context snapshots only when the subject's current version/fingerprint has advanced since the last snapshot. |
+| **turn-zero** | Assistant-authored kickoff turn that seeds a new secondary chat with kind-appropriate explicit context snapshots and options before the user responds. |
+| **turn** | One persisted authored conversational interaction with typed offer/reply parts and parent linkage. |
+| **frontier turn** | The single actionable durable conversational turn currently awaiting user completion. |
+| **proposal turn** | An assistant/system-first frontier turn offering a candidate bundle, graph-review finding, reconciliation suggestion, or other proposed action. It is not semantic truth until accepted. |
+| **workspace stream** | The merged center-column read model composed from active-path turns, anchored workflow facts, projected controls, phase markers, and activity cards. |
+| **projected control card** | A workflow affordance derived from durable state rather than authored conversational content. |
+| **preface card** | A turn-internal artifact presenting provisional context from context gathering, paired with a question card and captured only as part of the validated whole turn. |
+| **review set** | A synthesized candidate requirements or criteria list with stable reference codes and per-item/full-set review actions. |
+| **phase outcome** | Durable closure artifact for a phase, including summary and closure basis. |
+| **closeability** | Deterministic minimum bar for whether the user may close a phase now. |
+| **readiness band** | Coarse descriptive signal separate from closeability. |
+| **exploration knowledge** | Durable grounding/design knowledge: `goal`, `term`, `context`, `constraint`, `decision`, and `assumption`. |
+| **constraint** | A durable boundary on acceptable scope or solution space; `non-goal` is a subtype. |
+| **decision** | A chosen direction among plausible alternatives, with durable consequences. |
+| **assumption** | A material belief supporting a direction or decision that could later prove false. |
+| **invariant** | Planned ontology kind for a property that must remain true across relevant states, transitions, executions, versions, or semantic revisions. |
+| **example** | Planned ontology kind for concrete positive, negative/counterexample, edge-case, or not-relevant cases that disambiguate intent. |
+| **progressive checkability** | Represent each intent item at the weakest useful witness level today while preserving paths toward stronger witnesses. |
+| **checkability** | A typed field describing the strongest oracle currently witnessing an intent item. |
+| **witness strength** | The breadth/confidence of an item's oracle coverage, distinct from the oracle kind. |
+| **relation policy** | Per-relation registry deciding display, cascade, export, staleness, reconciliation, criteria-help, weak-suggestion participation, support/status semantics, operational directionality, and endpoint-relative labels for compact dependency/dependent snapshots. |
+| **context pack** | A scenario-specific semantic briefing derived from intent graph truth, workflow state, provenance, unresolvedness, relation neighborhoods, and authority labels. |
+| **prompt/context scenario substrate** | Foundation for markdown prompts, reusable doctrines, typed context packs, and repeatable prompt probes before UI commitment. |
+| **agent mutation surface** | Brunch-owned typed handler layer for any durable data mutation initiated by an agent. |
+| **agent capability contract** | Stable, typed read or mutation contract exposed to agents/harnesses with authority and replay metadata. |
+| **agent capability CLI** | Local JSONL adapter exposing Brunch capability contracts without defining its own product API or mutation authority. |
+| **AI runtime provider** | Shared server seam resolving configured LLM provider, model names, API-key source, and provider-specific options. |
+| **XDG auth state** | User-scoped credential/config storage outside the project workspace. |
+| **graph-review finding** | A turn-owned structured critique artifact; not itself semantic truth or reconciliation debt. |
+| **candidate graph bundle** | Coherent scenario-options commit/review unit with tradeoffs, generated intent items/edges, provenance, risks, and preconditions. |
+| **greenfield / brownfield** | Grounding strategies for new concepts vs existing-codebase work. |
+| **end-to-end build / incremental feature** | Delivery postures for whole-system shaping vs bounded changes. |
+| **output view** | Terminal route available when phases are closed; not a workflow phase. |
## Verification Design
### Verification Commands
-| Step | Check | Command |
-| --- | --- | --- |
-| 1 | Formatting | `npm run fmt:check` |
-| 2 | Lint + type check | `npm run lint` |
-| 3 | Unit tests | `npm run test` |
-| 4 | Build | `npm run build` |
-| all | Full gate | `npm run verify` |
+| Step | Check | Command |
+| ---- | ----------------- | ------------------- |
+| 1 | Formatting | `npm run fmt:check` |
+| 2 | Lint + type check | `npm run lint` |
+| 3 | Unit tests | `npm run test` |
+| 4 | Build | `npm run build` |
+| all | Full gate | `npm run verify` |
### Verification Policy
@@ -347,30 +366,39 @@ Every meaningful code change should pass `npm run fix` in the inner loop and `np
### Oracle Strategy by Loop Tier
-| Tier | Oracle families | What they prove | Main targets |
-| --- | --- | --- | --- |
-| Inner | Schema validation, type-aware linting, focused unit/integration tests, negative-space regressions | Boundaries remain type-safe; persistence/transport seams do not collapse. | I4, I17, I24, I44, I48, I54, I72, I87, I100–I119 |
-| Middle | Round-trip/replay oracles for seeded projects, hydration, export, and resume | Seeded or persisted state can be loaded, projected, re-rendered, and exported without semantic loss. | Requirements 13–15; I24, I44, I100 |
-| Middle | Route/query ownership and state-model oracles | Mutations refresh owned surfaces only; major in-flight modes are named and projectable. | Requirements 5, 7, 14; A20, A64; I24, I108, I110 |
-| Middle | Prompt/context golden and classifier corpora | Prompt/context output remains inspectable and regressable as prompts evolve. | Requirements 40, 41; A84, A88; I112, I114 |
-| Outer | Fixture-backed manual walkthroughs | Phase transitions, export, resume, graph view, and waiting states feel legible. | Requirements 5, 13–15, 33 |
-| Outer | Brownfield and scenario-quality review | Generated questions/bundles are useful, grounded, honest about tradeoffs, and not overconfident. | Requirements 3, 16, 20; A67, A68, A90, A91 |
-| Outer | Dense cascade/reconciliation walkthroughs | Users can understand and resolve downstream graph impact without skipping necessary judgment. | A48, A88, I113, I114 |
+| Tier | Oracle families | What they prove | Main targets |
+| ------ | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
+| Inner | Schema validation, type-aware linting, focused unit/integration tests, negative-space regressions | Boundaries remain type-safe; persistence/transport seams do not collapse. | I4, I17, I24, I44, I48, I54, I72, I87, I100–I119 |
+| Middle | Round-trip/replay oracles for seeded projects, hydration, export, and resume | Seeded or persisted state can be loaded, projected, re-rendered, and exported without semantic loss. | Requirements 13–15; I24, I44, I100 |
+| Middle | Route/query ownership and state-model oracles | Mutations refresh owned surfaces only; major in-flight modes are named and projectable. | Requirements 5, 7, 14; A20, A64; I24, I108, I110 |
+| Middle | Prompt/context golden and classifier corpora | Prompt/context output remains inspectable and regressable as prompts evolve. | Requirements 40, 41; A84, A88; I112, I114 |
+| Middle | Context-snapshot replay and handle-refresh oracles | Turn-level snapshots replay unchanged after graph edits; active handles re-snapshot only when changeset-backed item versions advance. | Requirement 45; A95; D154; I120 |
+| Middle | Structured context-builder assertions plus selected golden renderings | Item-list, neighborhood, and economic whole-graph snapshots contain required ids, sections, relation/provenance signals, and stable rendering boundaries without overfitting prose. | Requirements 40, 45; A84, A95; I112, I120 |
+| Outer | Fixture-backed manual walkthroughs | Phase transitions, export, resume, graph view, and waiting states feel legible. | Requirements 5, 13–15, 33 |
+| Outer | Brownfield and scenario-quality review | Generated questions/bundles are useful, grounded, honest about tradeoffs, and not overconfident. | Requirements 3, 16, 20; A67, A68, A90, A91 |
+| Outer | Dense cascade/reconciliation walkthroughs | Users can understand and resolve downstream graph impact without skipping necessary judgment. | A48, A88, I113, I114 |
### Acknowledged Blind Spots
-| Blind spot | Current mitigation | Revisit trigger |
-| --- | --- | --- |
-| Qualitative interviewer and kickoff quality across many repo shapes | Manual brownfield walkthroughs on representative repos. | Brownfield regressions recur or kickoff strategy debates cannot resolve qualitatively. |
-| Transcript trust after hydration | Legible placeholders/summaries plus manual transcript review. | Users cannot understand what happened after replay. |
-| UI lock/wait causality | Explicit visible in-flight states and manual browser inspection. | Manual inspection cannot explain repeated lock/disappearance bugs. |
-| Story quality and phase differentiation | Story variants reviewed against seeded walkthroughs. | Story/app drift grows or design disagreement blocks implementation. |
-| Observer latency and layout refresh freshness | Runtime observation during manual sessions. | A20 shows recurring latency or coarse refresh pain. |
-| Revisit/reconciliation UX adequacy | Structural coverage on graph/persistence seams plus manual cascade walkthroughs. | Revisit work moves active or users skip unresolved needs. |
-| Real browser scroll/hover/touch behavior | Outer-loop manual graph-view walkthroughs. | Users report chip navigation/preview failures. |
-| Performance under large intent graphs | Defer explicit budget until dense specs are common. | Render lag visible on representative walkthroughs. |
-| Visual regression infrastructure | Manual-heavy stance accepted. | Three or more visual regressions are caught only after merge. |
-| LLM classifier correctness and determinism | Proposals never auto-apply; re-run exists; corpora/goldens grow from failures. | Substantive items are mislabeled as auto-confirm or repeated runs diverge materially. |
+| Blind spot | Current mitigation | Revisit trigger |
+| ------------------------------------------------------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
+| Qualitative interviewer and kickoff quality across many repo shapes | Manual brownfield walkthroughs on representative repos. | Brownfield regressions recur or kickoff strategy debates cannot resolve qualitatively. |
+| Transcript trust after hydration | Legible placeholders/summaries plus manual transcript review. | Users cannot understand what happened after replay. |
+| UI lock/wait causality | Explicit visible in-flight states and manual browser inspection. | Manual inspection cannot explain repeated lock/disappearance bugs. |
+| Story quality and phase differentiation | Story variants reviewed against seeded walkthroughs. | Story/app drift grows or design disagreement blocks implementation. |
+| Observer latency and layout refresh freshness | Runtime observation during manual sessions. | A20 shows recurring latency or coarse refresh pain. |
+| Revisit/reconciliation UX adequacy | Structural coverage on graph/persistence seams plus manual cascade walkthroughs. | Revisit work moves active or users skip unresolved needs. |
+| Real browser scroll/hover/touch behavior | Outer-loop manual graph-view walkthroughs. | Users report chip navigation/preview failures. |
+| Performance under large intent graphs | Defer explicit budget until dense specs are common. | Render lag visible on representative walkthroughs. |
+| Visual regression infrastructure | Manual-heavy stance accepted. | Three or more visual regressions are caught only after merge. |
+| LLM classifier correctness and determinism | Proposals never auto-apply; re-run exists; corpora/goldens grow from failures. | Substantive items are mislabeled as auto-confirm or repeated runs diverge materially. |
+| Economic whole-graph snapshot quality | Structured assertions plus one selected golden rendering fixture; human review for whether compact context is useful. | Secondary-chat answers show missing authority/provenance/relation context or snapshots become too large for routine prompts. |
+| Context-handle refresh before real item versions | Defer handle freshness semantics until `changeset-ledger` supplies real item versions rather than blessing a temporary content fingerprint. | `chat-context-provision` is pulled before changeset-backed item versions exist. |
+
+### Design Notes
+
+- Context-handle freshness should wait for real item versions from `changeset-ledger`; do not bless a temporary content/edge fingerprint as the durable refresh oracle.
+- Economic whole-graph snapshot verification should pair structured JSON assertions for required sections/counts/ids with a small number of golden renderings and human review, rather than treating exact prose as the primary oracle.
### Acceptance Criteria
diff --git a/src/client/__tests__/router.test.tsx b/src/client/__tests__/router.test.tsx
index 8720d8dd..b8a3d078 100644
--- a/src/client/__tests__/router.test.tsx
+++ b/src/client/__tests__/router.test.tsx
@@ -13,9 +13,9 @@ import type { SpecificationState } from '@/shared/specification.js';
import { queryClient } from '../query-client.js';
const fetchMock = vi.fn();
-let interviewViewRenderCount = 0;
-let interviewViewMountCount = 0;
-let interviewViewUnmountCount = 0;
+let workspaceViewRenderCount = 0;
+let workspaceViewMountCount = 0;
+let workspaceViewUnmountCount = 0;
const minimalSpecificationState: SpecificationState = {
specification: {
@@ -86,18 +86,14 @@ vi.mock('../routes/-project-list.js', () => ({
fetchSpecificationListLoaderData: vi.fn(async () => []),
}));
-vi.mock('../routes/specification/$id/_view/-interview-controller', () => ({
- useInterviewController: () => ({ __brand: 'interview-controller' }),
-}));
-
-vi.mock('../routes/specification/$id/_view/-interview-view.js', () => ({
- InterviewView: () => {
- interviewViewRenderCount += 1;
+vi.mock('../routes/specification/$id/_view/-continuous-workspace-view.js', () => ({
+ ContinuousWorkspaceView: () => {
+ workspaceViewRenderCount += 1;
useEffect(() => {
- interviewViewMountCount += 1;
+ workspaceViewMountCount += 1;
return () => {
- interviewViewUnmountCount += 1;
+ workspaceViewUnmountCount += 1;
};
}, []);
@@ -171,9 +167,9 @@ async function renderRouteAt(pathname: string) {
beforeEach(() => {
queryClient.clear();
fetchMock.mockReset();
- interviewViewRenderCount = 0;
- interviewViewMountCount = 0;
- interviewViewUnmountCount = 0;
+ workspaceViewRenderCount = 0;
+ workspaceViewMountCount = 0;
+ workspaceViewUnmountCount = 0;
fetchMock.mockImplementation(async (input) => defaultFetchHandler(input));
vi.stubGlobal('fetch', fetchMock);
});
@@ -303,9 +299,9 @@ describe('generated routeTree', () => {
await renderRouteAt('/specification/42/grounding');
expect(await screen.findByRole('heading', { name: 'Interview screen' })).toBeTruthy();
- expect(interviewViewRenderCount).toBe(1);
- expect(interviewViewMountCount).toBe(1);
- expect(interviewViewUnmountCount).toBe(0);
+ expect(workspaceViewRenderCount).toBe(1);
+ expect(workspaceViewMountCount).toBe(1);
+ expect(workspaceViewUnmountCount).toBe(0);
await act(async () => {
await queryClient.invalidateQueries({ queryKey: ['specification', '42', 'entities'] });
@@ -324,17 +320,17 @@ describe('generated routeTree', () => {
return url === '/api/specifications/42';
});
expect(specificationFetches).toHaveLength(1);
- expect(interviewViewRenderCount).toBe(1);
- expect(interviewViewMountCount).toBe(1);
- expect(interviewViewUnmountCount).toBe(0);
+ expect(workspaceViewRenderCount).toBe(1);
+ expect(workspaceViewMountCount).toBe(1);
+ expect(workspaceViewUnmountCount).toBe(0);
});
it('refreshes the specification bundle without remounting the interview route for mutation-owned invalidation', async () => {
await renderRouteAt('/specification/42/grounding');
expect(await screen.findByRole('heading', { name: 'Interview screen' })).toBeTruthy();
- expect(interviewViewMountCount).toBe(1);
- expect(interviewViewUnmountCount).toBe(0);
+ expect(workspaceViewMountCount).toBe(1);
+ expect(workspaceViewUnmountCount).toBe(0);
await act(async () => {
await queryClient.invalidateQueries({ queryKey: ['specification', '42', 'bundle'] });
@@ -353,8 +349,8 @@ describe('generated routeTree', () => {
return url === '/api/specifications/42/entities?mode=active-path';
});
expect(entityFetches).toHaveLength(1);
- expect(interviewViewMountCount).toBe(1);
- expect(interviewViewUnmountCount).toBe(0);
+ expect(workspaceViewMountCount).toBe(1);
+ expect(workspaceViewUnmountCount).toBe(0);
});
it('redirects a completed specification index to the output route through one authoritative bundle fetch path', async () => {
diff --git a/src/client/routes/specification/$id/-phase-navigation-sidebar.tsx b/src/client/routes/specification/$id/-phase-navigation-sidebar.tsx
index dbaed537..c4134404 100644
--- a/src/client/routes/specification/$id/-phase-navigation-sidebar.tsx
+++ b/src/client/routes/specification/$id/-phase-navigation-sidebar.tsx
@@ -13,6 +13,8 @@ import {
} from '@/shared/phase-descriptors.js';
import type { SpecificationTurn } from '@/shared/specification.js';
+import { useWorkspaceFocus } from './-workspace-focus.js';
+
function formatStatus(status: WorkflowPhaseState['status']): string {
switch (status) {
case 'closed':
@@ -96,6 +98,8 @@ export function PhaseNavigationSidebar({
const currentReachablePhase = getCurrentReachablePhase(workflow);
const phaseTurnCounts = getPhaseTurnCounts(turns);
const outputAvailable = allWorkflowPhasesClosed(workflow);
+ const workspaceFocus = useWorkspaceFocus();
+ const focusedPhase = workspaceFocus?.focusedPhase ?? null;
return (