pi-background-tasks 2.1.1 → 2.1.2

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.
package/README.md CHANGED
@@ -26,7 +26,7 @@
26
26
  | Fact | Value |
27
27
  | --- | --- |
28
28
  | Package | `pi-background-tasks` |
29
- | Version | `2.1.1` |
29
+ | Version | `2.1.2` |
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) |
package/TESTING.md CHANGED
@@ -35,29 +35,30 @@ real Pi agent loop against a deterministic scripted provider and records what Pi
35
35
  guard depends on that behaviour and it must be proven by execution rather than read
36
36
  from type declarations.
37
37
 
38
- The observed guarantees are written to
38
+ The conservative guarantees shared by every supported Pi line are written to
39
39
  `tests/scripted-provider/pi-hook-contract-evidence.json` and shipped as
40
40
  `src/core/delegate/hook-contract-evidence.json`. A package test asserts the two are
41
- byte-identical, so the runtime gate and the gate that proved it cannot drift apart.
42
- If the evidence file already exists, the gate **compares** against it rather than
43
- rewriting it: a change in Pi's hook behaviour fails loudly and forces a deliberate
44
- re-review of the child guard instead of silently regenerating.
41
+ byte-identical, so the runtime gate and its proving evidence cannot drift apart. If the evidence file already exists, the gate **compares** against it rather
42
+ than rewriting it: a change in a required Pi hook invariant fails loudly and forces
43
+ a deliberate re-review of the child guard instead of silent regeneration. The
44
+ release compatibility gate additionally pins each supported line's exact abort mode.
45
45
 
46
- On Pi 0.83 the gate establishes, by execution:
46
+ Across the supported Pi lines, the gates establish by execution:
47
47
 
48
48
  | Question | Observed |
49
49
  |---|---|
50
50
  | Does `context` fire before every model call? | yes, once per call, in extension load order |
51
51
  | Do messages returned from `context` reach the provider? | yes |
52
52
  | Does **throwing** in `context` prevent the provider call? | **no** — Pi catches it and dispatches anyway |
53
- | Does `ctx.abort()` prevent it? | it does not skip the call site, but the call receives an already-aborted signal and the run terminates |
53
+ | Does `ctx.abort()` prevent transport? | yes; Pi 0.81.1–0.83.0 invoke the provider with an already-aborted signal, while Pi 0.84.0 skips provider invocation during signal-aware auth resolution; every line terminates |
54
54
  | Does `tool_result` fire before the transcript entry, and can a handler replace it? | yes, chained in load order; the replacement reaches the provider and the original does not |
55
55
  | Do tool-call id, role, and `isError` survive replacement? | yes |
56
56
 
57
- Because neither a throw nor an abort is a hard admission gate on its own, the child
58
- guard uses abort as the barrier **and** removes the oversized content from the
59
- outgoing message set. A Pi build that cannot provide the required guarantees causes
60
- `bg_delegate` to refuse to spawn with a typed `delegate_hook_contract_unsupported`.
57
+ Because a throw is not a barrier and older supported Pi lines still enter the
58
+ provider with an aborted signal, the child guard uses abort **and** removes the
59
+ oversized content from the outgoing message set. A Pi build that cannot provide the
60
+ required guarantees causes `bg_delegate` to refuse to spawn with a typed
61
+ `delegate_hook_contract_unsupported`.
61
62
 
62
63
  Full interactive gate:
63
64
 
package/TEST_PLAN.md CHANGED
@@ -40,7 +40,7 @@ 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`/`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 |
43
+ | Compatibility | `npm run test:compat` | release gate | implemented; exact Pi `0.81.1`, `0.82.1`, `0.83.0`, `0.84.0` pack/install plus `/jobs`, `/fusion`, and `/fusion-models` surfaces, per-version context-abort transport barriers, `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
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 |
@@ -86,8 +86,8 @@ SDK/RPC/scripted-provider/package/compatibility coverage asserts exactly four to
86
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. |
87
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. |
88
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. |
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. |
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. |
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/0.84'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. |
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()` either skips provider invocation (Pi 0.84) or delivers an already-aborted signal (older supported lines), blocks transport, 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. |
91
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. |
92
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. |
93
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. |
@@ -65,7 +65,7 @@
65
65
  "state": "pass"
66
66
  },
