Skip to content

FE-656: Add patch / event-stream data model design for side-chat V4#82

Closed
kostandinang wants to merge 5 commits into
mainfrom
ka/fe-656-side-chat_v4
Closed

FE-656: Add patch / event-stream data model design for side-chat V4#82
kostandinang wants to merge 5 commits into
mainfrom
ka/fe-656-side-chat_v4

Conversation

@kostandinang
Copy link
Copy Markdown
Contributor

@kostandinang kostandinang commented May 1, 2026

TL;DR

Adds the design document for the patch / event-stream data model that side-chat V4 will swap onto. V1 / V2 / V3 stay on the current schema (one knowledge_item table, turn-scoped provenance via turn_knowledge_item); this design describes the substrate the next phase migrates onto.

The model replaces direct in-place mutation of knowledge_item with four concepts:

  1. Branches — every line of conversation is a named branch with a lifecycle status (live, speculative, stale, discarded, merged, archived). Stale is recoverable; discarded is permanent.
  2. Events — append-only log; the only durable truth. kind ∈ { turn, side-chat-apply, architect-proposal, observer-capture, merge, branch-create, branch-status-change }.
  3. Patches — first-class rows for individual mutations, per-patch addressable, can be staged (event_id IS NULL) or applied.
  4. Item versions — read cache, scoped per-(item_id, branch_id); rebuildable from the log.

Branching covers five intent-driven triggers: edit past turn, side-chat apply, drill-down, architect proposal, revisit closed phase. Each has a default lifecycle policy (which sibling stays live, what auto-stales, what supersedes what).

Status

Draft / future-facing. Not a V4 implementation — V4 isn't a frontier item in memory/PLAN.md yet. This is a stake-in-the-ground so V1 / V2 / V3 are designed as if the substrate already existed; V4 becomes a substrate swap rather than a redesign.

What this changes in memory/SPEC.md

  • D80 ("no turn-tree branching") relaxes — branching is allowed, but only via tracked Branch entities with explicit origin_kind. Spirit preserved (no chaos), letter updated (forks now exist).
  • D113 ("one durable workflow model") reaffirms at the event-log layer — "one event log per spec."
  • A71 (patch / event-stream model), A72 (item versioning), A73 (architect loop) graduate from "low-confidence future" assumptions to real decisions as the corresponding capabilities ship.
  • D89, D125, D127, D128, D130, D131 unchanged — they describe surfaces that read/write through the substrate.

References

  • Design doc: docs/design/PATCH_EVENT_STREAM_MODEL.md (this PR)
  • Parent side-chat design: docs/design/SIDE_CHAT.md §9 phasing — V4 line names this substrate as the dependency
  • Linear epic: FE-656 — V4 line in the issue body
  • SPEC.md: assumptions [A71, A72, A73]; decisions [D80 (revised), D113 (reaffirmed), D89/D125/D127/D128/D130/D131 (unchanged)]
  • Sibling sub-issues under FE-656: FE-672 (V1), FE-673 (V2), FE-674 (V3) — all on the current schema (knowledge_item + turn_knowledge_item)
  • Branch: independent of ka/fe-656-side-chat (V1 implementation work) — off main, can advance on its own review timeline

Review checklist

  • TL;DR + decisions snapshot land before substrate detail
  • §2.5 ER diagram and §2.6 vocabulary map render in GitHub preview
  • §6 worked examples (one per origin_kind) are internally consistent with §3 lifecycle policies
  • Relaxation of D80 in §9.1 is acceptable framing — not a contradiction with current spec
  • §10 open questions are scoped to V4 implementation planning, not blocking this design

@linear-code
Copy link
Copy Markdown

linear-code Bot commented May 1, 2026

FE-656 Side chat

Side chat — graph-launched chat with patch-list staging

TL;DR

Problem / Motivation

  • Given a structured view of the specs, user may want to ask questions or discuss the spec without losing their place

Acceptance criteria

  • From the structured spec view, users can open a popover side chat
  • Users can highlight and attach context from the structured spec view to the chat
  • Users can trigger updates to the spec from the chat

Concept

Popover-to-panel chat anchored to items in the structured spec view. Two entry modes (per-row chat-with button + text-selection floating menu); three user-facing intents (Explore · Edit · Annotate); proposed changes stage in a persistent top-bar patch list and apply in batch.

The side-chat is the unified user-driven mutation surface. It subsumes three previously-separate horizon items: D128 graph-launched refinement, trigger-popover composer, revisit / edit mode + cascade preview.

