Files
makelore/.project-docs/30-worklog/tasks/20260822-pi-conversation-contracts-b72c4e19.md

8.2 KiB

Task: Implement PI-010 Conversation contracts and reducer

Identity

  • Task ID: 20260822-pi-conversation-contracts-b72c4e19
  • Mode: Feature
  • Branch: codex/20260822-pi-conversation-contracts-b72c4e19-pi-conversation-contracts
  • Worktree: D:\Datas\OthersProjects\makelore-pi-conversation-contracts-b72c4e19
  • Base commit: 72f7a26ca9
  • Owner: codex
  • Status: Completed

Scope

  • Implement PI-010 Conversation contracts and reducer from the merged Pi cutover Spec/ticket graph.
  • Add the vendor-neutral CodingConversationRuntime Interface and product DTOs under electron/coding-runtime.
  • Add one strict Snapshot/Patch reducer for both hydrated and live product fixtures.
  • Add an InMemoryConversationRuntime Implementation for later Host/Renderer product tests.
  • Add focused fixtures/tests for mixed messages, thinking, tools, queue, interactions, compaction, subagents, generation/sequence handling, reconciliation, and fail-closed unknown input.
  • Do not change Host routes, Renderer stores/components, Pi process/RPC wiring, project schema/migration, OpenCode behavior, or final packaging in this ticket.

Intent And Constraints

  • The external seam is the small product-owned CodingConversationRuntime Interface. Pi/OpenCode types, enums, paths, CLI options, provider details, and raw events must not cross it.
  • Keep UI node IDs distinct from durable sourceEntryId; reconcile optimistic user nodes by clientRequestId without replacing UI identity.
  • Enforce exact schemaVersion, worker generation, and per-Conversation sequence. Unknown schema/op or a sequence gap invalidates only that reducer state until a fresh Snapshot replaces it; stale generations are ignored.
  • Treat tool output as cumulative replacement and attach tool results to the existing tool node; never create a tool-result message.
  • agent_end is not idle. Only the product fixture projected from agent_settled may transition the run to idle.
  • Use one in-process reducer Module and one InMemory Implementation. Do not add speculative ports, adapters, compatibility layers, vendor aliases, or unrelated refactors.
  • Preserve the hard cutover and the explicit PI-000 waivers: they unlock this ticket but do not convert real Provider or macOS evidence into Pass.

Project Context Loaded

  • Planning commit a8c0806 and PI-000 implementation commit 2bc423e are part of the registered base commit 72f7a26, so Spec, tickets, evidence, and implementation share one Git history without appearing as PI-010 drift.
  • The first PI-010 registration used 2bc423e as its base and correctly failed the Task Documentation Gate after the planner merge appeared as foreign documentation. Its code-only checkpoint was re-applied here as 4deba3a; the old task registration was released, not completed.
  • The current canonical application still runs OpenCode; this ticket only introduces the vendor-neutral product seam that later tickets will consume.
  • maintain-project-docs Concurrent Task Gate and Planning Gate passed in this corrected worktree. Relevant peers are ready for integration and have no write overlap with this task.
  • codebase-design directs the Interface to stay small while reducer/runtime behavior remains behind it; internal test seams are not exposed as public adapters. The user-prohibited parallel-subagent design path is not used.
  • The canonical project-positioning record remains a placeholder; repository guidance, current state, and the merged Pi Spec/tickets are authoritative for this task.

Plan

  1. Define the vendor-neutral runtime Interface and all PI-010 product DTOs.
  2. Implement strict Snapshot replacement and ordered Patch reduction with stable identity reconciliation.
  3. Implement the InMemory runtime against the same Interface and product envelopes.
  4. Add locked-version product fixtures and focused acceptance tests, including no-vendor-import assertions.
  5. Run focused tests, typecheck, scoped/full lint, full unit, production compile, and project-documentation gates.

