diff --git a/.project-docs/30-worklog/tasks/20260825-fork-runtime-unavailable-8e7c4a21.md b/.project-docs/30-worklog/tasks/20260825-fork-runtime-unavailable-8e7c4a21.md new file mode 100644 index 0000000..f50871b --- /dev/null +++ b/.project-docs/30-worklog/tasks/20260825-fork-runtime-unavailable-8e7c4a21.md @@ -0,0 +1,72 @@ +# Task: Diagnose branch creation runtime unavailable + +## Identity + +- Task ID: 20260825-fork-runtime-unavailable-8e7c4a21 +- Mode: Feature +- Branch: codex/20260825-fork-runtime-unavailable-8e7c4a21-fork-runtime-unavailable +- Worktree: D:\Datas\OthersProjects\makelore-fork-runtime-unavailable-8e7c4a21 +- Base commit: 45d933732a8fbc0dadb07a4a4d65f0d12000c2ea +- Owner: codex-root +- Status: Done + +## Scope + +- Diagnose the installed Windows client's `从这里创建新对话分支` action returning `本地编程运行时暂时不可用。` from the exact packaged product source `45d9337`. +- Build a deterministic regression at the Renderer → Host → Pi runtime fork seam, identify the first failing ownership/runtime boundary, and report the verified cause. +- Do not change product code unless the user subsequently authorizes implementation; diagnostic fixtures or instrumentation must remain task-scoped and be removed before completion unless promoted into an approved regression test. + +## Intent And Constraints + +- Preserve Main-owned `/api/coding/*`, per-Conversation worker/session ownership, mutation no-replay semantics, and safe fixed error projection. +- Use installed-client logs only after redacting credentials, headers, prompts, project absolute paths, and user content. Do not expose or persist secrets. +- Do not infer the cause from the generic user-facing error: distinguish request/selection errors, missing or stale worker ownership, fork RPC failure, session persistence failure, and packaging/runtime resolution. +- Do not create subagents. + +## Project Context Loaded + +- Task ID: `20260825-fork-runtime-unavailable-8e7c4a21` +- Mode: Feature +- Branch: `codex/20260825-fork-runtime-unavailable-8e7c4a21-fork-runtime-unavailable` +- Worktree: `D:\Datas\OthersProjects\makelore-fork-runtime-unavailable-8e7c4a21` +- Base commit: `45d933732a8fbc0dadb07a4a4d65f0d12000c2ea` +- Other active local tasks: eleven planning/integration records were inspected; none owns the current Pi fork route/runtime path. The main-worktree integration record concerns the superseded OpenCode model-switch path. +- Overlap or semantic-conflict assessment: no blocking peer overlap. Canonical current-state/architecture documents are OpenCode-stale relative to the installed Pi product, so current Pi source and completed Pi task records are authoritative for this diagnosis. +- Read: project entry/gate/index files, task record, positioning/current state, decision and architecture indexes, module/data-flow and domain/success documents, evidence/reflection/commitment/stale indexes, and all active peer task scopes. +- Relevant understanding: the failing feature belongs to the Pi Conversation product chain and must retain Conversation-scoped ownership and no mutation replay. The packaged Windows artifact already passed Pi closure/load checks, which makes a total missing runtime less likely but does not prove the fork operation. +- Gate result: Passed. + +## Plan + +1. Locate the exact UI string, fork route, safe error mapper, runtime method, and existing fork tests from the fixed package source. +2. Construct and run the smallest unattended test that drives the same fork path and asserts the reported generic runtime-unavailable outcome. +3. Inspect redacted installed-product diagnostics and persisted Conversation/session metadata only as needed to distinguish the ranked hypotheses. +4. Minimize the failing state and state the verified cause, affected files, and an in-scope repair/verification proposal; do not implement without user authorization. + +## Outcome + +- Confirmed the reported message is caused by an invalid product-to-Pi fork entry, not by the Pi runtime being globally absent or crashed. +- `CodingConversationTimeline` currently renders `从这里创建新对话分支` for every durable message with a `sourceEntryId`, including assistant messages (`src/pages/Chat/CodingConversationTimeline.tsx:190`). The existing PI-130 fixture explicitly asserts this assistant-message behavior. +- The normative Pi cutover Spec assigns `/api/coding/conversations/:id/fork` to a **user entry**. A real pinned Pi `0.84.2` RPC experiment proved that the same persisted session accepts its user entry and deterministically rejects its assistant entry with `Invalid entry ID for forking`. +- `createPiManagedWorkerOpener` forwards the Renderer-selected entry unchanged as Pi RPC `{ type: 'fork', entryId }` after opening the target worker (`electron/coding-runtime/pi/runtime.ts:292`). `PiRpcClient` converts the rejection to `PI_RPC_RESPONSE_ERROR`; because that error has no product `publicError`, `CodingConversationService.runtimeError` maps it to `503 CODING_RUNTIME_UNAVAILABLE`, whose fixed Chinese message is exactly `本地编程运行时暂时不可用。`. +- The installed log did not provide a trustworthy click correlation: the observed `open_failure` timestamps overlap the automated package verifier. Those lines were excluded from the causal proof. +- No product source was changed. Temporary diagnostic tests were removed after the reproduction. + +## Verification + +- `corepack pnpm install --frozen-lockfile` — passed with pnpm `10.33.4` and pinned Pi `0.84.2`. +- Red-capable Renderer regression, run as `corepack pnpm exec vitest run tests/unit/coding-conversation-timeline.test.tsx` — failed deterministically in 18 ms because an assistant entry incorrectly rendered the fork button; the other four tests passed. The temporary assertion was then removed. +- Real Pi `0.84.2` diagnostic through Electron Node and `PiWorkerProcess` — passed: a synthetic persisted session was CLI-forked, Pi RPC accepted the user entry and rejected the assistant entry with `Invalid entry ID for forking`; stderr remained empty. This distinguishes an RPC contract rejection from worker crash/startup failure. The temporary diagnostic file and scratch sessions were removed. +- Static error-chain confirmation — `PI_RPC_RESPONSE_ERROR` has no product `publicError`, so the service maps it to `CODING_RUNTIME_UNAVAILABLE` and the Host route emits the exact reported Chinese message. +- Diagnostic cleanup — no product/test diff remains; only this task record is task-owned output. + +## Follow-ups + +- Recommended implementation task: render/enable fork only for durable **user** message entries, and validate the same invariant in Main before creating target metadata or spawning a target worker. Invalid/stale source entries should return `400 CODING_CONVERSATION_REQUEST_INVALID`, not a misleading runtime-unavailable response. +- Preserve the existing mutation no-replay rule. Do not retry fork automatically after timeout or an uncertain response. +- Add three permanent regressions: Renderer hides assistant-entry fork actions and still submits user entries; Main rejects assistant/unknown entry ids before target creation; real Pi `0.84.2` user-entry fork succeeds through the managed opener/final packaged seam. +- After implementation, run focused Timeline/Conversation service/Pi real-worker tests, typecheck, lint, full unit suite, `build:vite`, a real Electron branch-creation E2E, then rebuild and verify the Windows installer. + +## Promotion Candidates + +- None recorded.