Phasing

  • V1 — panel + Explore + Annotate. Annotation-only patches. → FE-672
  • V2 — Edit (router) + Drill-down + Propose-edge. Soft-impact edits apply directly; hard defers to V3. → FE-673
  • V3 — Hard edit absorbs REVISIT_MODULE — cascade preview inline + batch secondary-thread. → FE-674
  • V4 — patch / event-stream model, item versioning, architect-loop integration, multi-thread (depends on upstream A71/A72).

Acceptance-criteria mapping

  • From the structured spec view, users can open a popover side chat → V1 (FE-672)
  • Users can highlight and attach context from the structured spec view → V1 (FE-672)
  • Users can trigger updates to the spec from the chat → V2 + V3 (FE-673, FE-674)

Design doc & PR

Review in Linear

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

Concretizes A71/A72/A73 from memory/SPEC.md into a proposed data
structure (branches, events, patches, item_versions) that supports
branched turns, staged patches with batched apply, and architect-loop
HITL review through the same surface as the side-chat.

V1/V2/V3 still ship on the current store-of-stores; this is the
substrate V4 swaps onto.
The §3.5 ER diagram now carries the key enums on each entity
(branch.origin_kind/status, event.kind, patch.op/kind/impact_tier),
so the diagram is self-contained for the substrate vocabulary.

The new §3.6 maps today's V1-V3 terminology (turn, observer capture,
side-chat apply, spec state) onto the V4 substrate, anchors where
'turn' fits as one event kind among seven, and clarifies how D80 and
D113 relate to the new layering.
- Fold §1 ("Why this exists") into a one-line lead on §1 (decisions
  snapshot); the TL;DR already covers the why.
- Compress §2.6's four-paragraph narrative after the vocabulary
  diagram into one paragraph naming the shift.
- Tighten §3.3 supersession from a procedural sketch + commentary
  to two short paragraphs.
- Compress §4.3's five-alternative comparison (M1/M2/M3a/M3b/M3c)
  into one paragraph.
- Merge §6.1, §6.2, §6.3 (main branch / canonical view) into a
  single short §5 — most of the prior table's rows were "unchanged"
  noise.
- Trim §6.5 (revisit) — structurally identical to §6.4, just a UI tag.
- Trim §9.2 from a six-decision recap to one line.
- Trim open questions from 7 to the 4 most consequential.
- Delete §12 (recommendation summary) — restated TL;DR + decisions.

Net: 605 → 518 lines (~14%). Renumbered sections sequentially after
removing §1 and §12. No content claims changed.
@kostandinang kostandinang force-pushed the ka/fe-656-side-chat_v4 branch from be73f13 to ab049f5 Compare May 1, 2026 15:05
@kostandinang kostandinang self-assigned this May 1, 2026
kostandinang and others added 2 commits May 1, 2026 20:10
Today's schema is one `knowledge_item` table discriminated by `kind`,
not "per-kind tables" or a "store-of-stores". Updates the TL;DR, §1,
and §2.6 to describe the real schema. Substrate proposal unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Preamble status, "When does this ship?", and D113 line now reference
the real schema (`knowledge_item`) instead of "stores".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@kostandinang
Copy link
Copy Markdown
Contributor Author

As we discussed with @lunelson and concluded on a simpler model, closing this PR and following subsequently with the new design.

graphite-app Bot pushed a commit that referenced this pull request May 7, 2026
https://www.loom.com/share/b0d96bc2f0a849d8b57b043bb648a9aa

## Stack Context

This PR is the side-chat **V1.2 vertical slice** under FE-656, stacked on **PR #81** (V1.1 — Class 1 Explore: chat anchored to spec items). V1.1 proved the chat seam; **V1.2 proves the durable mutation seam** — the side-chat can now produce real, persistent changes to a spec.

PR #88 is sized as one coherent slice. **V1.2-D** (top-bar canonical Apply/Undo), **V1.2-E** (floating selection menu), and **V1.2-F** (multi-item pinning) are deferred to follow-up PRs per `memory/PLAN.md`.

## What

End-to-end Annotate flow: the user opens the side-chat on a knowledge item, types a note, hits Save, and it persists to the database. Existing notes for the pinned item render above the chat log as a collapsible `Notes` section.

The slice lands as three cards plus follow-on UX work:

- **A** — Annotation server seam: new `annotation` table + REST endpoints.
- **B** — `PatchListProvider` client module: React provider + hooks for staging and applying patches.
- **C** — End-to-end wiring: side-chat composer talks to the patch list and the server.
- **Auto-apply + UX coherence** — user-typed annotations save on submit (no extra Apply click); three clear states for in-flight / saved / failed.
- **C2 — Show existing annotations** — collapsible `Notes` section above the chat log.

## Why

V1.1 vertically proved the chat seam end-to-end (graph → side-chat → SSE → streaming reply). Without V1.2, the side-chat is read-only — Class 4 Annotate, V2 Edit / Drill-down / Propose-edge, and V4 architect-loop emissions all need somewhere to write. V1.2 establishes that surface.

