feat(client-core): merge conversations by daemon sequence and turn identity - #512
feat(client-core): merge conversations by daemon sequence and turn identity#512Zerlight wants to merge 11 commits into
Conversation
|
Your Claude subscription has hit its usage limit. It resets at 11:30am (UTC). Re-trigger Pullfrog after the reset, or add an Add repo secret → · Model settings → · Setup docs → · Ask in Discord →
|
Greptile SummaryThis PR introduces graph-backed conversation seeding and merges projection snapshots with live events using daemon
Confidence Score: 4/5The PR is not safe to merge until interior forks replace the displayed lineage instead of retaining messages from the abandoned branch. The new graph-change suppression correctly avoids re-reading for ordinary continuations, but it applies the same rule to forks whose new echo is already buffered; because forks emit no rewind, the client combines two sibling lineages in one conversation. Files Needing Attention: packages/client/core/src/conversation-store.ts
|
| Filename | Overview |
|---|---|
| packages/client/core/src/conversation-store.ts | Implements watermark-based projection merging and graph resynchronization, but misclassifies interior forks as linear continuations. |
| packages/client/core/src/conversation-read.ts | Walks consistent graph snapshots across cursor pages and falls back to legacy transcript seeding when no turn graph exists. |
| packages/host/engine/src/session/session-input-dispatcher.ts | Gives live prompt echoes the durable turn-derived row identity before committing graph movement. |
| packages/host/engine/src/conversation/projection-service.ts | Projects durable user rows using the same identity and branch cursor as live echoes. |
| packages/client/workbench/src/surface/use-seeded-conversation.ts | Integrates projection reads, persisted fallbacks, and store-requested revalidation into the workbench. |
| packages/client/workbench/src/mock/dev-mock-host.ts | Adds stamped event journaling and graph-backed conversation reads to the development host. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Read conversation projection] --> B[Fold active-lineage seed]
B --> C[Fold stamped live events above watermark]
C --> D{Graph revision advances}
D -->|New linear child echo is present| E[Continue without re-read]
D -->|Unknown leaf| F[Request fresh projection]
D -->|Interior fork echo is present| G[Currently treated as continuation]
G --> H[Old branch descendants remain visible]
Reviews (1): Last reviewed commit: "fix(engine,client-core): unify automatio..." | Re-trigger Greptile
efde0c0 to
3da74bb
Compare
There was a problem hiding this comment.
Greptile has paused reviews on this repository — it used its 100 free open-source review credits for this billing period. Reviews resume automatically on September 23. To continue before then, an organization admin can keep reviews running past the free credits — those bill as normal usage.
|
Your Claude subscription has hit its usage limit. It resets at 11:30am (UTC). Re-trigger Pullfrog after the reset, or add an Add repo secret → · Model settings → · Setup docs → · Ask in Discord →
|
There was a problem hiding this comment.
🔵 Needs a closer look
It changes core conversation identity/merge semantics across schema, engine, client-core, workbench, dev-mock, and mobile, so it warrants final human review despite strong automated coverage.
Pull request overview
Phase 2 of the CODE-627 conversation turn graph cutover: the client now seeds and merges conversation history using the daemon’s (epoch, seq) positions plus a daemon-minted “one user-row identity per turn”, and falls back to the legacy transcript (history.read) path when the turn graph is unavailable.
Changes:
- Introduces a projection-based seed (
conversation.readpaging) and a projection merge path that drops already-covered live frames by daemon watermark and requests a single re-read on drift (epoch jump / seq gap / graph leaf mismatch). - Unifies “live echo” and “conversation.read” user-row identity via
userRowMessageId(turnId)so the client no longer reconciles two ids for the same turn. - Adds a UI “history unavailable” placeholder item and updates dev-mock + tests to stamp/journal frames so reads reproduce the live stream.
File summaries
| File | Description |
|---|---|
| packages/presentation/ui/src/chat/types.ts | Adds history-unavailable conversation item kind to the UI chat model. |
| packages/presentation/ui/src/chat/turn-segment-view.tsx | Renders the new history-unavailable marker in the turn segment switch. |
| packages/presentation/ui/src/chat/history-unavailable-marker.tsx | Introduces the web UI marker component for unavailable projected history. |
| packages/presentation/ui/src/tests/activity-groups.test.ts | Updates test helpers to include the new boundary kind. |
| packages/presentation/i18n/src/locales/zh-cn.ts | Adds historyUnavailable translation key for workbench/mobile namespaces. |
| packages/presentation/i18n/src/locales/en.ts | Adds historyUnavailable translation key for workbench/mobile namespaces. |
| packages/host/engine/src/session/session-input-dispatcher.ts | Switches prompt/command echoes to durable per-turn row identity (userRowMessageId). |
| packages/host/engine/src/session/orchestrator.ts | Aligns orchestrator-side prompt echo identity with durable turn identity. |
| packages/host/engine/src/session/live-session.ts | Exports encodeLiveBranchCursor for reuse in read projections. |
| packages/host/engine/src/conversation/projection-service.ts | Uses userRowMessageId for read user rows and attaches legacy edit cursor when available. |
| packages/host/engine/src/tests/engine-turn-submit.test.ts | Tightens assertions to ensure echoed user-message ids match the durable row identity. |
| packages/host/engine/src/tests/engine-schedule.test.ts | Ensures schedule wiring emits user rows with the durable row identity. |
| packages/host/engine/src/tests/engine-conversation-read.test.ts | Verifies conversation.read rows share identity + edit cursor with the live echo. |
| packages/foundation/schema/src/wire/index.ts | Re-exports the new graph feature-gate wire version constant. |
| packages/foundation/schema/src/wire/conversation.ts | Introduces CONVERSATION_GRAPH_WIRE_VERSION and documents the graph wire introduction. |
| packages/foundation/schema/src/model/conversation.ts | Adds userRowMessageId(turnId) helper (daemon-minted “one user row per turn”). |
| packages/client/workbench/tests/integration/dev-mock-transport.test.ts | Updates subscription callback shape to the new event-buffer envelope signature. |
| packages/client/workbench/tests/integration/dev-mock-projection.test.ts | Adds E2E coverage for projection seeding + resync behavior against dev-mock. |
| packages/client/workbench/src/surface/use-seeded-conversation.ts | Switches seeding to readConversationSeed, persists projection seeds, and wires store resync to SWR mutate. |
| packages/client/workbench/src/surface/seed-cache.ts | Adds projection seed persistence keyed by session, sharing the same LRU cap with transcript seeds. |
| packages/client/workbench/src/surface/tests/seed-cache.test.ts | Tests projection persistence behavior and shared LRU entry cap. |
| packages/client/workbench/src/mock/dev-mock-host.ts | Stamps/journals frames with (epoch, seq) and serves conversation.read from the journal for parity. |
| packages/client/workbench/src/mock/tests/dev-mock-conversation.test.ts | Expands parity tests for stamping, turn recording, read replay, and epoch bump on resume. |
| packages/client/workbench/AGENTS.md | Documents updated workbench seeding/resync/persistence responsibilities. |
| packages/client/core/tests/integration/conversation-store-projection.test.ts | Adds comprehensive projection-merge behavior tests (watermark drop, gaps/epoch, graph drift, placeholders, attachment overlay). |
| packages/client/core/tests/integration/conversation-read.test.ts | Adds paging-walk tests for conversation.read projection reads (watermark, drift restarts, conflict, give-up). |
| packages/client/core/tests/integration/conversation-client.test.ts | Tests graph feature detection by wire version and buffering of daemon position/envelope fields. |
| packages/client/core/tests/integration/control-client.test.ts | Updates event subscription callback shape to match new SequencedAgentEvent delivery. |
| packages/client/core/src/react.tsx | Extends useConversation to accept projection seeds and surface a resync callback. |
| packages/client/core/src/index.ts | Exports the new conversation-read surface. |
| packages/client/core/src/conversation.ts | Adds a history-unavailable item kind and builder support to insert it into the timeline. |
| packages/client/core/src/conversation-store.ts | Splits store into projection vs history merge paths; adds resync signaling and watermark-based merge for projection. |
| packages/client/core/src/conversation-read.ts | Implements conversation.read paging walk + unified seed selection (projection → transcript → none). |
| packages/client/core/src/client/pending-registry.ts | Adds pending registries for conversation graph and read results. |
| packages/client/core/src/client/event-buffer.ts | Preserves daemon (epoch, seq) positions and attribution on buffered events; updates subscriber callback signature. |
| packages/client/core/src/client/conversation-graph-changes.ts | Adds per-session latest graph-change registry + subscription. |
| packages/client/core/src/client/control-channel.ts | Adds conversation.graph.get and conversation.read correlated control-plane APIs. |
| packages/client/core/src/client.ts | Wires new conversation graph/read APIs, event envelope ingestion, and graph change tracking; adds supportsConversationGraph gate. |
| packages/client/core/src/tests/event-buffer.test.ts | Ensures stamped repeats are retained to keep daemon sequence contiguous. |
| packages/client/core/CLAUDE.md | Adds per-directory agent instructions link. |
| packages/client/core/AGENTS.md | Documents the two seeding paths, merge rules, resync reasons, and key invariants. |
| apps/mobile/src/runtime/use-seeded-conversation.ts | Switches mobile seeding to readConversationSeed and handles projection resync by re-running the read. |
| apps/mobile/src/runtime/tests/use-seeded-conversation.test.ts | Adds coverage for projection seeding and resync-triggered re-reads; updates empty-graph behavior. |
| apps/mobile/src/components/conversation/timeline-item.tsx | Renders the history-unavailable item in the mobile timeline. |
Review details
- Files reviewed: 44/44 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…he turn graph requests
…r-row identity via schema
…to re-read on drift
…tion when the host serves one
…hen a leaf appears
3da74bb to
cfa0cce
Compare
|
Your Claude subscription has hit its usage limit. It resets at 11:30am (UTC). Re-trigger Pullfrog after the reset, or add an Add repo secret → · Model settings → · Setup docs → · Ask in Discord →
|
|
Review round on this PR (Greptile, one inline thread): the fork-retains-abandoned-messages finding is not reachable — every submit that is not a continuation of the active leaf relaunches under a new event epoch, and reads carry no user echoes, so the graph-move shortcut only ever sees a child of the displayed leaf. The constraint is now stated on |