67
67
  {
68
- "authored_body_sha256": "sha256:a60f4f25e266ea5cf9e5c89b1b6fbf7bf7fc07d2600a6b82bc5bd9d39eb60438",
68
+ "authored_body_sha256": "sha256:60b6235d33b9c7df1b1494c0c071862aee059074ce58058c103f9a71d5d9e7d8",
69
69
  "covers_sources": [
70
70
  "extensions/delegate-child.ts",
71
71
  "src/core/delegate/artifacts.ts",
@@ -84,7 +84,7 @@
84
84
  "rel": "docs/subsystems/delegation.md",
85
85
  "required": true,
86
86
  "reviewer": "gpt-5.5-final-delegation-review-panel-plus-timeout-delta",
87
- "state": "stale-sources"
87
+ "state": "stale-authored-prose"
88
88
  },
89
89
  {
90
90
  "authored_body_sha256": "sha256:200168b5db6e14947b5dbee9aef51c4e14d57de0df7716776250193b26b57289",
@@ -791,7 +791,7 @@
791
791
  "image": "https://raw.githubusercontent.com/ismailsaleekh/pi-background-tasks/main/logo.png",
792
792
  "name": "pi-background-tasks",
793
793
  "type": "module",
794
- "version": "2.1.1"
794
+ "version": "2.1.2"
795
795
  },
796
796
  "public_surface_ids": [
797
797
  "command:bg",
@@ -37,11 +37,11 @@ This generated registry lists production environment-variable references, runtim
37
37
  | `PI_API_BASE_URL` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:100` |
38
38
  | `PI_API_KEY` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:100` |
39
39
  | `PI_AUTH_FILE` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:100` |
40
- | `PI_BG_DELEGATE_ARTIFACT_DIR` | read, write | `src/core/delegate/launch.ts:324`<br>`src/delegate-child-extension.ts:277` |
41
- | `PI_BG_DELEGATE_LAUNCH_NONCE` | read, write | `src/core/delegate/launch.ts:328`<br>`src/delegate-child-extension.ts:281` |
42
- | `PI_BG_DELEGATE_SEED_PATH` | read, write | `src/core/delegate/launch.ts:325`<br>`src/delegate-child-extension.ts:278` |
43
- | `PI_BG_DELEGATE_SEED_SHA256` | read, write | `src/core/delegate/launch.ts:326`<br>`src/delegate-child-extension.ts:279` |
44
- | `PI_BG_DELEGATE_TASK_ID` | read, write | `src/core/delegate/launch.ts:327`<br>`src/delegate-child-extension.ts:280` |
40
+ | `PI_BG_DELEGATE_ARTIFACT_DIR` | read, write | `src/core/delegate/launch.ts:324`<br>`src/delegate-child-extension.ts:276` |
41
+ | `PI_BG_DELEGATE_LAUNCH_NONCE` | read, write | `src/core/delegate/launch.ts:328`<br>`src/delegate-child-extension.ts:280` |
42
+ | `PI_BG_DELEGATE_SEED_PATH` | read, write | `src/core/delegate/launch.ts:325`<br>`src/delegate-child-extension.ts:277` |
43
+ | `PI_BG_DELEGATE_SEED_SHA256` | read, write | `src/core/delegate/launch.ts:326`<br>`src/delegate-child-extension.ts:278` |
44
+ | `PI_BG_DELEGATE_TASK_ID` | read, write | `src/core/delegate/launch.ts:327`<br>`src/delegate-child-extension.ts:279` |
45
45
  | `PI_BG_DISABLE_PI_TELEMETRY` | read | `src/core/registry.ts:194` |
46
46
  | `PI_BG_DISABLE_UPDATE_CHECK` | read | `src/extension.ts:455` |
47
47
  | `PI_BG_MAX_OUTPUT_BYTES` | read | `src/core/registry.ts:68` |
@@ -117,7 +117,7 @@ This generated registry lists production environment-variable references, runtim
117
117
  | --- | --- |
118
118
  | `phase2.pi_task_attestation.v1` | `src/core/attested-pi-run.ts:20` |
119
119
  | `pi-background-tasks.delegate-budget-plan.v2` | `src/core/delegate/types.ts:21` |
120
- | `pi-background-tasks.delegate-child-terminal.v1` | `src/delegate-child-extension.ts:381` |
120
+ | `pi-background-tasks.delegate-child-terminal.v1` | `src/delegate-child-extension.ts:380` |
121
121
  | `pi-background-tasks.delegate-hook-contract.v1` | `src/core/delegate/hook-contract.ts:15` |
122
122
  | `pi-background-tasks.delegate-launch.v1` | `src/delegate-extension.ts:398` |
123
123
  | `pi-background-tasks.delegate-ledger.v1` | `src/core/delegate/types.ts:16` |
@@ -185,6 +185,6 @@ Each `DelegateError` renders code, message, child-created flag, artifact locatio
185
185
 
186
186
  The child guard relies on Pi hook behavior proven by `tests/scripted-provider/pi-hook-contract.test.ts`; shipped evidence is byte-identical to `src/core/delegate/hook-contract-evidence.json`.
187
187
 
188
- Required guarantees include context hook ordering, returned context messages reaching the provider, abort blocking the provider request by handing an aborted signal, abort terminating the run, context throw isolation, tool-result replacement before transcript entry, replacement identity preservation, and extension load order.
188
+ Required guarantees include context hook ordering, returned context messages reaching the provider, abort blocking transport, abort terminating the run, context throw isolation, tool-result replacement before transcript entry, replacement identity preservation, and extension load order.
189
189
 
190
- Pi 0.83 evidence explicitly shows two guarantees are false and therefore not required: context throws do not block provider calls, and abort does not skip the provider call site. The guard is built fail-closed anyway: it aborts and returns a suppressed message set, so the original oversized content is not dispatched even if a provider ignored the aborted signal. Missing/malformed/unsupported evidence fails with `delegate_hook_contract_unsupported`; the guard is not weakened at runtime.
190
+ Exact-version evidence covers both supported abort modes: Pi 0.81.1–0.83.0 invoke the provider with an already-aborted signal, while Pi 0.84.0 propagates that signal through auth resolution and skips provider invocation. Context throws still do not block dispatch. The guard is built fail-closed across both modes: it aborts and returns a suppressed message set, so the original oversized content is not dispatched even if a provider ignored the aborted signal. Missing/malformed/unsupported evidence fails with `delegate_hook_contract_unsupported`; the guard is not weakened at runtime.
@@ -12,7 +12,7 @@ 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: `2.1.1`
15
+ - Canonical package version: `2.1.2`
16
16
  - Governed markdown docs: 40
17
17
  - Public surfaces extracted: 30
18
18
  - Governed production sources: 48
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-background-tasks",
3
- "version": "2.1.1",
3
+ "version": "2.1.2",
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",
@@ -83,14 +83,14 @@
83
83
  ]
84
84
  },
85
85
  "peerDependencies": {
86
- "@earendil-works/pi-coding-agent": "^0.81.1 || ^0.82.1 || ^0.83.0",
87
- "@earendil-works/pi-tui": "^0.81.1 || ^0.82.1 || ^0.83.0",
86
+ "@earendil-works/pi-coding-agent": "^0.81.1 || ^0.82.1 || ^0.83.0 || ^0.84.0",
87
+ "@earendil-works/pi-tui": "^0.81.1 || ^0.82.1 || ^0.83.0 || ^0.84.0",
88
88
  "typebox": "*"
89
89
  },
90
90
  "devDependencies": {
91
- "@earendil-works/pi-ai": "^0.83.0",
92
- "@earendil-works/pi-coding-agent": "^0.83.0",
93
- "@earendil-works/pi-tui": "^0.83.0",
91
+ "@earendil-works/pi-ai": "^0.84.0",
92
+ "@earendil-works/pi-coding-agent": "^0.84.0",
93
+ "@earendil-works/pi-tui": "^0.84.0",
94
94
  "@types/node": "^24.0.0",
95
95
  "@types/turndown": "5.0.6",
96
96
  "tsx": "^4.19.0",
@@ -22,14 +22,15 @@ export const DELEGATE_HOOK_CONTRACT_SCHEMA_VERSION =
22
22
  * `ctx.abort()` so the request is never issued, then report a typed failure over
23
23
  * the child result channel.
24
24
  *
25
- * Empirically established by the characterisation gate on Pi 0.83:
26
- * `ctx.abort()` does NOT skip the `streamSimple` call site. Pi still invokes the
27
- * provider entry point, but hands it an already-aborted `AbortSignal`, so no
28
- * network request is issued and the run terminates with stop reason `aborted`.
29
- * Throwing from a `context` handler is NOT a barrier at all: Pi catches the
30
- * exception, reports it as an extension error, and dispatches the call anyway.
31
- * The guard therefore uses abort, never a throw, and additionally suppresses the
32
- * oversized content itself so a non-conforming provider cannot transmit it.
25
+ * Empirically established across the supported Pi lines by the characterisation
26
+ * and exact-version compatibility gates: Pi 0.81.1-0.83.0 invoke the provider
27
+ * entry point with an already-aborted `AbortSignal`, while Pi 0.84.0 propagates
28
+ * that signal through auth resolution and skips the entry point. No network
29
+ * request is issued in either mode, and the run terminates. Throwing from a
30
+ * `context` handler is NOT a barrier at all: Pi catches the exception, reports
31
+ * it as an extension error, and continues dispatch. The guard therefore uses
32
+ * abort, never a throw, and additionally suppresses the oversized content itself
33
+ * so a non-conforming provider cannot transmit it.
33
34
  *
34
35
  * `tool-result-spill-v1`: replace an oversized `tool_result` payload with an
35
36
  * explicit hash-accounted receipt before it enters the transcript.
@@ -65,11 +66,11 @@ export interface DelegateHookContractEvidence {
65
66
  * Guarantees the child guard actually depends on.
66
67
  *
67
68
  * `context_throw_blocks_provider_call` and
68
- * `context_abort_skips_stream_invocation` are deliberately absent, because
69
- * neither holds on Pi 0.83. The gate records both as observed evidence, and the
70
- * guard is built so that it does not need either: it aborts the run AND removes
71
- * the oversized content from the outgoing message set, so the request cannot be
72
- * issued and could not carry the content even if it were.
69
+ * `context_abort_skips_stream_invocation` are deliberately absent. Throws do
70
+ * not block dispatch, and skipping the stream entry point is not shared by every
71
+ * supported Pi line. The guard needs neither behavior: it aborts the run AND
72
+ * removes the oversized content from the outgoing message set, so the request
73
+ * cannot be issued and could not carry the content even if it were.
73
74
  */
74
75
  export const DELEGATE_REQUIRED_HOOK_GUARANTEES: readonly DelegateHookGuaranteeName[] = [
75
76
  'context_fires_before_every_model_call',
@@ -36,18 +36,17 @@ import {
36
36
  * - enforcing turn and tool-call limits;
37
37
  * - committing exactly one result package atomically.
38
38
  *
39
- * Measured Pi 0.83 behaviour this design accounts for (see
40
- * `tests/scripted-provider/pi-hook-contract.test.ts`):
39
+ * Measured behavior across the supported Pi lines (see
40
+ * `tests/scripted-provider/pi-hook-contract.test.ts` and `scripts/test-compat.ts`):
41
41
  *
42
- * - Throwing from a `context` handler does NOT stop the provider call. Pi
43
- * catches the exception and dispatches anyway. A throw is therefore never used
44
- * as a barrier here.
45
- * - `ctx.abort()` does not skip the provider call site, but the call receives an
46
- * already-aborted signal and the run terminates. That is the barrier used.
47
- * - Because neither mechanism is a hard admission gate on its own, the guard
48
- * ALSO replaces the offending content in the returned message set. Even a
49
- * provider that ignored the aborted signal could not transmit the content,
50
- * because the content is no longer there.
42
+ * - Throwing from a `context` handler does NOT stop dispatch. Pi catches the
43
+ * exception and continues, so a throw is never used as a barrier here.
44
+ * - `ctx.abort()` blocks transport in both supported modes: Pi 0.81.1-0.83.0
45
+ * invoke the provider with an already-aborted signal, while Pi 0.84.0 skips
46
+ * the provider entry point during signal-aware auth resolution.
47
+ * - The guard ALSO replaces the offending content in the returned message set.
48
+ * Even a non-conforming provider could not transmit the content because the
49
+ * content is no longer there.
51
50
  */
52
51
 
53
52
  const SPILL_DIRNAME = 'spill';
@@ -471,8 +470,8 @@ export default function delegateChildExtension(pi: ExtensionAPI): void {
471
470
  if (verdict.withinBudget) return undefined;
472
471
  const message = `delegate child context reached ${String(verdict.measuredTokens)} input tokens against a ${String(verdict.allowedTokens)}-token allowance on route ${seed.route.qualified_id}, over by ${String(verdict.overageTokens)}; estimator family ${verdict.rateSource.family}, source ${verdict.rateSource.source}, backed=${String(verdict.backed)}, dominant_byte_class=${verdict.dominantByteClass}, rate ${String(verdict.rateSource.effective_rate_bytes_per_token_x100)}/100 B/tok + ${String(verdict.rateSource.affine_f_tokens)} tokens`;
473
472
  latch('provider_context_budget_exhausted', message);
474
- // Barrier one: terminate the run. Measured on Pi 0.83, this hands the
475
- // provider call an already-aborted signal and stops further turns.
473
+ // Barrier one: terminate the run. Depending on the supported Pi line,
474
+ // this skips provider dispatch or hands it an already-aborted signal.
476
475
  ctx.abort();
477
476
  // Barrier two: remove the content itself, so the request could not carry it
478
477
  // even if a provider ignored the aborted signal. Retaining only the first