Two design choices worth attention before merge:

### D132 — Patch-list module shape

`/ln-design` explored four shapes in parallel (minimal-API, plug-in registry, event-log-public, react-context-native). The synthesis takes the React-native public surface (mirrors `SideChatHost` exactly) but uses an event-log internal primitive. Rationale:

- **Idiomatic for this codebase** — Zero contributor-onboarding cost.
- **A71-ready internally** — When the future `appendPatch(spec, patch[])` server primitive lands, migration is "swap the reducer," not "rewrite the public API."
- **Closed discriminated union** — V2 patch kinds force a typecheck failure at the provider mount until their applier is supplied. Silent drift impossible.

### D131 — User-driven annotations auto-apply

Originally framed as "uniform staging required for all patch kinds." User feedback during this PR pushed back: re-reviewing what you just typed adds nothing for annotations. Distinction is now explicit in D131:

- **Annotate** (user-driven, low-stakes, just-typed) → auto-apply on Save. The patch list still records the patch, surfaces it transiently, and provides Undo on the resulting batch.
- **Edit / Drill-down / Propose-edge** (V2, mutates durable content) → keep the explicit Apply step. Review-before-commit matters when the operation has cascading effects.
- **Architect-loop emissions** (V4, system-driven) → keep the explicit Apply step. The user wasn't in the moment of authoring; review is the whole point.

The patch-list module supports both paths — kind-specific behavior is wired in `SideChatHost` via the auto-apply `useEffect`, not in the module itself.

## Spec / plan deltas

`memory/SPEC.md`:
- **D132** — patch-list module shape (React-context-native public, event-log-shaped internally)
- **D133** — annotation as a new durable entity, item-anchored in V1, span-anchor-ready in schema
- **D131** revised — adds the user-driven vs review-required distinction; supersedes the "uniform staging required" framing

`memory/PLAN.md`:
- Active 1 reflects V1.2 vertical slice landed; V1.2-D / E / F still owed.
- Earlier "comment-store extension" framing corrected — D133 supersedes it.

## Stacked on

- **PR #81** (`ka/fe-656-side-chat`, V1.1 Explore) — must merge first.
- **PR #82** (`ka/fe-656-side-chat_v4`, V4 patch / event-stream data model) — sibling on the same parent, independent of V1.2.

## Linear

[FE-656](https://linear.app/hashintel/issue/FE-656) — same issue as V1.1 (one Linear issue per frontier item per `CLAUDE.md`).

## Test plan

**Automated** — `npm run verify` passes (793/793 tests, includes the 9 V1.1-polish tests merged in).

**Manual walkthrough** (in browser, dev server running):

- [ ] **Happy path.** Open a spec → graph view → click `💬` on any item row → click `Annotate` → type Summary + Body → click `Save`. Expect: brief `Saving annotation…`, then `✓ Annotation saved` with Undo. New note appears in the `Notes (1)` section above the chat log.
- [ ] **Persistence.** Reload the page. Re-open chat on the same item. Note still there.
- [ ] **Multiple annotations.** Save a second note on the same item. `Notes (2)` lists both, each independently expandable.
- [ ] **Cross-item isolation.** Save a note on item A, switch chat to item B. B's panel does not show A's notes.
- [ ] **Undo.** Save a note → click Undo. Notes section refetches; the just-undone note is gone.
- [ ] **Composer validation.** `Save` disabled until both Summary and Body are non-empty (whitespace-only doesn't count).
- [ ] **Cancel.** `Esc` or `Cancel` button in composer returns to chat without saving.
- [ ] **Streaming exclusivity.** While a chat reply is streaming, the `Annotate` button is disabled.
- [ ] **Notes collapse.** Click the `Notes (N) ›` chevron to collapse the entire section. Click individual rows to expand bodies.
- [ ] **Failure path** *(stop dev server mid-save).* Stuck-staged panel appears with `Retry` and `× Discard`. Restart server → `Retry` succeeds.

**Server sanity:**
```bash
curl -s http://localhost:3000/api/specifications/<id>/annotations | jq
npm run studio  # query the `annotation` table directly
```

## Known transitional gaps (deferred to follow-ups)

- **Top-bar canonical surface** (V1.2-D). Until this lands, in-panel Undo is the only undo affordance. Per D131 the in-panel list is "convenience UI, not source of truth"; V1.2-D moves canonical Undo to the persistent app top-bar.
- **Span-anchored annotations** (V2/V3). Schema reserves `selection_start` / `selection_end` columns; V1 leaves them NULL.
- **Annotation deletion UI** beyond Undo. Broader management lands in a later card.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant