feat(coding): add renderer conversation store
This commit is contained in:
1 parent
a0722574f3
commit
36626c88b5
14 files changed
+2703
-1227
No files matched your search
@@ -0,0 +1,158 @@
|
||||
# Task: Implement PI-110 Renderer Snapshot Patch Store
|
||||
|
||||
## Identity
|
||||
|
||||
- Task ID: 20260823-pi-renderer-store-b7e2c4a1
|
||||
- Mode: Feature
|
||||
- Branch: codex/20260823-pi-renderer-store-b7e2c4a1-pi-renderer-store
|
||||
- Worktree: D:\Datas\OthersProjects\makelore-pi-renderer-store-b7e2c4a1
|
||||
- Base commit: a0722574f3b36cb73ec8833787711e6bef1c5c54
|
||||
- Owner: codex-root
|
||||
- Status: In Progress
|
||||
|
||||
## Scope
|
||||
|
||||
- Implement PI-110's vendor-neutral Renderer facade and one Zustand store keyed
|
||||
by stable Makelore `conversationId`.
|
||||
- Consume the shared PI-010 Snapshot/Patch reducer for snapshot-first SSE,
|
||||
stale-generation discard, target-only gap recovery, and reconnect.
|
||||
- Own per-Conversation snapshot/run/error/queue/model/draft/unread/cursor plus
|
||||
optimistic prompt request state and fine-grained selectors.
|
||||
- Add focused facade/store/SSE/render-count tests. Do not migrate Chat UI,
|
||||
feature-complete controls, or remove the old OpenCode store in this ticket.
|
||||
|
||||
## Intent And Constraints
|
||||
|
||||
- Base is the planner-approved PI-100 cumulative HEAD `a072257`; the exact and
|
||||
sole Ready Frontier is `{PI-110}`.
|
||||
- Renderer access goes only through `src/lib/host-api.ts`; the SSE facade must
|
||||
initialize the cached Host token/base before constructing EventSource.
|
||||
- Reuse the PI-010 contract/reducer as the single product normalization seam.
|
||||
The first real Renderer consumer exposed that its Electron-only source
|
||||
location requires unavailable composite-project declarations in a clean
|
||||
worktree, so the canonical modules now live in `shared/` and Electron keeps
|
||||
thin re-exports. Do not duplicate Pi/OpenCode event mapping or import vendor
|
||||
types, paths, wire enums, credentials, or raw diagnostics.
|
||||
- A generation/sequence gap invalidates and reloads only its target
|
||||
Conversation. Old generations are ignored and accepted prompts are never
|
||||
replayed because an event stream reconnects.
|
||||
- Optimistic user identity is stable across durable reconciliation by
|
||||
`clientRequestId`. Definite rejection and uncertain acceptance retain enough
|
||||
request/draft/attachment state for explicit UI recovery; neither path
|
||||
silently resends.
|
||||
- Store updates replace only the target Conversation entry. Timeline selectors
|
||||
for the selected Conversation must not rerender when a hidden Conversation
|
||||
streams; hidden/sidebar consumers use lightweight summaries.
|
||||
- PI-120 owns Composer and timeline UI; PI-130 owns model/thinking/queue/
|
||||
compaction/interaction/subagent/changes UI; PI-140 owns old OpenCode removal.
|
||||
- Real Provider remains Explicitly Waived / Accepted Risk with
|
||||
`realTurnVerified=false`; macOS remains deferred to mandatory PI-150. Neither
|
||||
is Pass evidence. No subagents are authorized.
|
||||
|
||||
## Project Context Loaded
|
||||
|
||||
- Task identity: `20260823-pi-renderer-store-b7e2c4a1`, feature mode, isolated
|
||||
branch/worktree above, base `a0722574f3b36cb73ec8833787711e6bef1c5c54`.
|
||||
- Concurrent Task Gate passed. The only semantically adjacent planning task,
|
||||
`20260820-partner-create-model-parity-c83d`, still has no defined scope or
|
||||
owned files. The canonical main integration task is Blocked and is not a
|
||||
write target. Other active tasks concern unrelated Canvas/Robot/Learning or
|
||||
review scopes.
|
||||
- Planning Gate inputs read: memory index, project positioning/success fields,
|
||||
current state, decision/system/architecture/domain documents, evidence/
|
||||
reflection/commitment/stale indexes, PI-010 and PI-100 records, and the exact
|
||||
PI-110 ticket plus relevant Spec sections.
|
||||
- The canonical project-positioning fields remain placeholders; repository
|
||||
guidance and the planner-owned Pi Spec/ticket are authoritative here.
|
||||
- Confirmed seams: vendor-neutral contracts and strict reducer in
|
||||
`electron/coding-runtime`, snapshot-first `/api/coding/events`, target GET
|
||||
snapshot, `hostApiFetch`, `ensureHostApiToken`, and Zustand selector patterns.
|
||||
- No accepted ADR changes product positioning or conflicts with this task.
|
||||
Existing real OpenCode/provider commitments remain historical and do not
|
||||
authorize a compatibility store or runtime fallback.
|
||||
- Gate result: Passed.
|
||||
|
||||
## Plan
|
||||
|
||||
1. Add a Renderer-owned type surface and minimal typed `/api/coding` facade for
|
||||
target snapshot, prompt acceptance, and initialized global/target SSE.
|
||||
2. Implement a dependency-injectable Zustand store that keeps reducer state,
|
||||
summary, draft, unread, request lifecycle, loading/recovery and errors per
|
||||
Conversation while owning selection and one global event stream.
|
||||
3. Route snapshot and ordered patch events through the shared reducer; ignore
|
||||
stale generation, reload only a gapped target, and never replay mutations on
|
||||
reconnect.
|
||||
4. Add optimistic user-node/draft/attachment reconciliation and granular
|
||||
selectors that preserve unrelated Conversation object identity.
|
||||
5. Add facade, two-Conversation SSE, gap/reconnect, optimistic failure, vendor
|
||||
boundary and render-count regressions; then run focused/full verification,
|
||||
build, documentation gates, and planner review.
|
||||
|
||||
## Outcome
|
||||
|
||||
- Added a Renderer-owned product type surface and minimal typed Host facade for
|
||||
target snapshots, prompt acceptance, and EventSource creation. EventSource
|
||||
construction first hydrates the cached Host token/base, including a cold
|
||||
Renderer process.
|
||||
- Added one dependency-injectable vanilla Zustand store with React selectors.
|
||||
Each Conversation owns its reducer snapshot/cursor, load and target error,
|
||||
unread state, lightweight summary, draft revision/attachments, and prompt
|
||||
request lifecycle. Store updates preserve unrelated Conversation identity.
|
||||
- Added snapshot-first SSE ingestion, native reconnect state, stale-generation
|
||||
discard, per-target sequence/generation-gap recovery, load single-flight,
|
||||
and connection-generation protection. Reconnect never replays a prompt and
|
||||
an obsolete connection flight cannot clear a newer one.
|
||||
- Added optimistic user nodes keyed by `clientRequestId`. Durable upsert keeps
|
||||
the optimistic UI node id; definite rejection restores an untouched draft
|
||||
and marks the node failed; uncertain delivery restores the draft while
|
||||
retaining the request/node for explicit reconciliation without resend.
|
||||
- Promoted the existing product-neutral PI-010 contracts, reducer, product
|
||||
detail validator, and subagent detail validator to `shared/`. Existing
|
||||
Electron paths are compatibility-free source re-exports of the same
|
||||
functions, so Main, Renderer, fixtures, and tests cannot drift into separate
|
||||
reducer implementations.
|
||||
- Added facade/store tests for two interleaved Conversations, target-only gap
|
||||
recovery, stale generations, native reconnect, connection-flight ABA,
|
||||
optimistic accepted/rejected/uncertain outcomes, attachment restoration,
|
||||
vendor-neutral source boundaries, shared reducer identity, and render-count/
|
||||
summary identity under hidden streaming.
|
||||
- PI-120/130/140 boundaries remain unchanged. No Chat page or legacy OpenCode
|
||||
store consumer was changed by PI-110.
|
||||
|
||||
## Verification
|
||||
|
||||
- `pnpm exec vitest run tests/unit/coding-conversations-facade.test.ts tests/unit/coding-conversations-store.test.tsx`:
|
||||
2 files / 12 tests passed.
|
||||
- `pnpm exec vitest run` for the two PI-110 tests plus PI-010 contracts,
|
||||
coding core routes, event projector, Conversation runtime, product tools,
|
||||
and subagent suites: 8 files / 75 tests passed.
|
||||
- `pnpm run typecheck`: passed after the shared product seam removed the clean
|
||||
Renderer -> composite Electron declaration dependency.
|
||||
- `pnpm run lint:check`: passed with zero errors and the same six unrelated
|
||||
Renderer warnings in `ExecutionGraphCard.tsx`, Home, and Makelore.
|
||||
- `pnpm test`: 211 files / 2275 passed / 2 skipped (2277 total).
|
||||
- `pnpm run build:vite`: Renderer, Electron Main, Preload, and release utility
|
||||
production builds passed; existing dynamic-import and large-chunk warnings
|
||||
remain.
|
||||
- Electron E2E is not applicable yet: PI-110 intentionally exposes no page or
|
||||
user-visible interaction. The real Chat/Composer binding and its E2E belong
|
||||
to PI-120; the render-count store acceptance is covered directly here.
|
||||
- Real Provider remains Explicitly Waived / Accepted Risk with
|
||||
`realTurnVerified=false`. macOS x64/arm64 remains deferred to mandatory
|
||||
PI-150. Neither is recorded as Pass.
|
||||
|
||||
## Follow-ups
|
||||
|
||||
- PI-120 should bind the Composer/timeline to this store without restoring any
|
||||
read from `src/stores/opencode.ts`.
|
||||
|
||||
## Promotion Candidates
|
||||
|
||||
- Type: Architecture. Proposal: keep Makelore-owned Conversation contracts and
|
||||
the strict Snapshot/Patch reducer in `shared/`, with Main and Renderer
|
||||
importing/re-exporting that single implementation rather than depending on
|
||||
Electron composite build artifacts or copying normalization logic. Evidence:
|
||||
clean `pnpm run typecheck`, shared/Main function identity regression, 8-file
|
||||
75-test impacted suite, and full 211-file unit/build verification. Future
|
||||
impact: PI-120/130 can consume product DTOs without vendor/Main imports; any
|
||||
contract amendment must retain Main/Renderer reducer equivalence.
|
||||
Reference in new issue
Block a user