Summary
Phase 2 of CODE-627 — Conversation turn graph & immutable attachment store. Linear: https://linear.app/arcbox/issue/CODE-634/featclient-core-merge-conversations-by-daemon-sequence-and-turn
Stack: #511 ← this PR (
ruocheng/code-634, baseruocheng/code-632) ← #513. Merge bottom-up; this PR's diff is only its own commits.Phase 2 client cutover: when the host serves the graph, client-core seeds from
conversation.readpages and merges by the(epoch, seq)watermark and the daemon-minted user-row identity, asking for one re-read on a position skip; the CODE-621 content-matching machinery survives only as the old-daemon path. UI renders the history-unavailable placeholder on web and mobile, workbench and mobile seed from the projection, and the dev mock stamps and journals its frames so reads reproduce the live stream.Commits
Verification
Every commit passed
pnpm check:ciandpnpm testat its own tip; the stack tip (1d942a62; the same tree as the originally gated73fc5ff2plus the two review fixes below on 628/629) is atpnpm check:ci0 errors,pnpm test3408 passed / 1 skipped. Adversarial reviewers (one per axis, isolated read-only worktrees) reviewed the branch; each P1/P2 was reproduced with a failing test or a probe step before its fix — the round-by-round record is in the Linear issue's comments. A dev-mock end-to-end test seeds a conversation through the turn graph; the compiled renderer was probed headlessly againstdev:mock.Checklist
pnpm check:ciandpnpm testboth pass (no Rust changes)dev:mockin headless ChromeAGENTS.mdand module docs in this branch)