Files
makelore/.project-docs/30-worklog/tasks/20260823-pi-chat-timeline-c8f31a62.md

14 KiB
Raw Blame History

Task: Implement PI-120 core chat and first-conversation UX

Identity

  • Task ID: 20260823-pi-chat-timeline-c8f31a62
  • Mode: Feature
  • Branch: codex/20260823-pi-chat-timeline-c8f31a62-pi-chat-timeline
  • Worktree: D:\Datas\OthersProjects\makelore-pi-chat-timeline-c8f31a62
  • Base commit: 54d8bb2e4a
  • Owner: codex-root
  • Status: Ready for Integration

Scope

  • Implement PI-120 — Core Chat and first-Conversation UX on cumulative PI-110 delivery HEAD 54d8bb2.
  • Add a vendor-neutral CodingChatPanel composition, first-Conversation metadata selection/creation, core Composer, and memoized timeline renderers for message/thinking/tool/compaction/boundary nodes.
  • Bind the page exclusively to /api/coding/* Renderer facades and the PI-110 Conversation store, including optimistic prompt acceptance, preparing/queued/running/error/recovery states, draft continuity, and hidden-Conversation render isolation.
  • Add focused component/performance coverage and the first-prompt Electron E2E. Do not implement PI-130 feature-complete controls or PI-140 legacy removal.

Intent And Constraints

  • The exact Ready Frontier is {PI-120}. PI-110 is Done at audit HEAD 934ba02 and cumulative delivery HEAD 54d8bb2; PI-130 remains locked until this ticket is accepted.
  • Textarea editability depends only on an active project, an enabled Agent, and the absence of a project destruction/migration transition. It never depends on worker/runtime/metadata loading, provider latency, diagnostics, another Conversation, or the current Conversation run state.
  • Conversation creation is local metadata only. Snapshot/prewarm is lazy and Conversation-scoped; preparation beyond ten seconds becomes a recoverable error while the draft stays editable.
  • A send immediately creates one stable optimistic user node. HTTP 202 is only acceptance; later provider/tool failure never removes the accepted user message, and uncertain delivery is never silently resent.
  • Renderer components must use granular PI-110 selectors and memoized blocks. Hidden Conversation streaming cannot rerender the selected timeline; cumulative tool output replaces rather than appends duplicate content.
  • Do not read src/stores/opencode.ts, call /api/opencode, import Pi/OpenCode wire types, or mechanically rename the legacy 4k-line panel. The old panel remains only as PI-140 removal residue after the new page composition takes ownership.
  • PI-130 still owns model/thinking controls, steer/follow-up queue controls, compaction/retry/context actions, interactions, subagent graph, changes/files/ browser/skills/commands, and Conversation archive/fork/title/unread UI.
  • The planner amended the attachment contract: POST /api/coding/attachments accepts one bounded image binary and returns only {attachmentId,mime,byteLength}; authenticated GET /api/coding/attachments/:id/content returns raw bytes. Upload happens only on Send, each local variant has one in-flight/result, and Renderer state/protocol keep references rather than base64.
  • The planner selected public patch-batch delivery only. Main retains private single-patch envelopes and original seq, batches per Conversation/generation for 1633 ms with bounded early flush, and cancels an old generation's pending batch. Renderer validates the full batch and folds it in one Zustand transaction; malformed/gapped batches recover only their target.
  • Real Provider remains Explicitly Waived / Accepted Risk with realTurnVerified=false. macOS x64/arm64 remains deferred to mandatory PI-150. Neither is Pass evidence. No subagents are authorized.

Project Context Loaded

  • Task identity: 20260823-pi-chat-timeline-c8f31a62, feature mode, isolated branch/worktree above, exact base 54d8bb2e4a6f1a7dd857827659e60d1b4a1fb6f5.
  • Concurrent Task Gate passed. The only semantically adjacent planning task, 20260820-partner-create-model-parity-c83d, still has undefined scope and no claimed files. The canonical main integration task is Blocked and is not a write target; all other planning owners are unrelated Canvas/Robot/Learning or read-only scopes.
  • Planning Gate inputs read: memory index, active task record, project positioning/current state/decision/system/architecture/domain documents, PI-100/105/110 completion records, exact PI-120 ticket and PI-130 boundary, and relevant UX-*, REN-*, API, performance and recovery Spec sections.
  • Canonical positioning and project-level success fields are placeholders and the integrated memory still describes the legacy OpenCode UI. Repository guidance plus the planner-owned Pi Spec/tickets and reviewed cumulative code are authoritative for this feature branch.
  • Confirmed seams: schema-v2 project/config/Conversation routes already provide local-only metadata; PI-110 provides the typed Snapshot/prompt/SSE facade, shared reducer, per-Conversation store, optimistic identity, target-only recovery, and granular selectors. The current Chat page still imports the legacy OpencodeChatPanel and is the cutover seam.
  • No accepted ADR conflicts with this ticket. The attachment transport gap is recorded above and has been escalated to the planner instead of silently inventing a route.
  • Gate result: Passed.

Plan

  1. Add the minimal vendor-neutral project/config/Conversation Renderer facade and metadata store needed to load the active project, enabled Agents and Conversations without touching the legacy OpenCode store.
  2. Build a small CodingChatPanel composition and switch the Chat page to it; make first-Conversation selection/creation local-only and keep Textarea readiness independent of snapshot/runtime preparation.
  3. Implement focused Composer submission/recovery UI over the PI-110 draft and optimistic request lifecycle, including preparing/queued/running/error status without a page-wide loading gate.
  4. Implement memoized/windowed message, thinking, tool, compaction and boundary blocks that update only the selected target and keep large/cumulative output bounded; apply the planner's attachment ruling without expanding PI-130.
  5. Add red-capable first-Conversation, core Chat, optimistic failure, hidden-Conversation/render-count and 100 KB performance fixtures, plus the first-prompt Electron E2E; then run focused/full validation, build, documentation gates and planner review.

Outcome

  • Replaced the Chat page composition with a vendor-neutral CodingChatPanel backed only by /api/coding/* facades. It loads active project/config/local Conversation metadata, auto-creates the first local Conversation, and keeps the Composer editable while runtime Snapshot preparation is held.
  • Added text/image Composer behavior, stable optimistic user nodes, distinct preparing/accepted/running/uncertain/error/recovery feedback, Enter/Shift+Enter and IME handling, Send-time single-flight image upload, and authenticated object-URL previews without base64 state or protocol payloads.
  • Added a memoized/windowed timeline for message, Markdown, thinking, tool, compaction, boundary and notice nodes. Hidden Conversation batches leave the selected timeline selector stable; cumulative tool output is replaced rather than duplicated.
  • Added Main-owned attachment binary routes/IPC transport and public Snapshot + patch-batch SSE delivery. Main batches at 24 ms by default with item/byte early-flush bounds; Renderer atomically rejects malformed/gapped batches, buffers during target recovery, trims Snapshot-covered items and replays only a strict continuous tail.
  • Fixed a supported concurrency defect exposed by the full suite: the Pi Session Registry and Coding Project Service now receive the same project- scoped Conversation store provider, so runtime bindings and metadata writes serialize through one mutation queue instead of racing the same file.
  • Closed the first planner review findings after candidate 612135f: the authenticated Host server now admits only the exact image-binary upload exception; empty/invalid/oversize/not-found attachments have stable typed errors and supported image signatures are checked before disk writes.
  • Made active target ownership atomic across Agent switches. An old or archived Conversation cannot supply the visible draft/timeline/prompt target, and a slow automatic or explicit create completion only selects when its captured project and Agent are still active. Submission flights and errors are scoped per Conversation, so one pending/rejected target does not disable another.
  • Bounded each message to 16 local images and four concurrent uploads. A real Electron image fixture now traverses the Renderer facade, IPC channel and authenticated Host server, reads the stored bytes back for the optimistic timeline preview, observes one upload, and verifies the prompt contains only attachment ids rather than base64.
  • Extended target-only gap recovery: when the first recovery Snapshot remains behind a buffered continuous tail, Renderer requests one fresh target Snapshot; a repeated identical stale response becomes a retryable error instead of remaining in an infinite recovering state.
  • Closed the incremental planner review findings after bec93d0: attachment editing is locked for the originating Conversation until upload and HTTP 202 acceptance settle, so removal or a next-message paste cannot mutate the captured image set. Attachment preparation failures now remain local to the Composer, restore the draft, permit direct retry without runtime recovery, retain already uploaded variants for reuse, and wait for every concurrent upload flight to settle before releasing the edit lock. Attachment route failures use only registered CODING_ATTACHMENT_INVALID, CODING_ATTACHMENT_NOT_FOUND, and CODING_STORAGE_WRITE_FAILED codes while preserving 413/404 status.
  • Synchronized README.md with the current Pi core Chat, first-Conversation, batch and attachment behavior. PI-130 feature controls and PI-140 legacy removal remain outside this task.

Verification

  • First implementation candidate 612135f received planner review result Standards Needs Fix / Spec Needs Fix. PI-120 remained the unique Ready Frontier; the findings above were treated as blocking rather than advancing PI-130.
  • The correction candidate bec93d0 received incremental planner review result Standards PASS / Spec Needs Fix. Its three remaining attachment-state and typed-error findings were implemented and kept PI-130 locked pending another planner review.
  • Final candidate 1fe8863 received planner code review result Standards PASS / Spec PASS. The planner confirmed the all-settled upload semantics, held-sibling regression, direct attachment retry, registered error codes, and absence of duplicate-upload or cross-Conversation lock leakage.
  • Post-review focused suites passed: attachment Host routes, stale recovery, shared ProjectService/Registry mutation queue, slow Agent switch, cross- Conversation submission isolation, attachment count/concurrency and pressure tests all pass. The consolidated focused run covered 3 files / 30 tests, and coding-chat-panel.test.tsx covered 6/6 behavior tests.
  • REN-008 actual-path fixture passed with 100 runtime patch items, 20 public patch batches, 21 SSE frames including Snapshot, 20 Renderer transactions, 20 React commits, 131,148 wire bytes, and measured Main-to-React p95 35.995 ms against the <=50 ms budget. It includes mixed message blocks, 4 KiB tool output and more than 100 KiB of cumulative thinking output.
  • Latest attachment-state focused run passed: 3 files / 39 tests, including delayed upload/removal, delayed HTTP 202/next-image isolation, local preparation failure/direct retry, uploaded-variant reuse, and registered Host error codes.
  • pnpm test: passed, 218 files / 2321 passed / 2 skipped.
  • pnpm run typecheck: passed.
  • pnpm run lint:check: passed with 0 errors and six unchanged warnings in ExecutionGraphCard, Home, and Makelore.
  • pnpm run build:vite: passed; existing Vite dynamic-import and chunk-size warnings remain.
  • pnpm exec playwright test tests/e2e/pi-coding-first-chat.spec.ts: passed, 1/1. The post-review real-image fixture also passed 5/5 fresh-userData repeats with one upload, Host readback preview, optimistic message, HTTP 202 and no base64 in later payloads. The earlier text-only first-Conversation fixture passed 20/20 fresh-userData runs below the 500 ms editability budget.
  • git diff --check: passed; only repository line-ending conversion notices were printed.
  • Real Provider remains Explicitly Waived / Accepted Risk with realTurnVerified=false; no Provider Account, credential isolation, protocol-specific endpoint, rate-limit or real concurrency behavior is claimed as Pass.
  • macOS x64/arm64 execution remains user-deferred to mandatory PI-150; no macOS Pass is claimed.

Follow-ups

  • PI-130 owns Conversation model/thinking controls, steer/follow-up queue, compaction/retry/context controls, interactions, subagents, changes/files, browser, skills/commands, and archive/fork/title/unread UI.
  • PI-140 owns removal of legacy OpenCode runtime/routes/dependencies/UI/tests and migration notice.
  • PI-150 must run final packaged cross-platform proof, including the deferred macOS x64/arm64 matrix. Real Provider qualification remains explicitly waived unless the user changes that decision.

Promotion Candidates

  • Preserve the public Snapshot + patch-batch hard-cut contract and the target-only recovery semantics in the planner-owned Pi Spec/tickets after implementation review.
  • Preserve the explicit attachment upload/read Host contract, Send-time single-flight rule, and reference-only Renderer state in the planner-owned Pi Spec/tickets after implementation review.