Files
makelore/.project-docs/30-worklog/tasks/20260812-first-chat-fix-b84fd29c.md

6.3 KiB

Task: Fix first conversation latency

Identity

  • Task ID: 20260812-first-chat-fix-b84fd29c
  • Mode: Feature
  • Branch: codex/20260812-first-chat-fix-b84fd29c-first-chat-fix
  • Worktree: D:\Datas\OthersProjects\makelore-first-chat-fix-b84fd29c
  • Base commit: b02c3f22e1
  • Owner: codex
  • Status: Completed

Scope

  • Bound the AI programming retry loop when the upstream model group is saturated, so the first conversation fails promptly with an actionable message instead of appearing stuck for an unbounded period.
  • Shorten the first-send local critical path by avoiding a blocking history read for a just-created, known-empty OpenCode session.
  • Add focused regression coverage at the AI proxy and ChatPanel seams, then verify the affected Renderer/Main build paths.
  • Do not change AI Canvas behavior, Agent templates, provider configuration semantics, or the general OpenCode session model.

Intent And Constraints

  • Preserve Renderer -> Host API -> Electron Main -> OpenCode ownership boundaries.
  • Keep true quota exhaustion non-retryable and distinguish it from temporary upstream saturation.
  • Use a bounded response-status projection at the Host AI proxy rather than adding a second client-side retry controller that would compete with OpenCode.
  • Preserve lazy contact selection: opening an unused Agent must not create an empty runtime session or start the runtime.
  • Keep the change surgical and test-first; avoid unrelated loading-state or bootstrap refactors in this task.

Outcome

  • Confirmed the captured long first-conversation wait was dominated by repeated upstream saturation retries, while the local first-send chain also contained a redundant blocking read of a just-created empty session.
  • Added a narrow shared saturation classifier and changed only explicit upstream-group saturation responses from upstream 429 to Host-projected 400. OpenCode 1.18.9 treats that status as terminal, so the session no longer retries this known saturation response indefinitely. Quota exhaustion remains projected to 402, and generic rate limits remain 429.
  • Added an explicit selectSession(..., { loadMessages: false }) fast path. It skips the history request only when the store already owns a cache entry for the session; unknown sessions still load defensively, and ordinary historical selection keeps its refresh behavior.
  • Changed the ChatPanel history-loading guard to distinguish an unknown empty transcript from a known-empty cache entry, while still accepting restored visible messages whose cache map has not yet been hydrated.
  • Added deterministic unit and Electron regression coverage. The Electron test keeps the new session's history GET pending and proves that the prompt POST is already sent.

Verification

  • TDD RED evidence:
    • Saturation route test expected a terminal response but observed the original 429; the new shared classifier module was not yet present.
    • First-send test observed create -> history -> history and no prompt while the known-empty history request remained pending.
    • A first implementation made two existing ChatPanel restoration tests red; they were used to correct the history guard before completion.
  • Focused unit regression command passed: 4 files, 14 selected tests passed (opencode-error-details, ai-proxy-routes, opencode-store, opencode-chat-panel).
  • Corrected ChatPanel regression command passed: 4 selected tests passed, covering the two restored existing cases, first-send fast path, and lazy contact selection.
  • pnpm run typecheck: passed.
  • ESLint for all changed product, unit-test, and Electron-test files: passed.
  • pnpm run build:vite: passed for Renderer, Electron Main, and Preload.
  • pnpm exec playwright test tests/e2e/opencode-first-chat.spec.ts: passed, 1 test.
  • pnpm test: 1548 of 1551 tests passed. The three remaining failures reproduce on main and are outside the changed paths: two pre-existing opencode-manager timing/generation tests and one youth-plain-language-skill fixture failure caused by the absent repository .opencode/agent directory.
  • git diff --check: passed; Git only reported the repository's normal LF-to-CRLF checkout warnings.

Follow-ups

  • Revisit the internal 429 -> 400 compatibility projection whenever the bundled OpenCode version changes; the current choice is tied to OpenCode 1.18.9 retry semantics.
  • The broader cold-start bootstrap still performs duplicate project/config/session/status work and uses a coarse global loading flag. Those are separate optimization candidates and were intentionally left out of this surgical fix.
  • Repair the unrelated baseline unit failures separately: the two OpenCode manager timing tests and the missing .opencode/agent test fixture.

Promotion Candidates

  • Target canonical document: .project-docs/20-architecture/data-flow.md or the closest accepted OpenCode runtime/proxy contract section.
    • Proposal: record that the Host AI proxy may apply narrow internal HTTP status projections to match the pinned OpenCode retry contract; explicit upstream-group saturation is terminal, quota exhaustion remains a distinct terminal kind, and generic rate limits remain retryable.
    • Evidence: shared/opencode-error-details.ts, electron/api/routes/ai-proxy.ts, focused route tests, and the captured repeated-saturation diagnosis.
    • Future impact: OpenCode upgrades must revalidate status retry behavior before retaining or changing the projection.
    • Semantic conflicts: none identified with current architecture; the Renderer -> Host API -> Electron Main -> OpenCode boundary remains intact.
    • Human confirmation required: no, unless canonical maintainers prefer a different internal error transport than HTTP status projection.
  • Target canonical document: .project-docs/20-architecture/data-flow.md or the OpenCode session-state contract.
    • Proposal: record sessionMessagesBySessionId own-key semantics as absent = history unknown, present [] = history known empty; fast selection may skip a history fetch only for the latter.
    • Evidence: src/stores/opencode.ts, src/pages/Chat/OpencodeChatPanel.tsx, store/Panel unit tests, and tests/e2e/opencode-first-chat.spec.ts.
    • Future impact: preserves a safe performance seam for newly created sessions without making historical session selection stale.
    • Semantic conflicts: none identified.
    • Human confirmation required: no.