pi-background-tasks 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -57,7 +57,8 @@ Current `package.json` exposes the docs-engine lane:
57
57
  ```bash
58
58
  npm run docs:generate
59
59
  npm run docs:verify
60
+ npm run docs:verify:attestations
60
61
  npm run docs:attest/record -- <doc_id> --reviewer <identity-after-semantic-review> --verdict PASS --notes <review-notes>
61
62
  ```
62
63
 
63
- `npm run docs:attest` is an alias for the attestation recorder and still requires a doc id, reviewer, verdict, and notes after semantic review. Do not self-award PASS. For docs-only maintenance under a constrained operator request, use the requested focused subset (frontmatter, package-local links, targeted source/doc grep) and report that full docs verification/attestation was not run.
64
+ `npm run docs:verify` treats semantic receipt freshness as advisory while preserving all deterministic docs, ownership, link, and payload checks. Use the optional `npm run docs:verify:attestations` gate when fresh independent receipts are required. `npm run docs:attest` is an alias for the recorder and still requires a reviewed doc id, reviewer, verdict, and notes; do not self-award PASS.
package/README.md CHANGED
@@ -26,7 +26,7 @@
26
26
  | Fact | Value |
27
27
  | --- | --- |
28
28
  | Package | `pi-background-tasks` |
29
- | Version | `1.0.4` |
29
+ | Version | `1.0.6` |
30
30
  | Node engine | `>=22.19.0` |
31
31
  | Pi entrypoint | `./extensions/background-tasks.ts` |
