V3 Issue #247: Canonical conversation history
Issue: #247 — Canonical conversation history
Requirements: R101–R105, R107, R113, R114, R191
Branch: Evan/v3-247-conversation-history, based on main at d71d2bd42b68485feb4571d3aad490d7d8327aa3
Delivery: one GPG-signed PR; leave the PR unmerged and issue open.
Scope and ownership
The runtime owns turn recording and projections. Reuse the SQLite events table through private repository methods, with a ConversationHistory service for immutable scoped records, projections, forks, and import reconciliation. Keep workspace snapshots in HistoryManager; link snapshot nodes to journal cursors transactionally rather than adding another history store. Provider continuation remains private and bound to the adapter/model that created it. Interfaces consume display projections, and generic event/SSE APIs never expose journal payloads. AgentEngine replacement, structured compaction redesign, and unrelated V3 issues are out of scope.
The implementation path currently spans openkyrozen/persistence/events.py and store.py, openkyrozen/agent/runtime.py and loop.py, action_rounds.py, initial_response.py, response_recovery.py, prompts.py, context accounting, openkyrozen/workspace/history.py, and the CLI/TUI/Web chat adapters. Existing typed contracts live in openkyrozen/providers/models.py; public runtime events live in openkyrozen/agent/events.py and remain redacted projections.
Indexed implementation plan
Task 1 — Private journal repository and immutable entry model
- [x] Add regressions for append idempotency, conflicting duplicate IDs, stale expected heads, deep defensive snapshots, unsupported versions, scope isolation, and generic event/API privacy.
- [x] Extend the existing event repository with transaction-scoped conversation append/read/head methods. Use unique entry IDs and expected-head checks; do not expose journal rows through generic event listing.
- [x] Add versioned immutable entries and
ConversationHistorywith user/workspace/session scope, append, provider/display projections, fork/branch, and explicit legacy import operations. - [x] Add lossless codecs for
ModelResponse,ToolReply, andToolResult; validate continuation provider/model binding before native projection.
Task 2 — Runtime-owned recording and restart behavior
- [x] Record user input, actual model responses, correlated tool results, interaction/plan references, and turn outcomes exactly once; fail closed before any subsequent dispatch if persistence fails.
- [x] Reconcile legacy
AgentRuntime.chat()message lists through an explicit import adapter without deleting or rewriting the prior branch. - [x] Restore scoped history on session initialization, including the actual CLI/default session ID. Never infer historic protocol actions by parsing prose and never execute restored calls.
- [x] Add restart/branch tests, including a saved continuation with a changed adapter/model that pauses native projection explicitly without rebinding or replay.
Task 3 — Workspace history linkage and conversation projection
- [x] Link workspace snapshot nodes to the journal cursor in the same transaction as history-node creation; rollback appends branch selection while preserving abandoned journal records and existing filesystem recovery behavior.
- [x] Replace accumulated action-round summaries with one evolving projection. Record each provider response and result once; repairs append only their correction. Keep routing, learning, compaction, and delegation requests auxiliary.
- [x] Retain legacy list shapes and compaction as derived views; native projections preserve complete call/reply groups or fail safely.
Task 4 — Context assembly, integrations, and evidence
- [x] Route CLI/TUI/Web user/final recording through runtime projections; remove duplicate interface writes while preserving display and wire contracts.
- [x] Build deterministic stable/dynamic/conversation prompt sections, remove automatic graph-context injection, and preserve registry schemas and the existing one-inventory-per-request legacy path.
- [x] Extend
context_usage()with content-free attribution, prefix fingerprint, new/retransmitted history and duplicate-entry counts while preserving existing fields and separating estimates from provider totals. - [x] Update architecture/provider/history docs and tests. Run Python 3.12/3.13 focused and full validation, browser tests with installed Chromium, Go TUI and offline acceptance; record all skips.
- [ ] Obtain independent review, fix material findings, verify signed commit locally and on GitHub, attach PR, and wait for final-head CI/reviews.
Validation record
Post-review fixes on PR #283
- [x] Reproduce and fix seven new Codex findings from review of
1112102: typed history request projection, occurrence-based duplicate metrics, rollback conflict translation, journal-only session discovery, textless failure projection, empty canonical Web branch authority, and in-loop tool inventory refresh. - [x] Reproduce and fix three additional Codex findings: typed-message context preflight, failure-path cache refresh, and preventing a truncated display cache from replacing canonical history.
- [x] Fix the matching CodeRabbit findings and isolate the Web journal test from shared database/session state. Preserve the explicit restart policy: mismatched provider/model continuation fails closed instead of being converted to text or rebound.
- [x] Re-run focused regressions and both supported Python full suites; repository checks passed. Final-head CI and review-thread resolution remain pending publication.
- [x] Reproduce and fix four further final-head findings: safely compact legacy dictionary prefixes ahead of native history; pin final provider continuations even when they have no tool calls; include model-free turn outcomes in provider projection without duplicating model responses; and keep the canonical journal authoritative over older Web snapshots.
- Follow-up signature check: GitHub reports the prior head commit
d20fbf7asbad_email; the account's published GPG key markspiggyevan123@gmail.comverified and the noreply address unverified. A corrected follow-up uses the verified email; the existing commit history is not rewritten.
PASS — Python 3.12 and 3.13 focused conversation-history, rollback, interaction, Web, streaming, and native-provider suites (92 tests per focused run; one unrelated browser skip in the initial focused runs).
PASS — Full Python 3.12 and 3.13 suites: KYROZEN_BROWSER_TESTS=1 make test PYTHON=.venv/bin/python and .venv313/bin/python (833 tests each, including browser session/auth tests).
PASS — Python 3.13 make check, make lint, make docs-check, and make tui-test; git diff --check.
PASS — Latest focused compaction, conversation-history, native-provider, provider-contract, and Web suites: 106 tests on Python 3.13.
PASS — Latest full Python 3.12 and 3.13 suites: 837 tests each with KYROZEN_BROWSER_TESTS=1; browser session/auth coverage ran.
PASS — Latest make check, make lint, make docs-check, make tui-test, and git diff --check. make check and make docs-check require the project virtual environment on PATH; the system Python lacked the installed requests dependency.
PASS — Four final-head review findings reproduced and fixed. Their review threads still need replies and resolution after the signed commit is published.
PASS — Seven Codex findings reproduced and fixed: rollback session refresh, nested branch projection, legacy snapshot backfill, authoritative Web journal projection, early acceptance finalization, atomic rollback notifications, and per-dispatch context metrics (including typed native messages). Added regressions pass.
PASS — Post-review regressions: canonical provider projection and call/reply correlation, repeated journal identity accounting, stale rollback error translation, journal-only session discovery without payload exposure, textless error projection, empty canonical Web branch, and tool inventory replacement/fingerprint invalidation.
PASS — Final Python 3.12 and 3.13 full suites: 833 tests each, including browser auth/session tests with KYROZEN_BROWSER_TESTS=1. An earlier Python 3.12 run hit a transient 5-second headless-startup timeout; the isolated test and subsequent complete run passed.
PASS — Context-preflight, failed-turn cache, truncation, saved-model binding, and Web test-isolation regressions pass. Mismatched provider/model continuations are explicitly rejected, preserving the no-rebind restart policy.
PASS — Python 3.13 make check, make lint, make docs-check, and make tui-test; git diff --check.
PASS — CodeRabbit reviewed head 2f0c746 and posted four findings; three were fixed. Its automatic recovery suggestion was declined because converting/rebinding mismatched continuation state would violate the selected fail-closed restart policy. Codex posted three further findings; all are fixed. Threads remain open until the fixes are published.
PASS — Two additional Codex findings on 469ca5a were reproduced and fixed: explicit legacy replacement now commits its branch marker and replacement entries in one head-checked transaction, and context history metrics remap only retained message identities after preflight or overflow compaction. Atomic-failure and compacted-history regressions pass.
Compatibility and risks
Legacy callers keep their message-list shape through an explicit import adapter. Private journal rows contain full conversation and continuation data and must remain unavailable to generic event APIs, logs, and interface projections. If a saved native continuation cannot be validated against its live adapter/model, the request pauses for explicit recovery; tools are never automatically replayed.