Files
makelore/.project-docs/30-worklog/tasks/20260825-pi-background-run-lease-6a4e2c91.md

17 KiB

Task: Prevent background sleep from terminating active Pi runs

Identity

  • Task ID: 20260825-pi-background-run-lease-6a4e2c91
  • Mode: Feature
  • Branch: codex/20260825-pi-background-run-lease-6a4e2c91-pi-background-run-lease
  • Worktree: D:\Datas\OthersProjects\makelore-pi-background-run-lease-6a4e2c91
  • Base commit: 92f4c91088
  • Owner: codex-root
  • Status: Implementing follow-up

Scope

  • Follow up the installed 621ebb1 Windows artifact: treat an RPC confirmation timeout for an already-written Pi top-level mutation as uncertain ownership rather than a definite terminal failure. Keep the target run permit, process ownership, and Main background lease until a correlated late result/event, worker failure, abort, recover, or other authoritative cleanup converges it.

  • Prevent prompt, follow-up, steer, compact, model reconfiguration, and fork mutations from overlapping an unresolved uncertain mutation in the same Conversation, while preserving sibling Conversation independence.

  • Give manual compact a long-mutation lifecycle through compaction completion and authoritative settle, and keep CODING_REQUEST_UNCERTAIN distinct from local-runtime-unavailable UI semantics.

  • Add a Main-owned authoritative background lease for every queued or accepted top-level Pi Conversation run, acquired before mutation queueing and held through parent/child work until authoritative terminal cleanup.

  • Close the BackgroundLifecycleController.sleepIfIdle() in-flight race so a lease acquired while onSleep is awaiting prevents the later runtime stop, while preserving hidden-idle warm-worker eviction after all runs settle.

  • Terminalize supported intentional disposal of an active target Conversation before runtime projection state is removed, without replaying an accepted or uncertain mutation or affecting sibling Conversations.

  • Replace ambiguous Main stop reason dispose at supported callers with a bounded caller-specific reason, and retain content-free lifecycle evidence.

  • Extend focused Main/runtime/Renderer tests, Windows Electron E2E, final-ASAR packaged proof, and formal Windows NSIS/artifact verification.

Intent And Constraints

  • Preserve the Pi hard cutover and exact Pi 0.84.2; do not add OpenCode fallback, a Provider watchdog, automatic mutation replay, a global daemon, schema migration, feature flag, compatibility track, or Pi upgrade.
  • The authoritative lease is Main-owned. Renderer visibility or IPC lease delivery must not own run liveness. Acquire synchronously before a top-level mutation can be queued/accepted; a parent lease covers its child/subagent.
  • Release the lease exactly once only after authoritative settle, definite pre-accept rejection, terminal crash/protocol failure, completed cancel, explicit dispose cleanup, or application shutdown cleanup. Generation or resource replacement for the same logical run must not release it early.
  • Preserve target isolation, the existing same-session recover contract, and no-replay semantics. Intentional termination while the UI remains alive must project a recoverable terminal state; it must not fabricate success.
  • Keep stop reasons finite and content-free. Diagnostics may retain only safe lifecycle classification, reason, redacted identifiers, generation, code/signal, stage, and duration; no prompt/tool/header/token/session text or complete project path may enter logs or Renderer DTOs.
  • Do not edit the read-only diagnosis task or overwrite the user's installed Makelore. Do not push or publish. Real Provider remains Explicitly Waived / Accepted Risk (realTurnVerified=false); macOS/native Linux gates are out.

Project Context Loaded

  • Concurrent Task Gate passed with isolated ownership of this task, branch, and worktree at base 92f4c91088e79252aca76af3279b184da68e1eb7.
  • Diagnosis commit dc820b2 is a docs-only sibling based on 941b015, not an ancestor of the cumulative product HEAD; its task record was read-only and is not used as the implementation base.
  • Shared canonical memory remains OpenCode-stale relative to the cumulative Pi product. Current source, the Pi resilience contract, cumulative Pi task records, and the read-only output-stall diagnosis are authoritative here.
  • Eleven non-ready peer records were inspected. One owns an old main/OpenCode integration and the others are unrelated or placeholder scopes; no known peer owns Pi background lifecycle, runtime disposal, or packaged proof semantics. Placeholder scopes remain unknown coordination state but expose no semantic conflict that changes this isolated plan.
  • Relevant constraints are Main-owned run liveness, target-scoped monotonic terminalization, same-binding recovery, bounded stop reasons, no mutation replay, and final Windows packaged proof with zero residual resources.
  • Planning Gate result: Passed.

Plan