32
32
  | Package image | [logo.png](https://raw.githubusercontent.com/ismailsaleekh/pi-background-tasks/main/logo.png) |
@@ -291,6 +291,7 @@ Agent tasks launched through `pi -p ...` or `pi --mode json ...` and marked `isA
291
291
  - Shell jobs are tracked by the package, but they are not sandboxed. Treat commands as local processes with your permissions and credentials.
292
292
  - Delegate and Fusion child Pi processes are route-pinned where applicable; delegate/Fusion paths do not silently substitute routes.
293
293
  - Fusion uses direct child `pi --mode text` processes, not direct completion APIs. Frontier Fusion routes are admitted only through Pi Anthropic or Codex subscription OAuth; metered frontier API credentials are rejected before child creation.
294
+ - Claude Fusion children default Pi-selected prompt-cache breakpoints to one-hour retention. Set `PI_CACHE_RETENTION=short|none|long` to choose explicitly; malformed policy or cache evidence fails before transport.
294
295
  - Fusion research fetches only caller-supplied public `http(s)` URLs with bounded retrieval. It is not web search and not a secret-exfiltration boundary.
295
296
  - Attestation sidecars are local, unsigned, same-user-writable evidence. They are useful for downstream local gates, but not cryptographic proof against local compromise, a compromised Pi binary, or a compromised provider.
296
297
  - Metadata, attestations, delegate/Fusion artifacts, and configuration replacements use write/fsync/rename durability patterns. Ordinary task output is closed and drained before terminal publication but is not explicitly fsynced. POSIX directory entries are fsynced after atomic replacement; Windows lacks the same portable directory-entry crash-durability guarantee.
package/TESTING.md CHANGED
@@ -158,7 +158,7 @@ Smoke proves loadability only; completion requires `npm run test`, `npm run test
158
158
 
159
159
  ### Docs/gateway focused checks
160
160
 
161
- Current package docs gates are `npm run docs:generate`, `npm run docs:verify`, and `npm run docs:attest/record -- <doc_id> --reviewer <identity-after-semantic-review> --verdict PASS --notes <review-notes>`. For docs-only changes under constrained operator instructions, run only the requested focused subset (for example frontmatter, package-local links, absence of standalone parent `../EXTENSION_*` links, and version/tag wording derived from `package.json`/observed git tags) and report when full docs verification/attestation was not run.
161
+ Current package docs gates are `npm run docs:generate` and `npm run docs:verify`; semantic receipt freshness is advisory there. Use `npm run docs:verify:attestations` only when a release or operator explicitly requires fresh independent receipts, and record them with `npm run docs:attest/record -- <doc_id> --reviewer <identity-after-semantic-review> --verdict PASS --notes <review-notes>`.
162
162
 
163
163
  ## Required isolated environment
164
164
 
@@ -186,7 +186,7 @@ npm run test:rpc
186
186
  npm run test:agent-loop
187
187
  ```
188
188
 
189
- The Fusion SDK/RPC/scripted-provider tests install a deterministic fake child `pi` in a temp `PATH` from `tests/helpers/fusion-fake-pi.ts`. Parent Pi remains the real SDK/RPC runtime; only direct child `pi --mode text` calls with the package-owned private compact metadata extension are intercepted. `PI_CODING_AGENT_DIR` is pointed at the temp agent directory so `fusion-models.json` is never read from the user's real global Pi directory. Fusion v1 public-surface coverage asserts exactly four tools (`fusion_reason`, `fusion_investigate`, `fusion_research`, `fusion_validate`), no public capability argument, retired-tool active-tool removal, `/fusion` mapping to reason/no-tool candidates, closed schemas with Google-compatible enum status, targeted URL fetch not search, URL exfiltration warnings, strict validation verification rules, historical v4 rendering without old-tool activation, and actionable migration errors for `fusion_validate({prompt})`. Fusion context coverage covers both reason conversation projection and clean-task non-interference invariants, including parent-sentinel absence from every clean downstream prompt/artifact and byte-identical clean inputs across unrelated parent sessions. `tests/unit/fusion-context-prompts.test.ts` verifies that a synthetic session carrying more than 1 MB of tool arguments/results still yields a small canonical input, that user and assistant text survive verbatim, that thinking and tool payloads never appear (including no head/tail/preview sentinel), that omission counts, byte totals, and hashes are exact and stable, that repeated construction is byte-identical, that the active Fusion tool leaf and sibling calls stay scope-excluded, that images remain marker-only or ledger-only with no raw base64 in child prompts, and that every retained source block receives exactly one disposition. `tests/unit/fusion-high-cardinality.test.ts` covers the receipt-cardinality regression: a session of many short interleaved tool events (rather than a few enormous results) pins per-receipt cost, proves the compact `omitted_activity` fields are the only model-facing ones, reconciles every receipt against the ledger through `projection_map`, and proves the whole workflow fits a real route budget. `tests/unit/fusion-budget.test.ts` covers stage budgets: the limiting model is the smallest configured route (including when it is the evaluator rather than a candidate), unknown or too-small capacities fail before spawn, boundary prompts pass at exactly the limit and fail one byte past it, the child system prompt counts as input, dense multi-byte UTF-8 cannot bypass byte accounting, and candidate, evaluator, evaluation-repair, and merger expansions are each rejected before their child is spawned with zero partial launches. `tests/package/typebox-compat.test.ts` pins the TypeBox posture and compiles nullable-array schemas. The release-only `npm run test:compat` packs the package, installs exact supported Pi versions, runs `/jobs`, runs `/fusion` through the installed package entrypoint with the fake child Pi, verifies five child invocations, verifies `/fusion-models` rejects non-TUI mode, requires each supported Pi line to declare terminal `agent_settled`, asserts the resolved `typebox` is Pi's bundled peer rather than a private or nested copy, and scans the installed package bytes for TypeBox APIs removed in the 1.3.x line. Pi 0.75.5 is intentionally unsupported because it lacks the terminal event required to seal a Fusion audit after retries and compaction. It then drives the current host Pi through a real RPC `fusion_reason` parent-agent loop, checks the persisted tool result carries the complete Pi `Usage.cost` object, invokes `get_session_stats` (the same aggregation boundary used by the TUI footer), reopens the durable session, and verifies identical token/cost totals. All parent and child inference remains deterministic and local.
189
+ The Fusion SDK/RPC/scripted-provider tests install a deterministic fake child `pi` in a temp `PATH` from `tests/helpers/fusion-fake-pi.ts`. Parent Pi remains the real SDK/RPC runtime; only direct child `pi --mode text` calls with the package-owned private compact metadata extension are intercepted. `PI_CODING_AGENT_DIR` is pointed at the temp agent directory so `fusion-models.json` is never read from the user's real global Pi directory. Fusion v1 public-surface coverage asserts exactly four tools (`fusion_reason`, `fusion_investigate`, `fusion_research`, `fusion_validate`), no public capability argument, retired-tool active-tool removal, `/fusion` mapping to reason/no-tool candidates, closed schemas with Google-compatible enum status, targeted URL fetch not search, URL exfiltration warnings, strict validation verification rules, historical v4 rendering without old-tool activation, and actionable migration errors for `fusion_validate({prompt})`. Fusion context coverage covers both reason conversation projection and clean-task non-interference invariants, including parent-sentinel absence from every clean downstream prompt/artifact and byte-identical clean inputs across unrelated parent sessions. `tests/unit/fusion-context-prompts.test.ts` verifies that a synthetic session carrying more than 1 MB of tool arguments/results still yields a small canonical input, that user and assistant text survive verbatim, that thinking and tool payloads never appear (including no head/tail/preview sentinel), that omission counts, byte totals, and hashes are exact and stable, that repeated construction is byte-identical, that the active Fusion tool leaf and sibling calls stay scope-excluded, that images remain marker-only or ledger-only with no raw base64 in child prompts, and that every retained source block receives exactly one disposition. `tests/unit/fusion-high-cardinality.test.ts` covers the receipt-cardinality regression: a session of many short interleaved tool events (rather than a few enormous results) pins per-receipt cost, proves the compact `omitted_activity` fields are the only model-facing ones, reconciles every receipt against the ledger through `projection_map`, and proves the whole workflow fits a real route budget. `tests/unit/fusion-budget.test.ts` covers stage budgets: each route reserves the larger of Fusion's output contract and the model's declared maximum output, the limiting model is selected by conservative byte capacity (including when it is the evaluator rather than a candidate), unknown or too-small capacities fail before spawn, boundary prompts pass at exactly the limit and fail one byte past it, the child system prompt counts as input, dense multi-byte UTF-8 cannot bypass byte accounting, and candidate, evaluator, evaluation-repair, and merger expansions are each rejected before their child is spawned with zero partial launches. `tests/unit/fusion-pi-child.test.ts` covers the post-launch `fusion-runtime-guard.v1` protocol, exact final-payload measurement, 128-request/192-tool limits, malformed or duplicate evidence rejection, typed parent errors, and failed audit sealing. `tests/unit/fusion-claude-cache.test.ts` pins default one-hour Claude retention, explicit short/none/long policy, model compatibility fallback, non-mutation, no-marker compaction preservation, the four-breakpoint ceiling, and malformed-control refusal, and distinct `child_cache_policy_invalid` parent errors. Child metadata binds each requested/effective cache observation in `fusion-child-result.v3`. Terminal `fusion-child-settlement.v2` is published only at `agent_settled`; recovered non-final provider errors must be zero-content/zero-usage retry markers named by that settlement, and missing/duplicate/tampered/failed settlements or substantive error records remain fatal. `tests/scripted-provider/fusion-runtime-guard.test.ts` drives a real Pi agent loop through Pi's `openai-codex-responses` adapter against local HTTP and proves provider-payload transforms chain in load order and the governor's `ctx.abort()` prevents network transport. `tests/package/typebox-compat.test.ts` pins the TypeBox posture and compiles nullable-array schemas. The release-only `npm run test:compat` packs the package, installs exact supported Pi versions, runs `/jobs`, runs `/fusion` through the installed package entrypoint with the fake child Pi, verifies five child invocations, verifies `/fusion-models` rejects non-TUI mode, requires each supported Pi line to declare terminal `agent_settled` and `before_provider_request`, verifies the installed Anthropic adapter exposes cache breakpoints plus long/tool compatibility controls, asserts the resolved `typebox` is Pi's bundled peer rather than a private or nested copy, and scans the installed package bytes for TypeBox APIs removed in the 1.3.x line. Pi 0.75.5 is intentionally unsupported because it lacks the terminal event required to seal a Fusion audit after retries and compaction. It then drives the current host Pi through a real RPC `fusion_reason` parent-agent loop, checks the persisted tool result carries the complete Pi `Usage.cost` object, invokes `get_session_stats` (the same aggregation boundary used by the TUI footer), reopens the durable session, and verifies identical token/cost totals. All parent and child inference remains deterministic and local.
190
190
 
191
191
  ## Coverage summary
192
192
 
package/TEST_PLAN.md CHANGED
@@ -40,8 +40,8 @@ The table below remains the exhaustive acceptance source. Do not replace it with
40
40
  | Smoke | `npm run smoke` | no | implemented; isolated load-only |
41
41
  | Large-context smoke | `npm run smoke:large-context` | release gate | implemented; rebuilds the production failure byte composition, proves the pre-fix input is rejected and the post-fix projection fits all four stages against the smallest configured route, with no inference and no child spawn |
42
42
  | Live subscription evidence | `npx tsx scripts/delegate-live-run.ts` | release gate | implemented; one real subscription-OAuth child on the parent's current route, large seeded session, hash-verified answer, and explicit leak checks. Caught two defects no offline gate did (undelivered prompt, seed-not-prompt budgeting), both now pinned by unit and mutation tests |
43
- | Compatibility | `npm run test:compat` | release gate | implemented; exact Pi `0.81.1`, `0.82.1`, `0.83.0` pack/install plus `/jobs`, `/fusion`, and `/fusion-models` surfaces, per-version `agent_settled` event declaration and bundled-TypeBox peer verification, removed-TypeBox-API scan of installed package bytes, followed by a current-host real `fusion_reason` session-stat and replay witness |
44
- | Docs verification | `npm run docs:verify` | prepack/release gate | implemented; offline docs freshness, generated region/index/manifest/link/reachability/coverage/attestation checks |
43
+ | Compatibility | `npm run test:compat` | release gate | implemented; exact Pi `0.81.1`, `0.82.1`, `0.83.0` pack/install plus `/jobs`, `/fusion`, and `/fusion-models` surfaces, per-version `agent_settled`/`before_provider_request` declarations, Anthropic cache-adapter contracts, and bundled-TypeBox peer verification, removed-TypeBox-API scan of installed package bytes, followed by a current-host real `fusion_reason` session-stat and replay witness |
44
+ | Docs verification | `npm run docs:verify` | prepack/release gate | implemented; offline docs freshness, generated region/index/manifest/link/reachability/coverage checks with advisory attestation state; optional `docs:verify:attestations` enforces fresh receipts |
45
45
  | Docs tests | `npm run test:docs` | targeted docs gate | implemented; docs-gate unit/package tests |
46
46
  | Payload policy | `npm run payload:check` | prepack/release gate | implemented; package payload/docs/assets exclusions and inclusions |
47
47
  | Release version sanity | `npm run release:check-version` | release gate | implemented; package version/tag sanity without advertising nonexistent tags |
@@ -76,17 +76,18 @@ SDK/RPC/scripted-provider/package/compatibility coverage asserts exactly four to
76
76
  | Stop task from LLM tool | `bg_kill` | | yes | | | | | | Covers running kill and already-finished loud failure. |
77
77
  | Fusion command direct result | `/fusion`, `fusion-result` custom message | yes | yes | yes | | yes | yes | | Core unit covers deterministic v2 conversation-projection construction, explicit image omission markers without raw image data, direct final-text child argv/stdin/compact-metadata parsing, exact multi-block answer reconstruction, artifacts, pre-abort handling, and orchestration. SDK runs real `/fusion` against a fake child `pi`, verifies exactly five child text-mode invocations, hidden prompt persistence, visible exact merged custom message, no parent assistant rewrite, renderer output, progress/status behavior, no-argument editor flow, editor cancellation, and malformed config causing zero children. RPC verifies command discovery, `/fusion <prompt>` with U+2028/U+2029 content, custom-message result emission, no parent `agent_start`, no-argument editor protocol, malformed config/child failure visibility, and child isolation flags. PTY verifies `/fusion` renders the exact merged answer directly in a real TUI. Compatibility smoke runs `/fusion` through every supported Pi version with the installed package entrypoint. |
78
78
  | Fusion v1 tool result | `fusion_reason`, `fusion_investigate`, `fusion_research`, `fusion_validate` | yes | yes | | | current-host stats/replay | yes | yes | Exactly four tools are registered/activated; `fusion_brainstorm` is removed from active tools. No public `capability` exists. BUG-182 coverage pins the exact host `Usage` contract, complete cost-component aggregation, v4 result rendering, exact merged text, progress, context exclusion, and final details. The compatibility gate drives a real current-host RPC agent through `fusion_reason`, verifies persisted tool usage, invokes the same session-stat path used by the footer, then reopens the durable session and verifies identical stats. |
79
- | Fusion Anthropic child sanitization | `@ravshansbox/pi-anthropic-sps` dependency, child `--extension` argv | yes | | | | | yes | | Unit proves a Claude route receives exactly two `--extension` paths with the metadata extension first and the sanitizer second, that every non-Anthropic provider still receives exactly one and never resolves the sanitizer at all, and that the real installed package resolves to an existing file through its manifest `pi.extensions[0]`. Resolution failures are each pinned as loud errors: package unresolvable, manifest unreadable, manifest not JSON, missing `pi` section, empty `pi.extensions`, blank entry, and a declared file that does not exist. Package guards require the sanitizer to be a declared dependency and require the provider gate so non-Anthropic child argv cannot drift. |
79
+ | Fusion Anthropic child sanitization | `@ravshansbox/pi-anthropic-sps` dependency, child `--extension` argv | yes | | | | | yes | | Unit proves a Claude route receives exactly two `--extension` paths with the sanitizer first and the package runtime governor/metadata extension second, so final provider-payload measurement occurs after sanitization; every non-Anthropic provider still receives exactly one and never resolves the sanitizer at all, and that the real installed package resolves to an existing file through its manifest `pi.extensions[0]`. Resolution failures are each pinned as loud errors: package unresolvable, manifest unreadable, manifest not JSON, missing `pi` section, empty `pi.extensions`, blank entry, and a declared file that does not exist. Package guards require the sanitizer to be a declared dependency and require the provider gate so non-Anthropic child argv cannot drift. |
80
80
  | Fusion validation workflow | structured `fusion_validate`, workflow profiles, `fusion-manifest.v4`, `fusion-result.v5` | yes | yes | | | | yes | | Public validation rejects legacy `{prompt}` with a migration error, enforces non-empty `scope`/`acceptanceCriteria`, and loudly validates `verification` cross-fields (`provided` ↔ evidence, `not_run` ↔ reason). Core validate orchestration is clean/read-only/advisory, enforces source-finding accounting including singleton, duplicate, exclusion, and merger add/drop cases, and remains no build/test substitute claim. |
81
81
  | Fusion context boundaries | canonical input `fusion-input.v5`, reason `context-omission-ledger.json`, clean-task inputs | yes | yes | yes | | | yes | | Unit covers reason/session projection for a >1 MB synthetic tool-heavy session, verbatim user/assistant text, thinking exclusion, zero tool-payload preview bytes, exact and stable omission counts/byte totals/hashes, compact tuple round-trip, receipt-to-ledger reconciliation, active-tool-call-leaf and sibling-call exclusion, and byte-identical repeated construction. Clean-task tests assert investigate/research/validate inputs omit parent system prompt, conversation projection, and omission ledger, stay byte-identical across unrelated parent sessions, and keep parent sentinels out of every clean downstream prompt and artifact. SDK/RPC verify clean validate stdin has no `conversation_projection` or transcript while `/fusion`/reason preserve the projected-conversation path. |
82
- | Fusion stage budgets | `budget-plan.json` (v3 per-stage forecasts), typed `prompt_budget_exceeded_forecast` / `prompt_budget_exceeded_measured` | yes | | | | | | | Unit covers the per-family affine estimator, additive segment accounting, multibyte 1.0-token/byte charging, unknown-provider floor visibility, byte-capacity route selection, scope guards for small windows, input-only fatal preflight versus warning-only reservations, rejection of unknown/zero/negative/too-small context windows, boundary accept at exactly the limit and reject one byte past, the child system prompt counted as input, per-stage forecasts built from the real prompt builders against each stage's own route, reservation warnings, breach-detector artifacts, safe prompts completing all five calls, persisted route/plan snapshots including negative slack on fatal rejection, and the reproduced 1 MB failure shape now fitting the smallest configured budget. Errors carry stage, measured size, allowed size, limiting model, estimator source, and remediation in both structured detail and message text. |
82
+ | Fusion stage budgets | `budget-plan.json` (v4 per-stage forecasts), typed `prompt_budget_exceeded_forecast` / `prompt_budget_exceeded_measured` | yes | | | | | | | Unit covers the per-family affine estimator, additive segment accounting, multibyte 1.0-token/byte charging, unknown-provider floor visibility, per-route reservation of `max(Fusion output contract, model maximum output)`, byte-capacity route selection, scope guards for small windows, input-only fatal preflight versus warning-only reservations, rejection of unknown/zero/negative/too-small context windows, boundary accept at exactly the limit and reject one byte past, the child system prompt counted as input, per-stage forecasts built from the real prompt builders against each stage's own route, reservation warnings, breach-detector artifacts, safe prompts completing all five calls, persisted route/plan snapshots including negative slack on fatal rejection, and the reproduced 1 MB failure shape now fitting the smallest configured budget. Errors carry stage, measured size, allowed size, limiting model, estimator source, and remediation in both structured detail and message text. |
83
83
  | Fusion fixed-purpose profiles | `/fusion`, `fusion_reason`, `fusion_investigate`, `fusion_research`, `fusion_validate`, candidate child argv | yes | yes | yes | | | yes | | Public surface has no caller-selected capability. SDK/RPC pin `/fusion` to reason/no-tool candidates; investigate is read-only, research is targeted URL fetch with public http(s) source validation, and evaluator/merger remain no-tools by stage policy. Package guards reject extra keys and verify schemas are closed. |
84
84
  | Fusion research web fetch | `fusion_web_fetch({ url, extract? })`, `candidate-<slot>.attempt-<n>.tool-calls.jsonl` | yes | | | | | yes | live child | Unit covers the closed schema surface through the child extension, registration only when research mode is enabled, unsupported schemes and URL credentials failing before network access, blocked DNS classes, a mixed public-plus-blocked DNS answer failing loudly, a redirect to a blocked address failing loudly, redirect-loop limit failure, Content-Length and streamed-body response caps, unsupported content types, Markdown extraction preserving links/headings/tables/code blocks, script/style stripping, text/plain passthrough with hash and byte count, UTF-8-safe output truncation, and typed timeout. Unit also proves the resolver is consulted once and the connection is pinned to that vetted address, undeclared research URLs are rejected before fetch with only the attempted URL hash audited, and that audit metadata records `url`, `final_url`, `http_status`, `response_bytes`, and `content_sha256` without raw page content. Package guards require `fusion_web_fetch` registration behind the research env flag. Live verification fetched `https://example.com/`, reported the page H1, read a repository constant, and refused instruction-like text from both a repo file and the fetched page. |
85
- | Fusion multi-message transcript validation | `*.events.jsonl`, stop reasons `toolUse`/`stop` | yes | | | | | | | Unit accepts a multi-message tool loop, reconstructs stdout from the final assistant message only, and sums usage across all compact metadata records. Non-final records must be `toolUse`, the final record must be `stop`, and `length`, `error`, `aborted`, and `pending` fail loudly instead of being skipped. |
85
+ | Fusion multi-message transcript validation | `*.events.jsonl`, `fusion-child-settlement.v2`, stop reasons `toolUse`/`stop` plus recovered retry markers | yes | | | | | | | Unit accepts a multi-message tool loop, validates increasing cache-observation request ordinals, reconstructs stdout from the final assistant message only, and sums usage across all compact metadata records. Terminal `agent_settled` emits exactly one settlement binding ordered record bytes/count/final hash. Non-final `toolUse` remains normal; non-final `error` is accepted only when it has zero content and usage, is followed by final `stop`, and its ordinal is hash-bound in the settlement. Final/non-zero errors, `length`, `aborted`, `pending`, missing/duplicate/tampered/failed settlements, and pre-settlement shutdown fail loudly. |
86
+ | Fusion runtime context governor | `pi-background-tasks.fusion-runtime-guard.v1`, typed `child_runtime_budget_exceeded` | yes | | | | | | scripted provider | Unit proves every exact final provider payload is serialized, hashed, and conservatively estimated against `contextWindow - max(32,768, model.maxTokens) - 4,096`; request 128/tool call 192 are allowed and the next is refused; malformed/duplicate frames and clean-looking post-refusal output fail closed; parent errors preserve observed usage. A real local-HTTP Pi loop through the production `openai-codex-responses` adapter proves earlier payload transforms reach the later governor and `ctx.abort()` prevents network transport. |
86
87
  | Fusion stale-action watchdog | `FUSION_CHILD_IDLE_TIMEOUT_MS`, child process lifecycle | yes | | | | | | | Unit proves a child with no stdout or stderr activity fails as `child_timeout` with the stalled-child message and is terminated; stderr activity resets the watchdog and allows success; the 30-minute absolute timeout path remains distinct and is not reported as a stalled child. |
87
- | Fusion candidate tool-call audit log | `candidate-<slot>.attempt-<n>.tool-calls.jsonl`, `*.seal.json`, `pi-background-tasks.fusion-tool-call.v1` | yes | | | | | | | Unit proves completed tool calls are logged with tool name, byte counts, and hashes while raw arguments/results containing a secret never appear. Repeated low-level `agent_end` boundaries publish no seal; terminal `agent_settled` exclusively seals the complete log after all retry/compaction/follow-up work. The 46-call incident regression proves a 22-call prefix is never sealed and duplicate settlement fails without replacement. Shutdown before settlement writes failed evidence and latches process failure. The parent rejects extension diagnostics and missing/failed/mismatched seals and independently rejects aggregate result bytes above 8 MiB. A trailing partial line, ordinal gap, duplicate ordinal, wrong schema version, and inspect-child partial log all fail loudly. |
88
+ | Fusion candidate tool-call audit log | `candidate-<slot>.attempt-<n>.tool-calls.jsonl`, `*.seal.json`, `pi-background-tasks.fusion-tool-call.v1` | yes | | | | | | | Unit proves completed tool calls are logged with tool name, byte counts, and hashes while raw arguments/results containing a secret never appear. Children are independently bounded to 192 attempted tool calls and 8 MiB aggregate tool-result bytes; a limit refusal emits structured evidence, aborts, and cannot publish a complete seal. Repeated low-level `agent_end` boundaries publish no seal; terminal `agent_settled` exclusively seals the complete log after all retry/compaction/follow-up work. The 46-call incident regression proves a 22-call prefix is never sealed and duplicate settlement fails without replacement. Shutdown before settlement writes failed evidence and latches process failure. The parent rejects extension diagnostics and missing/failed/mismatched seals and independently rejects aggregate result bytes above 8 MiB. A trailing partial line, ordinal gap, duplicate ordinal, wrong schema version, and inspect-child partial log all fail loudly. |
88
89
  | Pi/TypeBox compatibility | `peerDependencies`, packed bytes | yes | | | | | yes | | Unit pins typebox as a `"*"` peer that is neither a runtime nor bundled dependency, requires the resolved TypeBox to be Pi 0.83's 1.3.x line, requires all four supported Pi/TUI lines in the peer range, scans all package TypeScript for the seven removed TypeBox APIs, and compiles the shipped tool schema plus nullable-array/nullable-string and optional-field shapes under TypeBox 1.3. The release compat gate repeats the removed-API scan against installed package bytes per Pi version. |
89
- | Pi hook contract | `npm run test:hook-contract`, `tests/scripted-provider/pi-hook-contract-evidence.json`, `src/core/delegate/hook-contract-evidence.json` | | | | | | evidence parity | yes | Executes a real Pi agent loop and records, rather than assumes: `context` fires once before every model call in load order; returned messages reach the provider; **throwing** in `context` does NOT block dispatch (Pi catches and continues); `ctx.abort()` does not skip the call site but delivers an already-aborted signal and terminates the run; `tool_result` fires before the transcript entry, chains in load order, replacement reaches the provider while the original does not, and toolCallId/role/`isError` survive. Handler ordering across two separate probe extensions is pinned. The evidence file is compared, never silently regenerated, and a package test asserts the shipped copy is byte-identical. |
90
+ | Pi hook contract | `npm run test:hook-contract`, `tests/scripted-provider/pi-hook-contract-evidence.json`, `src/core/delegate/hook-contract-evidence.json` | | | | | | evidence parity | yes | Executes real Pi agent loops and records, rather than assumes: Fusion `before_provider_request` transformations chain in extension load order through the Codex transport adapter and abort before local HTTP transport; Delegate `context` fires once before every model call in load order; returned messages reach the provider; **throwing** in `context` does NOT block dispatch (Pi catches and continues); `ctx.abort()` does not skip the call site but delivers an already-aborted signal and terminates the run; `tool_result` fires before the transcript entry, chains in load order, replacement reaches the provider while the original does not, and toolCallId/role/`isError` survive. Handler ordering across two separate probe extensions is pinned. The evidence file is compared, never silently regenerated, and a package test asserts the shipped copy is byte-identical. |
90
91
  | Delegate context seeding | `bg_delegate` seed `pi-background-tasks.delegate-seed.v1`, `seed.json`, `context-omission-ledger.json` | yes | yes | | | | mutation guard | yes | Unit covers verbatim visible user/assistant text, complete exclusion of thinking/tool-call arguments/tool-result payloads, marker-only images with no raw bytes anywhere in the seed, exclusion of the in-flight `bg_delegate` call **and every sibling call in the same assistant message** (two delegates launched together get byte-identical projected history), the prompt preserved exactly and marked `explicit_text` authority, zero payload-preview bytes, byte-identical construction across repeated builds and across separate processes via a fixed-leaf fixture, and refusal of a blank prompt. Receive-side verification rejects a single mutated byte, a foreign task identity, a structurally malformed seed whose hash matches, a directive whose hash disagrees with its text, and an unsupported capability. SDK proves the projected parent text actually reaches the child. |
91
92
  | Delegate route pinning | `bg_delegate` `route`, `route_attestations` | yes | yes | | | | mutation guard | yes | Unit covers defaulting to the parent current model, explicit pinning, refusal of an unavailable route with `route_unresolved` and no substitution, refusal of a route with no declared context window with `route_capacity_unknown` rather than assuming one, and refusal when neither is available. The result package rejects a mismatched route, a mismatched attestation, and a package carrying no attestation at all. The scripted-provider gate proves an observed route drift prevents a success commit entirely. The mutation guard fails if a fallback list or first-available selection appears. |
92
93
  | Delegate budget and guard | `budget-plan.json`, typed `seed_budget_exceeded` / `provider_context_budget_exhausted` | yes | yes | | | | mutation guard | yes | Unit covers reserve subtraction, exact-boundary accept and one-byte-past reject, the child system prompt counted as input, multi-byte UTF-8 measured by bytes, refusal of unusable windows without defaulting, and a total runtime governor that cannot throw from inside a hook. Preflight rejection is proven to create **zero** children and **zero** artifacts for hook-contract, budget, and blank-prompt refusals, with the artifact directory verified absent. The scripted-provider gate proves an over-budget model call is blocked in a real agent loop and produces a typed terminal record with no committed result. |
@@ -95,7 +96,7 @@ SDK/RPC/scripted-provider/package/compatibility coverage asserts exactly four to
95
96
  | Delegate isolation boundary | child argv, `--session-id`, `--session-dir`, `--tools` | yes | yes | | | | mutation guard | yes | Unit proves the child receives its own session id and a task-owned session directory, no `--continue`/`--resume`/`--session`/`--fork`, only the inspect tool set, an explicit denylist covering `bash`/`edit`/`write`/`bg_delegate` and all current/retired Fusion tools, disabled discovery of extensions/skills/prompt templates/themes/context files, exactly one explicitly loaded package guard extension, explicit provider/model with no `--api-key`, and parent session identity stripped from the child environment. SDK verifies the same facts from the argv and environment the child actually observed. |
96
97
  | Fusion artifact byte immutability | `canonical-input.json`, `context-omission-ledger.json`, `budget-plan.json` | yes | | | | | shared-source guard | | A 28-case differential corpus is rendered to raw bytes and compared against a committed golden file that is never auto-updated once present, and separately against `tests/oracle/fusion-context-pre-extraction.ts`, a verbatim pre-extraction copy of the projection engine used as an **independent oracle**. Equivalence covers canonical input, ledger, and budget-plan bytes, `Object.is` comparison of budget floats including `utilization`, field-for-field accounting parity, ledger root hashes, and identical error type and message for unknown blocks and blank requests. The package guard now scans the shared `context/` modules, not only the Fusion facade, and pins both the shared divisor definition and Fusion's binding to it. |
97
98
  | Fusion model selector | `/fusion-models`, `fusion-models.json`, `FusionModelSelector` | yes | yes | yes | yes | yes | yes | | Unit covers strict config parsing, duplicates, slash-containing model IDs, stale model failures, `$current`, atomic save, inter-process lock/revision compare-and-swap, and deterministic concurrent-save conflict. Component covers all five slots, duplicate selection, searchable model list, stale display, reset/save/cancel, persistence errors, and width safety. SDK drives the real command in a synthetic TUI context without `ctx.mode` to cover old Pi compatibility and verifies duplicate `$current`/explicit model persistence; SDK also verifies headless no-UI rejection. RPC verifies non-TUI notification without hanging, PTY verifies the real selector opens in a TUI, and compatibility smoke verifies print-mode rejection for every supported Pi version. |
98
- | Fusion child isolation/lifecycle | child `pi --mode text`, private compact metadata extension, shutdown cleanup, `.pi/fusion` artifacts | yes | yes | yes | | current-host stats/replay | yes | | BUG-180 coverage proves final-text transport, reasoning exclusion, strict response reconstruction, unchanged caps, isolation, process cleanup, failure artifacts, and lifecycle semantics. BUG-182 upgrades the private compact metadata and artifact manifest to v2, preserves all token and cost components, centralizes clone/add/empty operations, rejects missing/legacy/unknown/non-finite cost shapes, and proves successful plus failed/cancelled attempt costs aggregate exactly once. SDK/RPC verify public child isolation; session shutdown tracks initializing and live runs. |
99
+ | Fusion child isolation/lifecycle | child `pi --mode text`, private compact metadata extension, shutdown cleanup, `.pi/fusion` artifacts | yes | yes | yes | | current-host stats/replay | yes | | BUG-180 coverage proves final-text transport, reasoning exclusion, strict response reconstruction, unchanged caps, isolation, process cleanup, failure artifacts, and lifecycle semantics. BUG-182 preserves all token and cost components and proves successful plus failed/cancelled attempt costs aggregate exactly once. Claude cache coverage pins default one-hour retention, explicit short/none/long policy, model fallback, no-marker compaction preservation, four-breakpoint enforcement, sanitizer-before-normalizer ordering, and hash-bound cache observations in child-result v3/settlement v2 artifacts. SDK/RPC verify public child isolation; session shutdown tracks initializing and live runs. |
99
100
  | Extension request/response service | `pi-background-tasks:request:v1` → `pi-background-tasks:response:v1` | yes | yes | | | | yes | | Unit covers closed-frame validation, capability handshake, unknown keys, unknown operation, duplicate request IDs, missing `session_start`, shutdown refusal, strict `run.payload`, strict malformed frames, and unsubscribe. SDK loads the real extension with a shared `createEventBus()`, starts `printf api-ok`, reads bounded logs, lists status, starts and kills a real sleep task, and checks malformed/unknown/duplicate controls without model/provider calls. Package tests assert `src/core/extension-api.ts` ships. |
100
101
  | Terminal EventBus publication | `pi-background-tasks:terminal:v1` | yes | yes | | | | yes | | Registry unit proves one terminal snapshot after durable metadata when EventBus emit succeeds and loud/retriable delivery failure. Because retry after a listener throws may redeliver to an earlier listener, consumers must deduplicate by task id. Extension API unit proves one strict terminal frame correlated by task id after the run response for immediate, normal, failed, timeout, and killed tasks; SDK observes one terminal event for a completed task and one for a killed task through the real extension service. |
101
102
  | Completion notification | custom message `background-task-notification` | yes | yes | | renderer via typecheck | | | yes | BUG-181 unit/SDK coverage pins the durable-terminal guidance and truthful effective delivery receipts. Scripted provider loads the shipped extension, conditionally attempts the old `bg_status` poll when the real system prompt/descriptions/receipt are incomplete, and proves the fixed contract instead yields with exactly one `bg_run`, one terminal notification, and one default follow-up. Notification-only, notification-disabled, failed-task, and display-only `/bg` paths remain covered. |
@@ -125,7 +126,7 @@ SDK/RPC/scripted-provider/package/compatibility coverage asserts exactly four to
125
126
  | Package manifest | `package.json` | | | | | | yes | | Keywords, `pi.extensions`, files, local smoke/compat scripts, and direct-completion import bans. |
126
127
  | Pack contents | `npm pack --dry-run` | | | | | | yes | | Runtime files included; tests, fake child helpers, release-only scripts, artifacts, nested tarballs, and `node_modules` excluded. Default tarball install test uses isolated HOME/XDG/npm cache and offline peer-ignore install from the local tarball. |
127
128
  | Maintainer docs gateway | `BACKGROUND-TASKS-INSTRUCTIONS.md` | docs focused | | | | | | | Gateway requires INDEX → read-before-edit → owning-doc navigation, records current docs generate/verify/attestation workflow, preserves subscription-only frontier routing, parent/child tool separation, durability/integrity, and no self-certification. Logo reference is package-local (`docs/assets/logo.svg`) when the asset-owner file is present. |
128
- | Shared architecture/API/runtime/operations docs | `docs/api`, `docs/concepts`, `docs/subsystems`, `docs/reference`, `docs/operations` | docs focused | | | | | | | The active docs engine validates frontmatter, package-local links/reference links, INDEX reachability, exact behavioral source ownership, generated runtime contracts, deterministic generated regions, manifest freshness, and semantic receipts. Unsupported extraction and legacy placeholders fail closed. |
129
+ | Shared architecture/API/runtime/operations docs | `docs/api`, `docs/concepts`, `docs/subsystems`, `docs/reference`, `docs/operations` | docs focused | | | | | | | The active docs engine validates frontmatter, package-local links/reference links, INDEX reachability, exact behavioral source ownership, generated runtime contracts, deterministic generated regions, and manifest freshness. Semantic receipt state is reported by default and enforced only by the optional strict attestation command. Unsupported extraction and legacy placeholders fail closed. |
129
130
  | Package maintenance version/tag wording | `PUBLISHING.md`, `docs/operations/releasing.md` | docs focused | | | | | | | Release commands derive `VERSION` from `package.json`; observed git tags stop at `v0.6.0`, so git install/tag certification is separate from npm publishing and no nonexistent v1 tag is advertised. |
130
131
 
131
132
  ## Residual hardening coverage
@@ -89,12 +89,13 @@
89
89
  "state": "pass"
90
90
  },
