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

218 lines
13 KiB
Markdown

# 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: 274187e3cfe2ae6cb97f2b4bcb422b3fdf06fbf2
- 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.