Outcome

  • Added the vendor-neutral CodingConversationRuntime Interface and product-owned Snapshot/Patch, node, run, queue, context, interaction, model, worker, usage, error, input, and acceptance DTOs.
  • Added one strict reducer Module for Snapshot replacement and ordered live envelopes. It drops stale generations/duplicate sequence, invalidates only the target Conversation on future generation, sequence gap, unknown schema/op, malformed payload, explicit invalidation, or missing delta target, and resumes only after a valid Snapshot replacement.
  • Kept live UI identity stable while reconciling durable sourceEntryId and optimistic clientRequestId; cumulative tool updates replace output, and tool results remain attached to tool nodes.
  • Added InMemoryConversationRuntime as the second Implementation of the product Interface, with deterministic injected clock/id seams, idempotent prompt/queue acceptance, target abort, model/thinking updates, compaction, fork, recovery generation, disposal, and patch subscription.
  • Added locked @earendil-works/pi-coding-agent@0.84.2 fixture provenance whose projected values are product DTOs only. Fixtures cover text/thinking, parallel tools, tool error, cumulative output, retry, queue, interaction, compaction willRetry, subagent, hidden custom input, agent_end checkpoint, and authoritative agent_settled idle.
  • No Host route, Renderer store/component, project schema, Pi process/RPC implementation, OpenCode behavior, or packaging path changed.

Verification

  • Installed the merged frozen lockfile in this corrected worktree with the exact repository-pinned pnpm@10.33.4; 1,018 packages were reused from the local store.
  • pnpm exec vitest run tests/unit/coding-conversation-contracts.test.ts: 14 tests passed.
  • pnpm run typecheck: passed.
  • Scoped ESLint for the three runtime files, fixture, and focused test: passed.
  • pnpm run lint:check: passed with zero errors and six pre-existing React warnings outside this ticket.
  • pnpm test: 179 files / 2,097 tests passed.
  • pnpm run build:vite: Renderer, Main, Preload, and utility production builds passed; existing mixed-import/chunk-size warnings remain outside this ticket.
  • Scoped vendor scan over electron/coding-runtime: no OpenCode or Pi package import/reference found (rg exit 1 / zero matches).
  • Acceptance audit passed: snapshot/live equivalence, target-only gap invalidation, stale generation discard, stable optimistic/durable identity, cumulative tool replacement, no tool-result message, retry/compaction behavior, agent_end non-idle, agent_settled idle, and unknown fail-closed behavior all have focused assertions.
  • Task Documentation Gate passed: required project-doc files exist, ownership/doc-drift boundaries are clean, git diff --check passed, and the scoped trailing-whitespace scan returned zero matches.

Follow-ups

  • PI-050, PI-060, and PI-110 should consume this Interface/reducer directly. If their real implementation exposes a missing product capability, amend this upstream contract with focused equivalence tests rather than passing vendor wire through a caller.
  • PI-060 owns actual Pi live/hydrated event projection. It must preserve the locked fixture boundary established here and keep hidden/unknown raw events out of product state.
  • PI-110 owns the Renderer store; it must maintain one reducer state per Conversation so a gap cannot invalidate unrelated Conversations.

Promotion Candidates

  • Target: canonical Pi cutover architecture after Integration Gate. Proposal: record CodingConversationRuntime plus the Snapshot/Patch reducer as the product-owned seam shared by Main orchestration, Renderer state, and tests; Pi/OpenCode wire remains implementation-private. Evidence: electron/coding-runtime/contracts.ts, conversation-reducer.ts, in-memory-conversation-runtime.ts, and 14 focused acceptance tests. Future impact: later worker/event/Renderer tickets can vary their Implementation without widening the Interface or duplicating normalization logic. Semantic conflicts: none with the merged Spec/ticket graph; the current OpenCode runtime is unchanged until the hard-cutover release unit completes. Human confirmation required: no; the planning session already authorized and merged this ticket's scope.