91
91
  {
92
- "authored_body_sha256": "sha256:6b1afc2083d3f21c704d5af62c6b2259217169002daedb5aa604b8631d4d2fd8",
92
+ "authored_body_sha256": "sha256:77a2a9bfeb73a4cda9c65b2559a06e141096ff496d732e1e3d9c4eb1a0ba8616",
93
93
  "covers_sources": [
94
94
  "extensions/fusion-child.ts",
95
95
  "src/core/fusion/artifacts.ts",
96
96
  "src/core/fusion/budget.ts",
97
97
  "src/core/fusion/child-protocol.ts",
98
+ "src/core/fusion/claude-cache.ts",
98
99
  "src/core/fusion/clean-context.ts",
99
100
  "src/core/fusion/config.ts",
100
101
  "src/core/fusion/context.ts",
@@ -111,11 +112,10 @@
111
112
  "src/ui/fusion-model-selector.ts"
112
113
  ],
113
114
  "doc_id": "subsystems/fusion",
114
- "notes": "Fusion investigate established agent_settled as the terminal audit boundary and required strict parser behavior; final implementation uses exclusive durable journal/seal I/O, rejects extension diagnostics, and focused lifecycle/incident/compatibility tests pass.",
115
115
  "rel": "docs/subsystems/fusion.md",
116
116
  "required": true,
117
117
  "reviewer": "fusion-investigate-agent-settled-panel-plus-regression-evidence",
118
- "state": "pass"
118
+ "state": "stale-authored-prose"
119
119
  },
