specpi 0.11.2 → 0.12.0

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.
@@ -0,0 +1,382 @@
1
+ # Delegation protocol: archived version 1 target proposal
2
+
3
+ This is the original target design contract, not the implemented API. The normative
4
+ words **must** and **must not** specify requirements for that stronger future contract.
5
+ Use the [implemented calls/time protocol](protocol.md) and [guide](README.md) for the
6
+ current experimental interface. It does not supply this proposal's hard raw-transport,
7
+ per-provider-attempt or monetary admission guarantees, live web adapter, or alternative
8
+ model routes. The schemas and command examples below must not be submitted as if they
9
+ were the implemented protocol.
10
+
11
+ The current `bounded-pi-sessions-v1` implementation checks public SDK capabilities and uses actual Pi AgentSession workers,
12
+ fresh standard ModelRuntime configuration, explicit parent model/thinking and SDK-visible
13
+ streaming. It does not claim full parent-hook/ephemeral-setting inheritance or hard
14
+ raw-transport, hidden-attempt or invoice limits. It admits only `review` and `scout`,
15
+ with assigned requirement subsets. Its controller survives reloads; the implemented
16
+ guide specifies restart, fixed-root and SDK-settlement boundaries. The custom loop,
17
+ four-profile schema and stronger port contracts below remain historical proposals.
18
+
19
+ See the [archived architecture](design.md) for target policy and
20
+ [evaluation](evaluation.md) for the distinction between current fixtures and unmet
21
+ proof obligations.
22
+
23
+ ## 1. Authority and ownership
24
+
25
+ Separate three objects:
26
+
27
+ 1. **Request:** a parent-model proposal. All fields are untrusted and can only request
28
+ capabilities already granted by the human.
29
+ 2. **Envelope:** a host-created record binding a validated request to identities,
30
+ permissions, sources and resource reservations. A model cannot replace its fields.
31
+ 3. **Result:** a worker's claims plus separately generated host observations. Worker
32
+ prose cannot manufacture host observations or acceptance.
33
+
34
+ Use closed schemas, explicit version numbers, bounded strings and arrays, and rejection
35
+ of unknown fields. Validate input before dispatch and output before collection. This
36
+ is an in-process protocol with structured objects; no HTTP listener, RPC server, or
37
+ message serialization framework is required.
38
+
39
+ ## 2. Parent request
40
+
41
+ One tool named `delegate` accepts this discriminated union:
42
+
43
+ | Operation | Required input | Outcome |
44
+ | ----------- | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
45
+ | `run` | Objective, job proposals, selected input references, requested limits | Admit one batch; return IDs and effective limits, or a deterministic rejection |
46
+ | `status` | Batch ID | Compact states, coverage counts, usage and accounting availability |
47
+ | `collect` | Batch ID, optional job IDs, acknowledged revision cursor and bounded wait | Return applicable payloads after the caller's acknowledged cursor; no destructive dequeue |
48
+ | `follow_up` | Existing job/result binding, correction or new evidence, idempotency key | Admit one additional attempt under the original job limits and deadline |
49
+ | `resolve` | Exact result binding, disposition and per-finding decisions, idempotency key | Record parent adjudication; never authorize a new action |
50
+ | `cancel` | Batch or job ID | Revoke admission and request cancellation; report requests still settling |
51
+
52
+ For stage 1, the single review call may finish within `run`; it uses the same envelope
53
+ and result schema. Stage 2 adds asynchronous return without changing the result contract.
54
+ `collect` can wait at most 30 seconds; it does not create polling timers or new model
55
+ turns. Collect immediately before consuming the relevant evidence, not on a fixed loop.
56
+
57
+ `collect` returns a revision cursor without advancing the caller's acknowledgment.
58
+ Only the next request's explicit cursor acknowledges receipt. Repeating the old cursor
59
+ returns the same applicable payload, so a response lost before consumption can be
60
+ recovered. Results remain available within bounded session retention until resolved,
61
+ discarded or explicitly expired; advertise any expiration rather than silently
62
+ returning an empty successful result.
63
+
64
+ `follow_up` requires `batchId`, `jobId`, `attemptId`, `packetDigest`, `resultRevision`,
65
+ `taskGeneration`, and an idempotency key. It is admitted only from `incomplete` with an
66
+ explicit context gap, or `invalid` with a correctable format error. The controller
67
+ validates that the correction addresses that outcome, that prior provider resources
68
+ have settled, and that the original task/policy bindings, deadline and counters permit
69
+ another attempt. Authority and new source grants are rechecked. An atomic transition
70
+ records the new immutable attempt and debits the **existing** job, batch and session
71
+ ledgers. It does not create another batch or refresh the deadline. The same idempotency
72
+ key and payload return the existing outcome; reuse with a different payload is rejected.
73
+
74
+ Transient transport retries are controller-owned attempts under the same job, not a
75
+ parent `follow_up`. Cancelled, expired, stale, accepted and discarded jobs cannot be
76
+ revived through this operation. A materially new task requires a new admission and
77
+ still consumes the existing session allowance. A renamed request does not authorize
78
+ automatic recovery of a cancelled job.
79
+
80
+ `resolve` binds to those same exact result identity fields and includes a disposition
81
+ (`accept`, `discard`, or `needs_check`) plus decisions for every presented finding
82
+ (`confirmed`, `rejected`, or `needs_check`, with reasons and evidence IDs). The host
83
+ rejects stale revisions and mismatched task generations. An accepted result must have
84
+ required coverage and no unresolved material finding. Accepting a review report means
85
+ its evidence has been adjudicated; it does not assert that the code is ready or that
86
+ confirmed defects have been fixed. Incomplete, invalid and failed results can be
87
+ discarded or held for investigation but cannot be accepted as complete. Apply each
88
+ idempotent resolution atomically. Host state does not infer acceptance from prose,
89
+ collection, silence, or a worker verdict. Finding decisions remain separate from the
90
+ overall disposition. Ordinary task completion still follows SpecPi's existing gates.
91
+
92
+ Proposed request example:
93
+
94
+ ```json
95
+ {
96
+ "version": 1,
97
+ "op": "run",
98
+ "objective": "Resolve two independent causes of the observed regression",
99
+ "jobs": [
100
+ {
101
+ "key": "cache-invalidation",
102
+ "mode": "investigate",
103
+ "question": "Can the cache retain a value after its source changes?",
104
+ "requirements": ["R1"],
105
+ "sourceIds": ["src-cache", "src-cache-callers", "src-cache-tests"],
106
+ "acceptance": "Identify the relevant path and evidence, or state what prevents a conclusion.",
107
+ "decisions": ["Public cache API behavior must remain compatible."],
108
+ "nonGoals": ["Implementing a fix", "Changing public API behavior"],
109
+ "independence": "The parent is separately investigating event ordering.",
110
+ "parentAlternative": "Read these same sources sequentially in the parent.",
111
+ "reason": "A substantial independent source investigation can run while event ordering is inspected."
112
+ }
113
+ ],
114
+ "limits": {
115
+ "maxRequests": 4,
116
+ "deadlineMs": 120000
117
+ }
118
+ }
119
+ ```
120
+
121
+ Source IDs must already refer to a host-validated manifest prepared under the session
122
+ grant. The model does not create that manifest by inventing IDs. A repository capture
123
+ interface validates requested paths before issuing IDs. User-provided attachments or
124
+ parent-selected excerpts get explicit provenance distinct from broker observations.
125
+
126
+ The example's acceptance criteria permit an honest unknown. An instruction to prove a
127
+ preferred conclusion is not an acceptable evidence task.
128
+
129
+ ## 3. Host envelope
130
+
131
+ | Field | Meaning |
132
+ | ------------------------------------------------- | ----------------------------------------------------------------------------------------- |
133
+ | `version` | Protocol version; reject unsupported versions |
134
+ | `batchId`, `jobId`, `attemptId` | Host-generated opaque identities |
135
+ | `policyGeneration` | Immutable human policy and capability selection |
136
+ | `taskGeneration` | Active task identity, requirement revision, scope grant and session epoch |
137
+ | `taskBinding` | Exact card digest and requirement IDs, or an explicit ephemeral requirement set |
138
+ | `packetDigest` | SHA-256 of canonical packet content and selected source manifest |
139
+ | `modelRoute` | Bound model and effective configuration identity; no secrets or raw authorization headers |
140
+ | `capabilities` | Closed broker operations and source/network grants |
141
+ | `limits` | Effective job and batch reservations, deadlines and output limits |
142
+ | `question`, `acceptance`, `decisions`, `nonGoals` | Validated task content |
143
+ | `sources` | Opaque IDs, hashes, media type, coverage, captured location and provenance |
144
+ | `priorAttempt` | Optional parent-approved correction or additional evidence from the same logical job |
145
+
146
+ Canonical serialization must define UTF-8 encoding, key ordering, numeric handling and
147
+ array order. Hash the exact bytes supplied to a worker, including explicit omitted or
148
+ unavailable inputs. A digest detects accidental drift; it is not a signature or proof
149
+ against a compromised host extension. Do not expose reversible configuration secrets
150
+ through fingerprints; use a host-owned opaque generation for sensitive configuration.
151
+
152
+ Fresh context contains the task contract, mode instructions, admitted tools and source
153
+ references. Tool outputs are appended as data. A webpage or source comment cannot
154
+ alter the envelope by resembling its JSON syntax.
155
+
156
+ ## 4. Evidence references
157
+
158
+ Every accepted reference resolves through a host-managed evidence table:
159
+
160
+ | Kind | Required binding | Limit of the evidence |
161
+ | ------------------ | ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
162
+ | Snapshot source | Source ID, exact hash, one-based line or byte range | Supports claims about captured bytes only |
163
+ | Public source | Fetch receipt, final URL, retrieval time, source date when available, extracted range and hash | Retrieval does not establish factual correctness |
164
+ | Parent observation | Receipt ID, origin, observed result, bound source generation when relevant | A parent-authored description is not an independently executed check |
165
+ | Host check receipt | Fixed validator identity, actual outcome, environment/source binding | Valid only for the recorded check and inputs |
166
+
167
+ The worker can cite a receipt ID it received; it cannot register an observation as if
168
+ the host executed it. The host rejects nonexistent IDs, impossible ranges, wrong
169
+ hashes and references outside the grant. Mark exact quotations separately from
170
+ paraphrase or inference. Preserve relevant source-version distinctions.
171
+
172
+ Source text may include malicious instructions. The broker supplies it as bounded tool
173
+ data. The model-facing worker has no tool for shell execution, filesystem mutation,
174
+ credential lookup, delegation, persistent memory, or capability expansion. This is a
175
+ closed tool interface under a trusted process, not a claim of perfect prompt-injection
176
+ resistance or OS containment.
177
+
178
+ ## 5. Worker result and host receipt
179
+
180
+ The worker returns:
181
+
182
+ ```text
183
+ status: complete | partial | needs_context
184
+ answer: bounded answer to the assigned question
185
+ coverage[]:
186
+ requirementId, covered | uncovered | not_applicable, explanation, evidenceIds[]
187
+ findings[]:
188
+ findingId, claim, trigger, consequence,
189
+ observed | inferred | unverified,
190
+ evidenceIds[], contraryEvidenceIds[], limitations
191
+ missing[]:
192
+ neededEvidence, affectedConclusion, reason
193
+ suggestedNextStep: optional bounded text, never an executable action
194
+ ```
195
+
196
+ For review, add severity based on impact and the affected source location. No confidence
197
+ percentage or aggregate self-score is required. For research, distinguish publication
198
+ status and source date, and include evidence against the proposed conclusion. For
199
+ investigation, report failed hypotheses that affect the answer. For consultation,
200
+ prefer a discriminating next experiment to unsupported certainty.
201
+
202
+ The host separately attaches:
203
+
204
+ ```text
205
+ hostStatus: ready | incomplete | invalid | failed | cancelled | expired | stale
206
+ identity: batchId, jobId, attemptId, packetDigest, taskGeneration, resultRevision
207
+ observations: sourceReceipts[], toolOutcomes[], stopReason
208
+ usage: perRequestRecords[], totals, availabilityByCategory
209
+ responseLimits: rawBytesReceived, parsedBytesRetained, overflow, bufferingBoundVerified
210
+ timing: queuedAt, startedAt, settledAt, elapsedMs
211
+ limits: admitted, consumed, reserved, stillSettling
212
+ validation: schema, references, coverage, generation, truncation
213
+ ```
214
+
215
+ The collection response separately supplies `collectionCursor`, a batch event position
216
+ used to acknowledge delivery. It is not the job's `resultRevision`: follow-up and
217
+ resolution bind the exact result revision even if a batch cursor advances because a
218
+ different job produces an event.
219
+
220
+ Persist original assistant/tool message structures in the worker's bounded in-memory
221
+ loop as required by the provider, including opaque signatures. Do not fabricate,
222
+ rewrite or transplant provider reasoning blocks. The parent sees the bounded result,
223
+ not hidden chain-of-thought or the entire worker transcript.
224
+
225
+ For usage, separate input, output, cache reads/writes, tool charges and cost. Preserve
226
+ provider category semantics: Pi's output accounting can already include reasoning,
227
+ so adding reasoning a second time would inflate totals. Distinguish known zero from
228
+ missing data and estimated cost from reported cost. A returned error can still have
229
+ billable usage. Include unsuccessful and cancelled attempts.
230
+
231
+ ## 6. Lifecycle
232
+
233
+ ```mermaid
234
+ stateDiagram-v2
235
+ [*] --> proposed
236
+ proposed --> rejected: admission fails
237
+ proposed --> queued: envelope and reservation created
238
+ queued --> running: capacity available; preconditions rechecked
239
+ queued --> cancelled: grant revoked or user cancels
240
+ running --> ready: complete payload and host validation
241
+ running --> incomplete: partial answer or missing context
242
+ running --> invalid: schema, evidence or truncation error
243
+ running --> failed: provider or broker failure
244
+ running --> cancelled: cancellation
245
+ running --> expired: deadline
246
+ ready --> stale: task or required source binding changes
247
+ ready --> accepted: parent adjudicates
248
+ ready --> discarded: parent rejects result
249
+ incomplete --> discarded
250
+ invalid --> discarded
251
+ failed --> discarded
252
+ ```
253
+
254
+ The diagram shows logical result state. Resource settlement is tracked separately:
255
+ `reserved`, `in_flight`, `settled`, or `uncertain`. `cancelled` does not assert that the
256
+ provider stopped billing. A cancelled or expired request cannot publish a late result.
257
+ An adapter that ignores cancellation retains its slot as still settling; do not start
258
+ new work under the fiction that no request is running.
259
+
260
+ Review output is accepted against its frozen target. On any relevant source change,
261
+ revalidate or mark it stale before use as completion evidence. Research citations may
262
+ remain informative after an unrelated code edit, but requirement/policy drift always
263
+ requires explicit parent reassessment. Scope determines relevance; a changed unrelated
264
+ file must not invalidate every independent research result.
265
+
266
+ Ordinary advancement of a session leaf is not branch navigation. Use a controller
267
+ epoch changed on actual task/policy navigation, not a rule that invalidates jobs after
268
+ each normal parent tool result. Pi 0.84.4 exposes `session_before_switch`,
269
+ `session_before_fork`, `session_before_tree`, `session_tree`, `session_start`, and
270
+ `session_shutdown`; there is no assumed `session_switch` or `session_fork` after-event.
271
+ Before-events may conservatively cancel work even if navigation is later declined.
272
+ Restarting after that is explicit, never a hidden retry.
273
+ [Pinned lifecycle contracts](https://github.com/earendil-works/pi/blob/v0.84.4/packages/coding-agent/src/core/extensions/types.ts#L522).
274
+
275
+ ## 7. Retries, follow-ups, cancellation and deduplication
276
+
277
+ Retry only a classified failure, with its reservation intact. Honor provider backoff
278
+ inside the original deadline. A transport retry after uncertain dispatch can duplicate
279
+ billing; label it accordingly. Do not promise exactly-once provider execution.
280
+
281
+ A `needs_context` follow-up creates a new immutable attempt under the same job ID. It
282
+ includes what changed and why that addresses the gap. The old result remains marked
283
+ incomplete. Call, tool, byte and deadline counters remain attached to the logical job
284
+ and batch; a follow-up cannot reset them. Limit it to one generation initially.
285
+
286
+ Deduplicate only exact active equivalents: same task and policy generation, mode,
287
+ question/acceptance contract, source hashes, model route and relevant settings. Return
288
+ the existing job identity for a repeated request. Do not infer that semantically similar
289
+ questions are equivalent. Cross-session result reuse is out of scope.
290
+
291
+ Cancellation must revoke broker access before awaiting provider settlement. Combine
292
+ the parent signal with job and batch deadlines. Recheck revocation and counters before
293
+ every complete tool invocation and model request. Partial streamed tool arguments are
294
+ never executable. Check terminal `stopReason` as well as rejected promises: Pi streams
295
+ can resolve an assistant message with `error` or `aborted` status. The scheduler's own
296
+ abort state remains authoritative when setup errors obscure cancellation.
297
+
298
+ ## 8. Scheduling and provider interface
299
+
300
+ The following pseudocode expresses ordering, not an available Pi API:
301
+
302
+ ```text
303
+ admit(request):
304
+ validate closed request and current human policy
305
+ bind immutable task, source and model generation
306
+ check exact deduplication key
307
+ reserve batch capacity atomically
308
+ enqueue only ready independent jobs
309
+
310
+ run(job):
311
+ acquire concurrency slot
312
+ recheck authority, generation, deadline and source binding
313
+ build explicit child context and broker schemas
314
+ while another request is allowed:
315
+ reserve next request before dispatch
316
+ response = InferencePort.request(context, admittedOptions, signal,
317
+ admissionBeforeEveryUnderlyingAttempt, rawByteLimit)
318
+ account for response, terminal status and uncertainty
319
+ reject incomplete tool calls or oversized messages
320
+ if final result: validate and stop
321
+ for each complete tool call in this response:
322
+ recheck grant, counters and cancellation
323
+ execute through EvidencePort; append bounded tool result
324
+ settle or quarantine outstanding resources
325
+ publish only if the job generation remains valid
326
+ ```
327
+
328
+ `InferencePort` and `EvidencePort` are proposed injected interfaces. The former must
329
+ be host-owned and preserve request-policy behavior; the latter is the closed broker.
330
+ The Pi 0.84.4 public registry completion facade is insufficient to claim full host
331
+ pipeline parity. [Target architecture compatibility gate](design.md#8-pi-runtime-and-package-boundary).
332
+
333
+ Each underlying inference attempt, including an internal SDK retry, must obtain a
334
+ controller reservation immediately before dispatch. Disable opaque retries when the
335
+ adapter cannot call this admission hook. Initial dispatch and each admitted retry get
336
+ separate attempt receipts; admission must not debit the initial attempt twice. The
337
+ same retry classifier, job retry count, deadlines, provider backoff and batch/session
338
+ ledgers apply. If the adapter cannot enforce this boundary, it cannot claim hard
339
+ attempt limits and must be rejected for the default policy. Silent provider fallback
340
+ to another model is also forbidden.
341
+
342
+ The port's raw-byte ceiling covers the entire decoded application response, including
343
+ stream framing, tool arguments, thinking, text and metadata, across bounded chunks.
344
+ Also bound decompression and transport buffering before handing bytes to a parser;
345
+ reject adapters with opaque unbounded buffering. Stop accumulating and signal abort
346
+ as soon as the next chunk would exceed the allowance. Do not parse or append the
347
+ oversized content, and do not truncate it into an apparently valid final object.
348
+ Record overflow and keep uncertain billing and non-cooperative requests in settlement
349
+ tracking. The byte bound is not a guarantee about provider-side generation or billing.
350
+
351
+ For asynchronous work, the host issues a job-lifetime lease containing immutable
352
+ admitted route data and cancellation hooks. Do not retain a stale invocation-scoped
353
+ extension context after `run` returns. The lease is revoked by actual task/policy
354
+ invalidation, user cancellation, shutdown or deadline; a normal parent tool return
355
+ must not accidentally expire it. Its lifetime and hook behavior are part of the
356
+ proposed host bridge, to be proven by integration fixtures.
357
+
358
+ Serialize tool calls within one worker initially. Parallelism is across admitted jobs.
359
+ If `pi-agent-core` is used to preserve message protocol correctness, explicitly configure
360
+ its tool execution policy; its default is parallel. Limits require pre-call enforcement,
361
+ not only `shouldStopAfterTurn`, which is evaluated after work already occurred.
362
+
363
+ No automatic sibling steering is necessary. If a finding invalidates another job's
364
+ premise, the parent cancels that job and submits an explicitly revised contract, charging
365
+ all abandoned work to the same evaluated task.
366
+
367
+ All batches also debit the session allowance. Starting another batch, changing an
368
+ ephemeral requirement set, or toggling the tool cannot reset consumed usage. A human
369
+ policy change must explicitly renew an exhausted allowance; it cannot erase the
370
+ reported cost of prior work.
371
+
372
+ ## 9. Protocol acceptance tests
373
+
374
+ Before a real provider is enabled, fixtures must demonstrate rejection of forged host
375
+ fields, unsupported versions, oversized or truncated output, nonexistent source IDs,
376
+ stale revisions, duplicate results, recursive delegation, denied tools and exhausted
377
+ reservations. Race tests must cover simultaneous admission, cancellation between a tool
378
+ decision and execution, and late results after task navigation.
379
+
380
+ A valid schema is only the beginning. An answer with valid references can still be
381
+ wrong. Parent adjudication and actual task checks are required for acceptance; a
382
+ protocol receipt must never be displayed as proof that the task itself is correct.