Files
makelore/.project-docs/30-worklog/tasks/20260825-pi-worker-exit-thinking-5e7c2a91.md

13 KiB

Task: Fix Pi worker exit terminalization and thinking contract

Identity

  • Task ID: 20260825-pi-worker-exit-thinking-5e7c2a91
  • Mode: Feature
  • Branch: codex/20260825-pi-worker-exit-thinking-5e7c2a91-pi-worker-exit-thinking
  • Worktree: D:\Datas\OthersProjects\makelore-pi-worker-exit-thinking-5e7c2a91
  • Base commit: 274187e3cf
  • Owner: codex-root
  • Status: Completed

Scope

  • Fix the installed Windows Pi Conversation lifecycle so an accepted run whose matching worker generation exits or is protocol-invalidated converges within a bounded time to a recoverable terminal failure instead of remaining running or aborting.
  • Make abort-after-exit and crash/abort/agent_settled ordering monotonic on the target Conversation projection chain while preserving target isolation, the original session binding, and no replay of an uncertain prompt.
  • Add Main-only worker lifecycle forensics that distinguish unexpected exit, protocol invalidation, and intentional stop with a required finite reason, generation, stage, code/signal, and bounded redacted stderr.
  • Persist and display only the thinking level Pi actually supports and accepts, and derive managed custom-model reasoning compatibility from the authoritative capability data without implicitly replacing a worker generation.
  • Add focused, Host/SSE/Renderer, Windows Electron, and final packaged fault- injection regressions; build and verify a new Windows x64 NSIS installer.

Intent And Constraints

  • Keep the Pi hard cutover. Do not add an OpenCode fallback, compatibility layer, generic Provider watchdog, feature flag, or uncertain prompt replay.
  • Serialize crash, abort, and settled handling by Conversation + generation. A terminal run is monotonic; a stale generation cannot modify the active Conversation; one crash cannot affect another Conversation.
  • On crash/protocol invalidation, finally settle the target run and converge its queue permit, process lease, pending interaction, extension run, child worker, and project write lease. Normal live-worker abort continues to wait for authoritative agent_settled.
  • Thinking changes and same-account model changes must not restart a normally running worker. Provider/resource/credential revisions rebuild only after the accepted run settles, with an explicit generation-replacement reason.
  • Every Main-initiated stop must use a bounded reason enum covering application shutdown, idle eviction, stale-resource rebuild, recover, dispose, fork replacement, protocol invalidation, and test injection or their exact current implementation equivalents. Do not log prompt/response/tool/header/token, expose stderr to Renderer, or write credentials into diagnostics.
  • Preserve direct API-key, OAuth, local Provider, existing session persistence, fork/recover behavior, and the user's installed application under D:\Tools\泥土\niancode\Makelore.
  • Use pinned pnpm 10.33.4, frozen install semantics, focused/full verification, formal Windows packaging, final artifact/runtime closure checks, and isolated packaged product fault injection with zero residual proof processes.
  • Real external Provider verification remains Explicitly Waived / Accepted Risk with realTurnVerified=false; loopback/fault injection is not a real Provider Pass. macOS and native non-WSL Linux status is unchanged.