120
120
  {
121
121
  "authored_body_sha256": "sha256:185e4ec320770ededfce51e1e8a5a166be8b4b11275b7515737f0305820555fe",
@@ -438,6 +438,7 @@
438
438
  "src/core/fusion/artifacts.ts",
439
439
  "src/core/fusion/budget.ts",
440
440
  "src/core/fusion/child-protocol.ts",
441
+ "src/core/fusion/claude-cache.ts",
441
442
  "src/core/fusion/clean-context.ts",
442
443
  "src/core/fusion/config.ts",
443
444
  "src/core/fusion/context.ts",
@@ -787,7 +788,7 @@
787
788
  "image": "https://raw.githubusercontent.com/ismailsaleekh/pi-background-tasks/main/logo.png",
788
789
  "name": "pi-background-tasks",
789
790
  "type": "module",
790
- "version": "1.0.4"
791
+ "version": "1.0.6"
791
792
  },
792
793
  "public_surface_ids": [
793
794
  "command:bg",
@@ -1663,6 +1664,9 @@
1663
1664
  "src/core/fusion/child-protocol.ts": [
1664
1665
  "subsystems/fusion"
1665
1666
  ],
1667
+ "src/core/fusion/claude-cache.ts": [
1668
+ "subsystems/fusion"
1669
+ ],
1666
1670
  "src/core/fusion/clean-context.ts": [
1667
1671
  "subsystems/fusion"
1668
1672
  ],
@@ -79,6 +79,16 @@ Missing config means all five slots are `$current`. Config entries are qualified
79
79
 
80
80
  Fusion accepts frontier-model routes only through Pi Anthropic or Codex subscription OAuth where `ModelRegistry.isUsingOAuth` confirms the route. Metered frontier API-key/base-URL paths are rejected before child creation, and relevant metered environment variables are stripped from Fusion children.
81
81
 
82
+ ## Fusion Claude prompt caching
83
+
84
+ | Variable | Effect |
85
+ |---|---|
86
+ | `PI_CACHE_RETENTION=long` | Use one-hour retention on Pi-selected Anthropic cache breakpoints. This is Fusion's default when the variable is unset. |
87
+ | `PI_CACHE_RETENTION=short` | Use normal ephemeral retention without a `ttl` field (approximately five minutes). |
88
+ | `PI_CACHE_RETENTION=none` | Remove Anthropic cache breakpoints from normal Fusion provider payloads. Pi compaction payloads that already contain no breakpoints remain unmarked under every policy. |
89
+
90
+ Fusion children are isolated with `--no-session --no-extensions`, so a parent session's `/claude-cache` override from `spawn-anthropic-attribution` is not inherited; use `PI_CACHE_RETENTION` for Fusion. Invalid values fail before provider transport. Fusion never adds breakpoints where Pi selected none, preserves at most Anthropic's four supported breakpoints, and records requested/effective policy in each child result event. Models that explicitly reject long retention use short retention instead. One-hour cache creation has a higher provider write price than short retention; cache reads/writes and their calculated costs remain visible in Fusion usage evidence.
91
+
82
92
  ## Fusion runtime limits
83
93
 
84
94
  These are source constants, not documented operator env knobs:
@@ -47,7 +47,8 @@ From current `package.json`:
47
47
  | Compatibility | `npm run test:compat` | Release-only exact Pi version install/compat plus current-host witness. |
48
48
  | Pack | `npm run pack:dry-run` | Release payload preview. |
49
49
  | Docs generate | `npm run docs:generate` | Regenerates generated docs regions/index/manifest. |
50
- | Docs verify | `npm run docs:verify` | Offline, read-only deterministic docs freshness verification; renders generated files twice in memory and compares committed bytes. |
50
+ | Docs verify | `npm run docs:verify` | Offline, read-only deterministic docs freshness verification; renders generated files twice in memory and reports semantic receipt freshness without requiring it. |
51
+ | Strict docs attestation verify | `npm run docs:verify:attestations` | Optional strict mode that additionally requires every behavioral receipt to match current prose and sources. |
51
52
  | Docs attestation | `npm run docs:attest/record -- <doc_id> --reviewer <identity-after-semantic-review> --verdict PASS --notes <review-notes>` | Computes hashes and records an explicit semantic PASS receipt after review; `npm run docs:attest` is an alias and still needs args. |
52
53
  | Docs unit/package gate | `npm run test:docs` | Docs-gate unit/package tests. |
53
54
  | Payload check | `npm run payload:check` | Package payload policy check. |
@@ -28,7 +28,9 @@ Start from the symptom, verify the source-owned doc, then apply the remediation.
28
28
  | `bg_result` says not ready | Child has not committed `result.json` yet | Wait for terminal notification or inspect later; do not poll tightly. |
29
29
  | Delegate result corruption/hash/identity mismatch | Result package does not match task/seed/route/hash contract | Treat as invalid; inspect artifact bytes. Do not synthesize an answer. |
30
30
  | Fusion model unavailable or metered route refusal | Frontier route is not admitted as a Pi subscription/OAuth route, or configured model is stale | Fix `/fusion-models` config to available subscription routes. Never route GPT/Claude-class work through metered APIs. |
31
- | Fusion prompt budget exceeded | Stage forecast or measured prompt exceeds limiting route capacity | Use larger configured routes or reduce explicit request/context. Do not route-substitute after planning. |
31
+ | Fusion prompt budget exceeded | Stage forecast or measured prompt exceeds limiting route capacity after reserving the larger of the Fusion output contract and route maximum output | Use a larger-context or lower-max-output configured subscription route, or reduce explicit request/context. Do not route-substitute after planning. |
32
+ | `child_runtime_budget_exceeded` | A post-launch provider payload exceeded safe route input, the child exceeded 128 provider requests or 192 tool calls, or runtime capacity/payload evidence was invalid | Inspect the attempt stderr `fusion-runtime-guard.v1` frame and failed audit seal. Narrow/split the task or choose a route with more safe input headroom; never ignore intermediate errors or weaken the guard. |
33
+ | `child_cache_policy_invalid` | Claude cache policy, retention configuration, or final cache-control shape was invalid | Set `PI_CACHE_RETENTION` to `none`, `short`, or `long`; inspect the guard frame and do not bypass its four-breakpoint or shape checks. |
32
34
  | Fusion child timeout vs idle timeout | Absolute timeout is 30 minutes; idle watchdog is 20 minutes of no stdout/stderr activity | Preserve distinction in errors. `FUSION_CHILD_IDLE_TIMEOUT_MS` is a source constant, not documented as env-configurable. |
33
35
  | Fusion research URL rejected | Source URL is not declared/public http(s), has credentials, resolves to blocked address class, or redirects unsafely | Provide declared public source URLs with purpose; targeted fetch is not search. |
34
36
  | `/fusion-models` rejects in non-TUI mode | Selector requires interactive UI | Use an interactive Pi TUI session to edit config; headless path should fail loudly. |
@@ -37,6 +37,7 @@ Every production file under `src/**` and `extensions/**` has exactly one primary
37
37
  | `src/core/fusion/artifacts.ts` | [subsystems/fusion](./subsystems/fusion.md) |
38
38
  | `src/core/fusion/budget.ts` | [subsystems/fusion](./subsystems/fusion.md) |
39
39
  | `src/core/fusion/child-protocol.ts` | [subsystems/fusion](./subsystems/fusion.md) |
40
+ | `src/core/fusion/claude-cache.ts` | [subsystems/fusion](./subsystems/fusion.md) |
40
41
  | `src/core/fusion/clean-context.ts` | [subsystems/fusion](./subsystems/fusion.md) |
41
42
  | `src/core/fusion/config.ts` | [subsystems/fusion](./subsystems/fusion.md) |
42
43
  | `src/core/fusion/context.ts` | [subsystems/fusion](./subsystems/fusion.md) |
@@ -16,27 +16,27 @@ This generated registry lists production environment-variable references, runtim
16
16
 
17
17
  | Name | Access | Provenance |
18
18
  | --- | --- | --- |
19
- | `ANTHROPIC_API_KEY` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:70` |
20
- | `ANTHROPIC_AUTH_TOKEN` | remove | `src/core/fusion/pi-child.ts:70` |
21
- | `ANTHROPIC_BASE_URL` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:70` |
22
- | `AZURE_OPENAI_AD_TOKEN` | remove | `src/core/fusion/pi-child.ts:70` |
23
- | `AZURE_OPENAI_API_KEY` | remove | `src/core/fusion/pi-child.ts:70` |
24
- | `AZURE_OPENAI_API_VERSION` | remove | `src/core/fusion/pi-child.ts:70` |
25
- | `AZURE_OPENAI_BASE_URL` | remove | `src/core/fusion/pi-child.ts:70` |
26
- | `AZURE_OPENAI_DEPLOYMENT_NAME_MAP` | remove | `src/core/fusion/pi-child.ts:70` |
27
- | `AZURE_OPENAI_ENDPOINT` | remove | `src/core/fusion/pi-child.ts:70` |
28
- | `AZURE_OPENAI_RESOURCE_NAME` | remove | `src/core/fusion/pi-child.ts:70` |
19
+ | `ANTHROPIC_API_KEY` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:92` |
20
+ | `ANTHROPIC_AUTH_TOKEN` | remove | `src/core/fusion/pi-child.ts:92` |
21
+ | `ANTHROPIC_BASE_URL` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:92` |
22
+ | `AZURE_OPENAI_AD_TOKEN` | remove | `src/core/fusion/pi-child.ts:92` |
23
+ | `AZURE_OPENAI_API_KEY` | remove | `src/core/fusion/pi-child.ts:92` |
24
+ | `AZURE_OPENAI_API_VERSION` | remove | `src/core/fusion/pi-child.ts:92` |
25
+ | `AZURE_OPENAI_BASE_URL` | remove | `src/core/fusion/pi-child.ts:92` |
26
+ | `AZURE_OPENAI_DEPLOYMENT_NAME_MAP` | remove | `src/core/fusion/pi-child.ts:92` |
27
+ | `AZURE_OPENAI_ENDPOINT` | remove | `src/core/fusion/pi-child.ts:92` |
28
+ | `AZURE_OPENAI_RESOURCE_NAME` | remove | `src/core/fusion/pi-child.ts:92` |
29
29
  | `ComSpec` | read | `src/core/common.ts:683`<br>`src/core/common.ts:692` |
30
- | `OPENAI_API_KEY` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:70` |
31
- | `OPENAI_BASE_URL` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:70` |
32
- | `OPENROUTER_API_KEY` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:70` |
33
- | `OPENROUTER_BASE_URL` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:70` |
30
+ | `OPENAI_API_KEY` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:92` |
31
+ | `OPENAI_BASE_URL` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:92` |
32
+ | `OPENROUTER_API_KEY` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:92` |
33
+ | `OPENROUTER_BASE_URL` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:92` |
34
34
  | `path` | read | `src/core/common.ts:638` |
35
35
  | `Path` | read | `src/core/common.ts:638` |
36
36
  | `PATH` | read | `src/core/common.ts:638` |
37
- | `PI_API_BASE_URL` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:70` |
38
- | `PI_API_KEY` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:70` |
39
- | `PI_AUTH_FILE` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:70` |
37
+ | `PI_API_BASE_URL` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:92` |
38
+ | `PI_API_KEY` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:92` |
39
+ | `PI_AUTH_FILE` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:92` |
40
40
  | `PI_BG_DELEGATE_ARTIFACT_DIR` | read, write | `src/core/delegate/launch.ts:324`<br>`src/delegate-child-extension.ts:277` |
41
41
  | `PI_BG_DELEGATE_LAUNCH_NONCE` | read, write | `src/core/delegate/launch.ts:328`<br>`src/delegate-child-extension.ts:281` |
42
42
  | `PI_BG_DELEGATE_SEED_PATH` | read, write | `src/core/delegate/launch.ts:325`<br>`src/delegate-child-extension.ts:278` |
@@ -48,17 +48,18 @@ This generated registry lists production environment-variable references, runtim
48
48
  | `PI_BG_REGISTRY_URL` | read | `src/extension.ts:453` |
49
49
  | `PI_BG_SHELL` | read | `src/core/common.ts:679` |
50
50
  | `PI_BG_SHELL_PATH` | read | `src/core/common.ts:680` |
51
- | `PI_FUSION_RESEARCH_ENABLED` | read, remove, write | `src/core/fusion/pi-child.ts:1291`<br>`src/core/fusion/pi-child.ts:70`<br>`src/fusion-child-extension.ts:393` |
52
- | `PI_FUSION_SOURCE_POLICY_PATH` | read, remove, write | `src/core/fusion/pi-child.ts:1292`<br>`src/core/fusion/pi-child.ts:70`<br>`src/fusion-child-extension.ts:349` |
53
- | `PI_FUSION_SOURCE_POLICY_SHA256` | read, remove, write | `src/core/fusion/pi-child.ts:1293`<br>`src/core/fusion/pi-child.ts:70`<br>`src/fusion-child-extension.ts:350` |
54
- | `PI_FUSION_TOOL_CALL_LOG_PATH` | read, remove, write | `src/core/fusion/pi-child.ts:1280`<br>`src/core/fusion/pi-child.ts:70`<br>`src/fusion-child-extension.ts:392` |
55
- | `PI_MODEL` | remove | `src/core/delegate/launch.ts:301`<br>`src/core/fusion/pi-child.ts:70` |
51
+ | `PI_CACHE_RETENTION` | read | `src/core/fusion/claude-cache.ts:56` |
52
+ | `PI_FUSION_RESEARCH_ENABLED` | read, remove, write | `src/core/fusion/pi-child.ts:1807`<br>`src/core/fusion/pi-child.ts:92`<br>`src/fusion-child-extension.ts:673` |
53
+ | `PI_FUSION_SOURCE_POLICY_PATH` | read, remove, write | `src/core/fusion/pi-child.ts:1808`<br>`src/core/fusion/pi-child.ts:92`<br>`src/fusion-child-extension.ts:629` |
54
+ | `PI_FUSION_SOURCE_POLICY_SHA256` | read, remove, write | `src/core/fusion/pi-child.ts:1809`<br>`src/core/fusion/pi-child.ts:92`<br>`src/fusion-child-extension.ts:630` |
55
+ | `PI_FUSION_TOOL_CALL_LOG_PATH` | read, remove, write | `src/core/fusion/pi-child.ts:1796`<br>`src/core/fusion/pi-child.ts:92`<br>`src/fusion-child-extension.ts:672` |
56
+ | `PI_MODEL` | remove | `src/core/delegate/launch.ts:301`<br>`src/core/fusion/pi-child.ts:92` |
56
57
  | `PI_OFFLINE` | read | `src/extension.ts:445` |
57
- | `PI_PROVIDER` | remove | `src/core/delegate/launch.ts:301`<br>`src/core/fusion/pi-child.ts:70` |
58
- | `PI_REASONING_LEVEL` | remove | `src/core/delegate/launch.ts:301`<br>`src/core/fusion/pi-child.ts:70` |
59
- | `PI_SESSION_FILE` | remove | `src/core/delegate/launch.ts:301`<br>`src/core/fusion/pi-child.ts:70` |
60
- | `PI_SESSION_ID` | remove | `src/core/delegate/launch.ts:301`<br>`src/core/fusion/pi-child.ts:70` |
61
- | `PI_SKIP_VERSION_CHECK` | write | `src/core/delegate/launch.ts:323`<br>`src/core/fusion/pi-child.ts:234` |
58
+ | `PI_PROVIDER` | remove | `src/core/delegate/launch.ts:301`<br>`src/core/fusion/pi-child.ts:92` |
59
+ | `PI_REASONING_LEVEL` | remove | `src/core/delegate/launch.ts:301`<br>`src/core/fusion/pi-child.ts:92` |
60
+ | `PI_SESSION_FILE` | remove | `src/core/delegate/launch.ts:301`<br>`src/core/fusion/pi-child.ts:92` |
61
+ | `PI_SESSION_ID` | remove | `src/core/delegate/launch.ts:301`<br>`src/core/fusion/pi-child.ts:92` |
62
+ | `PI_SKIP_VERSION_CHECK` | write | `src/core/delegate/launch.ts:323`<br>`src/core/fusion/pi-child.ts:256` |
62
63
  | `SHELL` | read | `src/core/common.ts:675` |
63
64
  | `SystemRoot` | read | `src/core/windows-taskkill.ts:96` |
64
65
  | `WINDIR` | read | `src/core/windows-taskkill.ts:101` |
@@ -91,7 +92,7 @@ This generated registry lists production environment-variable references, runtim
91
92
  | fusion-artifact | `budget-plan.json` | `src/core/fusion/artifacts.ts:369` |
92
93
  | fusion-artifact | `candidate-<slot>.attempt-<n>.response.md \| candidate-<slot>.attempt-<n>.response.partial.md` | `src/core/fusion/artifacts.ts:203` |
93
94
  | fusion-artifact | `candidate-<slot>.attempt-<n>.tool-calls.jsonl` | `src/core/fusion/artifacts.ts:301` |
94
- | fusion-artifact | `candidate-<slot>.attempt-<n>.tool-calls.jsonl.seal.json` | `src/core/fusion/child-protocol.ts:13` |
95
+ | fusion-artifact | `candidate-<slot>.attempt-<n>.tool-calls.jsonl.seal.json` | `src/core/fusion/child-protocol.ts:17` |
95
96
  | fusion-artifact | `canonical-input.json` | `src/core/fusion/artifacts.ts:339` |
96
97
  | fusion-artifact | `context-omission-ledger.json` | `src/core/fusion/artifacts.ts:348` |
97
98
  | fusion-artifact | `error.json` | `src/core/fusion/artifacts.ts:385` |
@@ -127,26 +128,29 @@ This generated registry lists production environment-variable references, runtim
127
128
  | `pi-background-tasks.extension-response.v1` | `src/core/extension-api.ts:16` |
128
129
  | `pi-background-tasks.extension-terminal.v1` | `src/core/extension-api.ts:17` |
129
130
  | `pi-background-tasks.fusion-blind-candidates.v1` | `src/core/fusion/prompts.ts:299` |
130
- | `pi-background-tasks.fusion-budget-plan.v3` | `src/core/fusion/types.ts:24` |
131
- | `pi-background-tasks.fusion-calibration-violation.v1` | `src/core/fusion/types.ts:26` |
132
- | `pi-background-tasks.fusion-child-result.v2` | `src/core/fusion/child-protocol.ts:5` |
133
- | `pi-background-tasks.fusion-context-ledger.v2` | `src/core/fusion/types.ts:22` |
131
+ | `pi-background-tasks.fusion-budget-plan.v4` | `src/core/fusion/types.ts:25` |
132
+ | `pi-background-tasks.fusion-calibration-violation.v1` | `src/core/fusion/types.ts:27` |
133
+ | `pi-background-tasks.fusion-child-result.v3` | `src/core/fusion/child-protocol.ts:6` |
134
+ | `pi-background-tasks.fusion-child-settlement.v2` | `src/core/fusion/child-protocol.ts:9` |
135
+ | `pi-background-tasks.fusion-claude-cache-observation.v1` | `src/core/fusion/claude-cache.ts:4` |
136
+ | `pi-background-tasks.fusion-context-ledger.v2` | `src/core/fusion/types.ts:23` |
134
137
  | `pi-background-tasks.fusion-evaluation-repair-input.v1` | `src/core/fusion/prompts.ts:279` |
135
138
  | `pi-background-tasks.fusion-evaluation.v1` | `src/core/fusion/types.ts:16` |
136
139
  | `pi-background-tasks.fusion-input.v4` | `src/core/fusion/types.ts:14` |
137
140
  | `pi-background-tasks.fusion-input.v5` | `src/core/fusion/types.ts:15` |
138
- | `pi-background-tasks.fusion-manifest.v3` | `src/core/fusion/types.ts:20` |
139
- | `pi-background-tasks.fusion-manifest.v4` | `src/core/fusion/types.ts:21` |
141
+ | `pi-background-tasks.fusion-manifest.v3` | `src/core/fusion/types.ts:21` |
142
+ | `pi-background-tasks.fusion-manifest.v4` | `src/core/fusion/types.ts:22` |
140
143
  | `pi-background-tasks.fusion-merge-input.v1` | `src/core/fusion/prompts.ts:325` |
141
144
  | `pi-background-tasks.fusion-models.v1` | `src/core/fusion/types.ts:13` |
142
145
  | `pi-background-tasks.fusion-progress.v1` | `src/fusion-extension.ts:57` |
143
146
  | `pi-background-tasks.fusion-request.v1` | `src/fusion-extension.ts:58` |
144
- | `pi-background-tasks.fusion-result.v4` | `src/core/fusion/types.ts:18` |
145
- | `pi-background-tasks.fusion-result.v5` | `src/core/fusion/types.ts:19` |
146
- | `pi-background-tasks.fusion-source-policy.v1` | `src/core/fusion/types.ts:23` |
147
- | `pi-background-tasks.fusion-tool-call-seal.v1` | `src/core/fusion/child-protocol.ts:12` |
148
- | `pi-background-tasks.fusion-tool-call.v1` | `src/core/fusion/types.ts:27` |
149
- | `pi-background-tasks.fusion-validation-candidate.v1` | `src/core/fusion/types.ts:17` |
147
+ | `pi-background-tasks.fusion-result.v4` | `src/core/fusion/types.ts:19` |
148
+ | `pi-background-tasks.fusion-result.v5` | `src/core/fusion/types.ts:20` |
149
+ | `pi-background-tasks.fusion-runtime-guard.v1` | `src/core/fusion/child-protocol.ts:19` |
150
+ | `pi-background-tasks.fusion-source-policy.v1` | `src/core/fusion/types.ts:24` |
151
+ | `pi-background-tasks.fusion-tool-call-seal.v1` | `src/core/fusion/child-protocol.ts:16` |
152
+ | `pi-background-tasks.fusion-tool-call.v1` | `src/core/fusion/types.ts:28` |
153
+ | `pi-background-tasks.fusion-validation-candidate.v1` | `src/core/fusion/types.ts:18` |
150
154
  | `pi-background-tasks.input-token-calibration.v1` | `src/core/context/token-budget.ts:18` |
151
155
 
152
156
  ### Status vocabularies
@@ -12,14 +12,14 @@ covers_sources: []
12
12
  This authored section defines the boundary: documentation facts are extracted from package metadata and TypeScript ASTs, then generated into docs and the manifest. Unsupported syntax fails the gate rather than falling back to regex or stale hand-maintained inventories. Public registrations must remain unconditional top-level direct calls or use the one validated local tool-wrapper shape; host/method aliases, computed access, nested or conditional registration, wrapper chaining/passing, constructor helpers, ambiguous public metadata, destructured Pi parameters, and repeated imported registrars are rejected.
13
13
 
14
14
  <!-- pi-docs:begin name="docs-freshness-gate" generator="scripts/docs/generate.mjs" -->
15
- - Canonical package version: `1.0.4`
15
+ - Canonical package version: `1.0.6`
16
16
  - Governed markdown docs: 40
17
17
  - Public surfaces extracted: 30
18
- - Governed production sources: 44
18
+ - Governed production sources: 45
19
19
  - Tool contracts extracted: 11
20
- - Schema IDs extracted: 37
21
- - Environment variable references extracted: 46
22
- - Behavioral attestation receipts not passing: 0
20
+ - Schema IDs extracted: 40
21
+ - Environment variable references extracted: 47
22
+ - Behavioral attestation receipts not passing: 1
23
23
  - Receipt store: `docs/attestations.json`
24
24
 
25
25
  `npm run docs:verify` is read-only: it renders generated files twice in memory and compares them with committed bytes. `npm run docs:generate` is the only docs writer.
@@ -5,8 +5,9 @@ mode: mixed
5
5
  review_policy: behavioral
6
6
  stability: stable
7
7
  covers_surfaces: [renderer:fusion-result, workflow:investigate, workflow:reason, workflow:research, workflow:validate]
8
- covers_sources: [extensions/fusion-child.ts, src/core/fusion/artifacts.ts, src/core/fusion/budget.ts, src/core/fusion/child-protocol.ts, src/core/fusion/clean-context.ts, src/core/fusion/config.ts, src/core/fusion/context.ts, src/core/fusion/evaluation.ts, src/core/fusion/orchestrator.ts, src/core/fusion/pi-child.ts, src/core/fusion/prompts.ts, src/core/fusion/source-policy.ts, src/core/fusion/types.ts, src/core/fusion/web-fetch.ts, src/core/fusion/workflows.ts, src/fusion-child-extension.ts, src/fusion-extension.ts, src/ui/fusion-model-selector.ts]
8
+ covers_sources: [extensions/fusion-child.ts, src/core/fusion/artifacts.ts, src/core/fusion/budget.ts, src/core/fusion/child-protocol.ts, src/core/fusion/claude-cache.ts, src/core/fusion/clean-context.ts, src/core/fusion/config.ts, src/core/fusion/context.ts, src/core/fusion/evaluation.ts, src/core/fusion/orchestrator.ts, src/core/fusion/pi-child.ts, src/core/fusion/prompts.ts, src/core/fusion/source-policy.ts, src/core/fusion/types.ts, src/core/fusion/web-fetch.ts, src/core/fusion/workflows.ts, src/fusion-child-extension.ts, src/fusion-extension.ts, src/ui/fusion-model-selector.ts]
9
9
  ---
10
+
10
11
  # Fusion subsystem
11
12
 
12
13
  <!-- pi-docs:begin name="fusion-workflows" generator="scripts/docs/generate.mjs" -->
@@ -60,12 +61,12 @@ Do not describe Fusion as unconditionally exactly five model calls. A completed
60
61
 
61
62
  Candidate tool policies are fixed by workflow:
62
63
 
63
- | Workflow | Candidate capability | Candidate tools |
64
- |---|---:|---|
65
- | reason | `reason` | none (`--no-tools`) |
66
- | investigate | `inspect` | `read`, `grep`, `find`, `ls` |
67
- | research | `research` | `read`, `grep`, `find`, `ls`, `fusion_web_fetch` |
68
- | validate | `inspect` | `read`, `grep`, `find`, `ls` |
64
+ | Workflow | Candidate capability | Candidate tools |
65
+ | ----------- | -------------------: | ------------------------------------------------ |
66
+ | reason | `reason` | none (`--no-tools`) |
67
+ | investigate | `inspect` | `read`, `grep`, `find`, `ls` |
68
+ | research | `research` | `read`, `grep`, `find`, `ls`, `fusion_web_fetch` |
69
+ | validate | `inspect` | `read`, `grep`, `find`, `ls` |
69
70
 
70
71
  Evaluator, evaluator-repair, and merger always use capability `reason` and empty tool lists. Tool-enabled children run with built-in tools disabled and an explicit allowlist plus a denylist that includes shell/write/edit, Fusion recursion, and background/delegate tools.
71
72
 
@@ -81,13 +82,15 @@ Research is targeted fetch, not search. The public caller declares exact non-dup
81
82
 
82
83
  Research intentionally combines read-only file tools and network fetch in one child. This supports source-backed synthesis but is security-sensitive: operators must not supply secret-bearing URLs or ask children to put private data in URL strings. The package blocks common SSRF targets and credential URLs, but its deny rules are not an exhaustive network sandbox; fetched content remains untrusted and caller-declared public URLs can still disclose access through remote logs/timing.
83
84
 
84
- Inspect/research candidates write sealed tool-call audit logs. The log contains schema version, ordinal, tool name, argument/result byte counts and SHA-256 digests, status, duration, and fetch provenance. Raw arguments, raw results, page content, and rejected raw URLs are not persisted. The parent requires the log and seal, verifies hashes/counts/ordinals/status, enforces the 8 MiB aggregate result-byte cap, and rejects non-allowlisted tools.
85
+ Inspect/research candidates write sealed tool-call audit logs. The log contains schema version, ordinal, tool name, argument/result byte counts and SHA-256 digests, status, duration, and fetch provenance. Raw arguments, raw results, page content, and rejected raw URLs are not persisted. The parent requires the log and seal, verifies hashes/counts/ordinals/status, enforces the 8 MiB aggregate result-byte cap, and rejects non-allowlisted tools. A child may attempt at most 192 tool calls; crossing that limit aborts the run, emits structured refusal evidence, and prevents a complete audit seal.
85
86
 
86
87
  ## Child process isolation
87
88
 
88
- Fusion never calls direct completion APIs. It launches direct child `pi --mode text` processes and writes the prompt over stdin. Child argv includes `--no-session`, `--no-extensions`, `--no-skills`, `--no-prompt-templates`, `--no-themes`, and `--no-context-files`; explicit extensions still load, so the package-owned compact metadata extension is always supplied. Anthropic children additionally receive the `@ravshansbox/pi-anthropic-sps` sanitizer extension because discovery is disabled and Claude routes need Pi system-prompt sanitization.
89
+ Fusion never calls direct completion APIs. It launches direct child `pi --mode text` processes and writes the prompt over stdin. Child argv includes `--no-session`, `--no-extensions`, `--no-skills`, `--no-prompt-templates`, `--no-themes`, and `--no-context-files`; explicit extensions still load, so the package-owned compact metadata extension is always supplied. Anthropic children additionally receive the `@ravshansbox/pi-anthropic-sps` sanitizer extension because discovery is disabled and Claude routes need Pi system-prompt sanitization. That dependency only sanitizes rejected system-prompt lines and preserves existing cache fields; it does not choose Fusion's cache policy.
90
+
91
+ Child text mode writes the final full answer to stdout. The private child extension emits compact reasoning-free metadata frames to stderr for finalized assistant messages: provider/model, stop reason, text block byte counts and hashes, aggregate text hash, the complete Pi `Usage` object, and a closed cache-policy observation. It also governs every final `before_provider_request` payload after earlier extensions have transformed it. Claude's sanitizer therefore loads before the package governor. For Anthropic routes, the package normalizes only cache breakpoints already selected by Pi's adapter: default retention is `long` (`ttl: "1h"`), while inherited `PI_CACHE_RETENTION=short|none|long` explicitly selects the policy. Long retention falls back to short when model compatibility rejects it. Existing no-marker payloads remain unmarked so Pi's call-level `cacheRetention="none"` compaction requests are never overridden. Malformed controls, invalid policy values, or more than four breakpoints abort before transport. Non-Anthropic payloads remain byte-equivalent apart from the governor's existing JSON normalization.
89
92
 
90
- Child text mode writes the final full answer to stdout. The private child extension emits compact reasoning-free metadata frames to stderr for finalized assistant messages: provider/model, stop reason, text block byte counts and hashes, aggregate text hash, and the complete Pi `Usage` object. The parent reconstructs and validates stdout against the final metadata, requires final stop reason `stop` and non-final stop reason `toolUse`, verifies model identity, and preserves usage/cost exactly.
93
+ After cache normalization, the governor serializes and hashes the exact payload, applies the shared conservative estimator, reserves the model's declared maximum output plus 4,096 safety tokens, and aborts before transport if the payload cannot fit or if the child exceeds 128 provider requests. Pi's provider-hook behavior is characterized through the same `openai-codex-responses` transport adapter used by subscription Codex routes in a real local HTTP agent loop: transforms chain in extension load order and `ctx.abort()` prevents network transport. Cache observations use `pi-background-tasks.fusion-claude-cache-observation.v1`, state requested/effective retention, source, breakpoint count, and provider-request ordinal, and are hash-bound inside `pi-background-tasks.fusion-child-result.v3` attempt event artifacts. At terminal `agent_settled`, the extension emits exactly one `pi-background-tasks.fusion-child-settlement.v2` frame binding the complete ordered metadata stream by count and SHA-256, the final record/hash, and any recovered retry-marker ordinals. The parent validates closed cache evidence and increasing request ordinals, reconstructs stdout against the final metadata, requires final stop reason `stop`, verifies model identity, and preserves usage/cost exactly. Non-final `toolUse` records remain normal. A non-final `error` is accepted only when it is a zero-content, empty-hash, zero-usage retry marker, a later final `stop` exists, and the terminal settlement hash/accounts for that exact ordinal. `length`, `aborted`, `pending`, final `error`, error records carrying text or usage, missing/duplicate/tampered settlement, and settlement before terminal idleness all fail loudly.
91
94
 
92
95
  Fusion child environments strip session/model/provider variables plus metered credential/base-url variables for OpenRouter, OpenAI, Anthropic, Azure OpenAI, and generic Pi API credentials before launch. Frontier model routes are admitted only when the registry reports subscription OAuth for trusted `anthropic` or `openai-codex` endpoints. There is no fallback, model substitution, endpoint override, or metered API-key route.
93
96
 
@@ -95,7 +98,7 @@ Fusion child environments strip session/model/provider variables plus metered cr
95
98
 
96
99
  Budget planning is per route and per stage. Every configured candidate, evaluator, and merger route must have a usable context window. The affine estimator from the shared token-budget layer accounts for byte classes plus a 512-token intercept; backed model-family calibrations are used only where applicable, unknown/unbacked providers are reported in artifacts/result details, and multibyte/dense ASCII diagnostics are preserved.
97
100
 
98
- `budget-plan.json` records route capacities, stage forecasts for candidate/evaluation/evaluation-repair/merge, conditional repair reservation, warnings, blockers, empty-request counterfactuals, and remediation. Fatal preflight blockers launch zero children. High utilization or worst-case reservation pressure is a warning when input still fits. Exact rendered prompt checks happen again immediately before candidate, evaluation, repair, and merge launches.
101
+ `budget-plan.json` uses `pi-background-tasks.fusion-budget-plan.v4` and records route capacities, stage forecasts for candidate/evaluation/evaluation-repair/merge, conditional repair reservation, warnings, blockers, empty-request counterfactuals, and remediation. Each route reserves the larger of Fusion's 32,768-token output contract reserve and the resolved model's declared maximum output; a model advertising a 128,000-token maximum therefore receives the full 128,000-token reserve. Fatal preflight blockers launch zero children. High utilization or worst-case reservation pressure is a warning when input still fits. Exact rendered prompt checks happen again immediately before candidate, evaluation, repair, and merge launches.
99
102
 
100
103
  Output contracts are checked after durable attempt recording: candidate responses up to 48 KiB JSON-rendered bytes, evaluator up to 64 KiB, merger/final report up to 64 KiB, diagnostics contract 8 KiB, child stdout cap 32 MiB, child stderr cap 4 MiB. Oversized child output fails loudly and preserves evidence; Fusion never clips or silently forwards truncated content.
101
104
 
@@ -105,7 +108,7 @@ Run artifacts are private local evidence under `.pi/fusion/<session-id>-<pid>/<r
105
108
 
106
109
  Artifact writes use durable private temp-file/fsync/rename. Manifests enforce legal state transitions and record config, resolved models, fixed capabilities, context policy, tool policy, anonymous map, attempts, artifact refs, cumulative usage, and errors. Successful, failed, and cancelled observed attempts preserve complete Pi usage/cost components; public tool results clone the same `Usage` shape.
107
110
 
108
- For tool-enabled children, the private audit journal remains open across every low-level `agent_end`, because Pi may still retry, compact and retry, or process a queued continuation. Only terminal `agent_settled` can exclusively publish the complete hash/count/byte seal. Tool activity after finalization, duplicate settlement, pre-settlement shutdown, extension diagnostics, and missing/failed/stale seals are fatal. This lifecycle requires Pi 0.81.1 or newer; older Pi lines do not expose the required terminal event and are not claimed as compatible.
111
+ For tool-enabled children, the private audit journal remains open across every low-level `agent_end`, because Pi may still retry, compact and retry, or process a queued continuation. Only terminal `agent_settled` can exclusively publish the complete hash/count/byte seal. Runtime-guard refusal latches process failure, makes that seal incomplete, and forces the result settlement to failed. The child emits one closed `pi-background-tasks.fusion-runtime-guard.v1` stderr frame containing the refusal code, route capacities, request/tool ordinals, exact payload byte count and SHA-256, conservative token estimate, and a bounded message; it never emits the payload itself. The parent validates this frame and reports typed `child_runtime_budget_exceeded` for runtime capacity/loop refusals or `child_cache_policy_invalid` for Claude cache-policy refusal, instead of accepting a later clean-looking result or reducing it to an unexplained exit code. Tool activity after finalization, duplicate settlement, pre-settlement shutdown, extension diagnostics, malformed/duplicate runtime-guard frames, and missing/failed/stale seals are fatal. This lifecycle requires Pi 0.81.1 or newer; older Pi lines do not expose the required terminal event and are not claimed as compatible.
109
112
 
110
113
  Cancellation and shutdown are loud and durable when a run store exists. The extension tracks active runs, links external abort signals, aborts on session shutdown/reload, and waits for settlement. Child processes have a 30 minute wall timeout, 20 minute idle watchdog, SIGTERM grace, SIGKILL wait, process-group kill on POSIX, bounded stdout/stderr, and cleanup-error propagation.
111
114
 
@@ -116,6 +119,8 @@ Cancellation and shutdown are loud and durable when a run store exists. The exte
116
119
  - Frontier/API route rejected: use Pi Anthropic or Codex subscription OAuth, not OpenAI/OpenRouter/Azure/API-key routes.
117
120
  - `prompt_budget_exceeded_forecast`: inspect `budget-plan.json`; the error says whether shortening the request can help or whether session history/scope/model context window is the blocker.
118
121
  - `prompt_budget_exceeded_measured`: an exact rendered prompt exceeded capacity after upstream output was known; split the workflow or choose a larger-context subscription route.
122
+ - `child_runtime_budget_exceeded`: a later provider payload, provider-request loop, or tool-call loop crossed a child runtime guard after launch. Inspect the attempt stderr guard frame and failed tool seal; narrow the task or select a subscription route with more safe input headroom. Do not ignore intermediate provider errors or weaken the guard.
123
+ - `child_cache_policy_invalid`: `PI_CACHE_RETENTION` or Claude cache-control evidence was malformed. Use exactly `none`, `short`, or `long`; do not remove the final-payload guard.
119
124
  - `evaluation schema repair failed`: both evaluator attempts failed the closed JSON contract; inspect `evaluation.attempt-*.response.txt` and errors.
120
125
  - `tool-call log invalid`: inspect the candidate `*.tool-calls.jsonl` and `*.seal.json`; missing/partial/unsealed logs, non-allowlisted tools, hash/count mismatches, and over-budget tool output fail by design.
121
126
  - Research fetch failures are typed and do not retry via other URLs or extraction modes; verify the declared URL is public, reachable, supported content, and within caps.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-background-tasks",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Pi extension for durable background shell tasks, read-only delegated agents, local attested Pi runs, and fixed-purpose Fusion workflows through child Pi processes.",
5
5
  "type": "module",
6
6
  "license": "ISC",
@@ -68,6 +68,7 @@
68
68
  "test:hook-contract": "tsx --test --test-concurrency=1 tests/scripted-provider/pi-hook-contract.test.ts",
69
69
  "docs:generate": "node scripts/docs/generate.mjs",
70
70
  "docs:verify": "node scripts/docs/verify.mjs",
71
+ "docs:verify:attestations": "node scripts/docs/verify.mjs --require-attestations",
71
72
  "docs:attest/record": "node scripts/docs/attest.mjs",
72
73
  "docs:attest": "npm run docs:attest/record",
73
74
  "test:docs": "tsx --test tests/unit/docs-gate.test.ts tests/package/docs-contract.test.ts",