Follow-up plan from cumulative HEAD 621ebb17810394f6f7b97154cb01217bc9112857:

  1. Add deterministic red tests for delayed Pi prompt preflight confirmation, delayed compact confirmation, late failure/exit/abort convergence, same-Conversation mutation exclusion, sibling isolation, and Renderer uncertainty unlock.

  2. Make RPC confirmation timeout preserve authoritative uncertain ownership without replay, then converge exactly once from late response/events or explicit cleanup.

  3. Extend final-ASAR packaged proof beyond the old ten-second threshold and re-run the full Windows release gate from a clean follow-up commit.

  4. Trace actual background lifecycle, Pi mutation/dispose, composition, and stop-reason callers; build a deterministic combined red test for the exact hidden-active-run failure and the in-flight sleep race.

  5. Add the narrow Main-owned lease dependency, acquire before top-level queue/acceptance, and release exactly once across settle/reject/crash/ protocol/abort/dispose/shutdown paths.

  6. Reuse the existing Conversation projection chain to terminalize active intentional disposal before state removal, and pass caller-specific bounded reasons without changing settled runs or sibling Conversations.

  7. Extend Renderer/Host/Windows E2E and final packaged proof for hidden active completion, later idle stop, explicit-dispose unlock/recover/isolation, no replay, safe diagnostics, and zero resource/process residue.

  8. Run focused tests, typecheck, lint, full unit, build, Windows Electron E2E, then commit a clean candidate and run formal package:win, Windows/Pi closure verification, packaged proof, artifact fingerprinting, and the Task Documentation Gate.

Outcome

Installed-package P1 follow-up

  • Pi RPC mutation confirmation now has an explicit retained-correlation mode. Crossing the former 10-second Host confirmation threshold returns the safe recoverable CODING_REQUEST_UNCERTAIN contract but does not retire the RPC id or release the pool's active run, revision run, process permit, or Main background lease.

  • A late correlated success clears the provisional run error without ending the run; a late explicit RPC failure terminalizes only the target; worker invalidation, abort/recover cleanup, or authoritative agent_settled converge the same ownership exactly once. agent_settled also confirms a mutation when it arrives before the RPC success response, avoiding a hung Host acceptance promise or terminal-state regression.

  • Prompt, queued follow-up/steer, compact, model reconfiguration, and fork are blocked for the same Conversation while uncertainty is unresolved. The service performs model/fork rejection before metadata persistence or fork target creation; sibling Conversations retain independent permits.

  • Manual compact uses the same retained ownership through compaction_start, compaction_end, authoritative settlement, and hydrate. The final-ASAR proof now arms a controlled 12-second compact response and records its running/uncertain and completed/idle states.

  • Renderer submission errors retain their stable backend code. An uncertain submission keeps the draft and prevents overlap, shows the actionable delay message instead of a runtime-outage banner, and automatically removes the transient message when the authoritative run reaches a terminal state. Model, thinking, compact, and fork controls are disabled while the run is active; abort and recover remain available.

  • Implemented a Main-owned per-Conversation top-level run lease in the Pi runtime. Prompt and compact acquire before optimistic/queue acceptance; steer/follow-up reuse the parent run lease. Settle, definite rejection, crash, protocol invalidation, abort convergence, explicit recovery, intentional disposal, and shutdown release through an idempotent owner map.

  • Closed both background-stop races: the lifecycle controller rechecks visibility and leases after asynchronous sleep preparation, and the Pi pool rechecks the target's authoritative active-work predicate after pending prepare/rebuild work and immediately before worker cancellation.

  • Background sleep now refuses the entire coding-runtime sleep while any run is queued or active, while settled hidden workers remain eligible for normal eviction. A parent lease remains held while child/subagent resources finish.

  • Active intentional disposal projects the existing safe recoverable terminal failure on the target Conversation chain before cleanup/removal, preserves the durable session binding, does not replay the accepted prompt, and leaves sibling Conversations unchanged.

  • Replaced the ambiguous dispose worker stop reason with caller-owned finite reasons for background sleep, project deactivation/removal, Conversation deletion, auth cleanup, model reconfiguration, fork cleanup, app shutdown, and existing internal replacement/cleanup paths.

  • Extended the final-ASAR resilience proof to use the real Main composition for hidden active-run survival, settled idle eviction, intentional-dispose UI unlock/recover/isolation, safe lifecycle reason evidence, background lease counts, and zero residual resource/process verification.

  • The clean implementation candidate completed Windows NSIS creation, both artifact/closure verifiers, and the final packaged Main/UI/fault proof. The task record is amended into the cumulative delivery commit before the formal commands are rerun for the returned artifact.

Verification