Project Context Loaded

  • Concurrent Task Gate passed in the isolated worktree owned by codex-root; task identity, branch, worktree, base, and task record match the registry.
  • Planning Gate passed after reading project entry/memory/current-state, architecture/domain/decision/evidence/reflection/commitment/stale records, the Pi hard-cutover runtime/ticket constraints, both cumulative Windows Pi hotfix records, the read-only stuck-processing diagnosis, and all active peer task scopes.
  • Base 274187e3cfe2ae6cb97f2b4bcb422b3fdf06fbf2 contains the earlier proxy-token and persisted-session reopen delivery. The diagnosis worktree is read-only; dirty main and all other task worktrees remain untouched.
  • Shared canonical architecture/current-state files predate the Pi delivery. The current source, Pi cutover contract, cumulative task records, and the accepted diagnostic evidence are authoritative for this repair.
  • The active peer tasks are older, unrelated, test-only, or read-only. The one main-worktree OpenCode integration task explicitly does not package; no unresolved semantic conflict changes this plan.
  • Eleven copied-session packaged loopback cases settled normally, so Provider SSE, session corruption, and task_state are not established causes. The incident trigger remains unknown until the replacement artifact records the bounded exit/stop classification.
  • No subagents are used, per user direction and repository policy.
  • The committed planning supplement 2d9d8274d77986fe96e88f02ccba2b5389d2e696 is a direct child of this task's base and identifies this executor task as PI-R001. Its RES-INV-001..009, RES-ACC-001..016, release blockers, Main-only privacy boundary, and final packaged fault-injection matrix are additional acceptance contracts for this implementation. The content first entered as the conflict-free cherry-pick 2b13454; the exact source commit 2d9d827 was then retained as a merge parent, so planning and implementation share one history without rewriting either line of work. At the executor tip the specification is materialized under the task-owned path 20260825-pi-worker-exit-thinking-5e7c2a91__pi-runtime-resilience-hardening.md; the planner task record remains available in the original commit history instead of violating feature-task document ownership.

Plan

  1. Inspect runtime, pool, process/RPC, extension/child/lease, model capability, Host/SSE, Renderer, E2E, and packaged proof seams; map all worker stop callers and generation-replacement reasons before changing contracts.
  2. Add focused red regressions for active accepted-run exit, abort-after-exit, exit/abort/settled ordering, target isolation and resource convergence; unexpected/protocol/intentional diagnostics and redaction; effective thinking persistence and no worker replacement.
  3. Implement the smallest lifecycle, diagnostics, and capability changes that satisfy the existing Pi contracts, retaining the original error category and session binding through recover.
  4. Extend Host SSE/Renderer unlock-and-recover and Windows packaged deterministic fault-injection proof for running exit, abort-after-exit, settled-before-close, strict JSONL invalidation, deliberate stop, isolation, no prompt replay, no unexplained generation replacement, and zero residual processes.
  5. Run frozen install, focused tests, typecheck, lint, full unit, build:vite, Windows Electron E2E, formal package:win, artifact/runtime/closure verification, and final packaged proofs from a clean committed candidate.
  6. Record exact commits, changed files, verification results, structured packaged evidence, installer size/SHA-256, accepted/deferred risks, clean git state, and complete the Task Documentation Gate.

Outcome

  • Implemented matching-generation worker crash/protocol terminalization on the per-Conversation projection chain. An accepted run now reaches recoverable error without overriding an earlier terminal agent_settled; abort after exit cannot restore running.
  • Generation invalidation now cancels command, interaction, child/dispatch, extension-run, process-permit, and write-lease resources for only the target Conversation. Recover reopens the same persisted Pi binding and never replays the uncertain accepted prompt.
  • Added finite, required Main stop/replacement reasons and separate structured lifecycle classification for unexpected exit, strict protocol invalidation, and intentional stop. PI_RPC_EXITED retains bounded stderr after token, header, credential, and managed-path redaction; prompt/response/tool content is not copied into lifecycle diagnostics or Renderer state.
  • Same-account model and thinking changes no longer replace the worker. Hydration and mutations query Pi capabilities/state and persist/project only the effective level. The managed deepseek-v4-pro profile now derives its reasoning, DeepSeek compatibility, context/output limits, and supported product thinking level from the imported authoritative capability profile; unsupported levels reject instead of presenting false success.
  • Renderer error state displays 本地 Agent 已中断,原请求未自动重发。, leaves the Composer editable, exposes recovery, and does not remain in processing/recovering. The packaged proof now drives the real final-ASAR Main composition through target exit, abort-after-exit, protocol invalidation, settled-before-close, target recovery, sibling isolation, child/write-lease cleanup, explicit deliberate stop, redacted lifecycle evidence, and clean process exit.
  • Concurrent packaged workers exposed a reachable Windows rename collision while materializing the same managed extension. Materialization is now single-flight per extensions directory; eight concurrent registrations share one atomic result without changing the extension contract.
  • Formal Windows package:win completed from the clean code candidate, including pinned Python/uv acquisition, Vite production build, Pi runtime bundling, and NSIS generation. The final product verifiers and the final-ASAR resilience proof pass. Real Provider verification is not claimed.