Installed-package P1 follow-up candidate

  • Red phase — 5 expected failures across RPC correlation, pool ownership, Main background lease, compact overlap, and Renderer reconciliation: the old implementation retired the correlation and released active ownership at 10 seconds, returned a raw timeout, and retained the UI uncertainty after a completed run.

  • Focused green gate — passed: 8 files / 115 tests, including delayed prompt and compact, late success/failure, settled-before-response, same-target mutation exclusion with zero fork/model persistence, sibling isolation, safe Host error mapping, Renderer automatic unlock, and final-ASAR wiring.

  • pnpm run typecheck — passed after the final runtime/Renderer/proof changes.

  • pnpm run lint:check — passed with zero errors and the same 5 pre-existing warnings in src/pages/Home/index.tsx and src/pages/Makelore/index.tsx.

  • pnpm test — passed: 181 regular files / 1535 tests passed / 2 skipped, followed by the isolated pressure file / 1 test passed.

  • pnpm run build:vite — passed for Renderer, Main, Preload, and utility bundles; only existing dynamic-import and chunk-size warnings were emitted.

  • pnpm run test:electron:windows — passed: 2 files / 4 tests.

  • Final amended-HEAD NSIS, artifact closure, 12-second packaged UI/Main proof, Authenticode, and zero-residual-process results are completed after the task documentation/registry commit so the returned artifact binds to a clean cumulative HEAD.

  • The first candidate packaged proof intentionally required CODING_REQUEST_UNCERTAIN but the controlled Provider's message-shape matcher did not arm the delay; diagnostics showed both runs, both Main leases, both Pi processes, and both Provider requests still active with no runtime failure. The proof was corrected to arm prompt and compact delay explicitly through E2E-only Main seams, removing message-shape dependence; this was a proof-wiring failure, not a product fallback or relaxed gate.

  • The explicit Provider arm then proved the loopback HTTP response remained open for 12 seconds, but locked Pi acknowledged the local prompt RPC before the first Provider response on this controlled path. The proof therefore separates the two facts instead of claiming causality: the Provider response remains delayed for 12 seconds, and an E2E-only one-shot Pi RPC response hold independently crosses the 10-second client threshold. The hold is armed only through the existing Main fault-injection surface, is absent from Renderer and product configuration, and preserves the real packaged Pi command, session, Provider request, events, and cleanup path.

  • pnpm install --frozen-lockfile — passed with package-manager-pinned pnpm 10.33.4 and locked Pi 0.84.2.

  • Red phase: the new background lifecycle in-flight test observed one unwanted onStopRuntime call; the real Pi-runtime/lifecycle combination observed zero Main run leases after prompt acceptance.

  • Focused regression gate — passed: 8 files / 106 tests, covering lifecycle, running+queued Pi work, parent/child lease retention, exactly-once release, crash/protocol/abort/recover, forced disposal, worker reason diagnostics, project/auth callers, and packaged proof wiring.

  • pnpm run typecheck — passed.

  • pnpm run lint:check — passed with 5 pre-existing warnings and zero errors.

  • pnpm test — passed: 182 files, 1529 tests passed, 2 skipped.

  • pnpm run build:vite — passed for Renderer, Main, Preload, and utility bundles; only existing dynamic-import/chunk-size warnings were emitted.

  • pnpm run test:electron:windows — passed: 2 files / 4 tests.

  • Clean-candidate pnpm run package:win — passed; generated the Windows x64 NSIS without overwriting an installed Makelore directory.

  • pnpm run verify:artifact:win — passed for NSIS/unpacked Electron, app.asar, bundled Python/uv/npm, and Windows native modules; verifier HEAD matched the clean implementation candidate.

  • pnpm run verify:artifact:pi — passed: exact Pi 0.84.2, 130 production packages, 6 asset groups, zero missing/relocated package or asset, 5 native assets outside ASAR, managed Skills, and materialized extension/subagent.

  • pnpm run test:pi-subagent:packaged — passed from packaged app.asar Main: two UI/Main runs retained 2 background leases and 2 worker processes while hidden past grace; both settled, released leases, then warm idle workers stopped with reason background_sleep. Controlled intentional disposal projected CODING_RUNTIME_START_FAILED as recoverable, kept the sibling running and both bindings intact, and did not change Provider request counts. Recover reused the binding without mutation replay. Final workers, Pi processes, process leases, run permits, child permits/dispatches, extension registrations, write leases, and background leases all reached zero.

  • Packaged proof clean exit — passed with zero lingering tracked Electron/Pi PIDs. Lifecycle evidence distinguished unexpected exit, protocol invalidation, and intentional stop; every stop/replacement had a reason and redaction/content-free checks passed.

  • Authenticode inspection — NotSigned; no signing identity was available.

  • The returned installer is rebuilt and reverified from the amended cumulative clean HEAD; its exact path, size, SHA-256, and signing state are reported in the delivery response.

Follow-ups

  • PI-R002 soak/field attribution remains a separate follow-up and is not a blocker for this deterministic failure-convergence hotfix.
  • Real external Provider concurrency, credential isolation, and protocol compatibility remain Explicitly Waived / Accepted Risk with realTurnVerified=false; loopback/fault injection is not a Provider Pass.
  • macOS and native non-WSL Linux gate status is unchanged and not promoted.

Promotion Candidates

  • Target canonical document: Pi runtime architecture/resilience documentation. Proposal: record Main-owned top-level run leases, post-onSleep activity recheck, terminal-before-dispose monotonicity, and finite caller-owned stop reasons as accepted invariants. Evidence: focused lifecycle/runtime tests, Windows Electron E2E, final-ASAR hidden-run/idle-eviction/intentional-dispose proof, and zero-resource shutdown. Future impact: new Pi mutation or stop callers must join these seams rather than relying on Renderer visibility. Semantic conflicts: none known with the accepted Pi hard cutover/resilience plan. Human confirmation required: yes, during Integration Gate.