Verification

  • corepack pnpm install --frozen-lockfile — pass with pinned pnpm 10.33.4.
  • Focused Pi/runtime/pool/RPC/extension/subagent/UI regressions — pass, including 6 files / 60 tests for the lifecycle contract and 2 files / 9 tests after the extension materialization concurrency repair.
  • corepack pnpm run typecheck — pass.
  • corepack pnpm run lint:check — pass with 0 errors and 5 pre-existing warnings in unrelated Home/Makelore files.
  • corepack pnpm test — pass: 178 files / 1520 passed / 2 skipped, plus the isolated pressure file 1/1 passed.
  • corepack pnpm run build:vite — pass for Renderer, Main, Preload, and utility bundles; existing dynamic-import and chunk-size warnings remain non-blocking.
  • corepack pnpm run test:electron:windows — pass: 2 files / 4 tests.
  • corepack pnpm run package:win — pass from the clean 7aa9f79 product-code candidate. Two earlier attempts were blocked only by a transient GitHub uv 0.10.0 download timeout; the final formal command downloaded both x64/arm64 archives and completed without staging reuse.
  • corepack pnpm run verify:artifact:win — pass: final app.asar, Electron 43.4.0, Node 24.18.1, bundled Python/pip/sqlite/SSL, uv 0.10.0, npm 11.6.2, required native modules/assets, and NSIS validated. The pre-task-doc candidate installer was 211912226 bytes with SHA-256 54559D5ADEFAF84F3F124A535A811778E2A347E1B5247F43C0D5A31BBDFC6C0D; the post-documentation clean-HEAD artifact metadata is reported in the final handoff rather than being recursively embedded into the artifact-producing commit.
  • corepack pnpm run verify:artifact:pi — pass: Pi 0.84.2, final resources/pi-runtime/dist/cli.js, 130 production packages, 6 runtime assets, 5 native assets outside asar, managed Skills, and materialized extension/subagent closure all present and executable.
  • corepack pnpm run verify:publish-runtime — pass with npm 11.6.2.
  • corepack pnpm run test:pi-subagent:packaged — pass against the real final-ASAR Main composition. Target worker exit and strict protocol invalidation reached bounded recoverable terminal states; abort-after-exit did not restore running; settled-before-close stayed terminal; sibling Conversation kept running; recover reused the same binding and did not replay the uncertain prompt. Lifecycle classifications and all stop/replacement reasons were present and redacted, Renderer was unlocked with recovery available, all pool/subagent/extension/write-lease counters returned to zero, and no tracked Electron/Pi process lingered after exit. realTurnVerified=false.
  • The first final proof attempt selected the still-running isolation Conversation after reload, and the next locator matched both sidebar and header controls. The harness now selects the fault-target sidebar entry deterministically and emits Main/UI state on failure; no product assertion, timeout, or lifecycle contract was relaxed.

Follow-ups

  • Later soak and any new real-external-Provider occurrence may use the new bounded diagnostics to identify the initiating exit class. They are not substitutes for this task's required deterministic convergence proof.
  • Real Provider protocol/concurrency/credential-isolation verification remains explicitly waived accepted risk and must continue to report realTurnVerified=false.
  • PI-R002 loopback soak and field incident classification start only after PI-R001 is delivered. They do not block this repair or broaden its current implementation scope.

Promotion Candidates

  • None recorded.