@eir-labs/coltrane 0.24.30 → 0.24.32

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.
Files changed (87) hide show
  1. package/agents/change-verifier.json +4 -2
  2. package/agents/deploy-scout.json +2 -2
  3. package/agents/red-law-reviewer.json +54 -0
  4. package/agents/red-spec-attester.json +53 -0
  5. package/agents/red-spec-builder.json +56 -0
  6. package/agents/red-spec-drafter.json +1 -1
  7. package/agents/spec-reviewer.json +1 -1
  8. package/dist/src/chart.js +4 -0
  9. package/dist/src/chart.js.map +1 -1
  10. package/dist/src/chat_completions_port.d.ts +41 -0
  11. package/dist/src/chat_completions_port.js +221 -0
  12. package/dist/src/chat_completions_port.js.map +1 -0
  13. package/dist/src/claude_invoker.d.ts +18 -0
  14. package/dist/src/claude_invoker.js +771 -22
  15. package/dist/src/claude_invoker.js.map +1 -1
  16. package/dist/src/cli.d.ts +1 -1
  17. package/dist/src/cli.js +49 -8
  18. package/dist/src/cli.js.map +1 -1
  19. package/dist/src/completions_invoker.d.ts +79 -0
  20. package/dist/src/completions_invoker.js +220 -0
  21. package/dist/src/completions_invoker.js.map +1 -0
  22. package/dist/src/composition.d.ts +13 -0
  23. package/dist/src/composition.js +16 -0
  24. package/dist/src/composition.js.map +1 -1
  25. package/dist/src/genome_schema.d.ts +200 -0
  26. package/dist/src/genome_schema.js +37 -0
  27. package/dist/src/genome_schema.js.map +1 -1
  28. package/dist/src/genome_store.d.ts +30 -2
  29. package/dist/src/genome_store.js +51 -8
  30. package/dist/src/genome_store.js.map +1 -1
  31. package/dist/src/index.d.ts +5 -0
  32. package/dist/src/index.js +9 -0
  33. package/dist/src/index.js.map +1 -1
  34. package/dist/src/invoker_selection.d.ts +58 -0
  35. package/dist/src/invoker_selection.js +110 -0
  36. package/dist/src/invoker_selection.js.map +1 -0
  37. package/dist/src/ledger.d.ts +45 -2
  38. package/dist/src/ledger.js +23 -3
  39. package/dist/src/ledger.js.map +1 -1
  40. package/dist/src/mcp.js +2 -2
  41. package/dist/src/mcp.js.map +1 -1
  42. package/dist/src/outputs.d.ts +24 -0
  43. package/dist/src/outputs.js +1 -0
  44. package/dist/src/outputs.js.map +1 -1
  45. package/dist/src/registry.js +16 -0
  46. package/dist/src/registry.js.map +1 -1
  47. package/dist/src/repo_index.d.ts +13 -0
  48. package/dist/src/repo_index.js +90 -10
  49. package/dist/src/repo_index.js.map +1 -1
  50. package/dist/src/reside_backing.d.ts +3 -2
  51. package/dist/src/reside_backing.js +8 -2
  52. package/dist/src/reside_backing.js.map +1 -1
  53. package/dist/src/reuse.d.ts +8 -0
  54. package/dist/src/reuse.js.map +1 -1
  55. package/dist/src/run_deps.d.ts +10 -10
  56. package/dist/src/run_deps.js +25 -15
  57. package/dist/src/run_deps.js.map +1 -1
  58. package/dist/src/runtime.d.ts +205 -109
  59. package/dist/src/runtime.js +908 -145
  60. package/dist/src/runtime.js.map +1 -1
  61. package/dist/src/server.js +148 -45
  62. package/dist/src/server.js.map +1 -1
  63. package/dist/src/server_relay.js +28 -0
  64. package/dist/src/server_relay.js.map +1 -1
  65. package/dist/src/skill_runner.mjs +9 -2
  66. package/dist/src/skill_subprocess.d.ts +20 -1
  67. package/dist/src/skill_subprocess.js +11 -4
  68. package/dist/src/skill_subprocess.js.map +1 -1
  69. package/dist/src/transcript_store.d.ts +14 -0
  70. package/dist/src/transcript_store.js +39 -0
  71. package/dist/src/transcript_store.js.map +1 -0
  72. package/dist/src/turn_loop.d.ts +173 -0
  73. package/dist/src/turn_loop.js +283 -0
  74. package/dist/src/turn_loop.js.map +1 -0
  75. package/dist/src/version.d.ts +1 -1
  76. package/dist/src/version.js +1 -1
  77. package/dist/src/worker.js +6 -0
  78. package/dist/src/worker.js.map +1 -1
  79. package/dist/src/worker_env.d.ts +4 -2
  80. package/dist/src/worker_env.js +42 -0
  81. package/dist/src/worker_env.js.map +1 -1
  82. package/domain_types/change-set.json +33 -22
  83. package/domain_types/red-spec.json +32 -23
  84. package/domain_types/seat-primer.json +65 -0
  85. package/package.json +1 -1
  86. package/standards/build-from-red-spec-v0.json +93 -0
  87. package/standards/draft-red-laws-v0.json +68 -0
@@ -10,10 +10,20 @@ import { type GigConformanceResult } from "./gig_conformance.js";
10
10
  import { type Ledger, type GigUsage } from "./ledger.js";
11
11
  import { type PlacementResolver } from "./placement.js";
12
12
  import type { Depth } from "./pricing.js";
13
+ import type { Effort } from "./genome_schema.js";
13
14
  import type { SkillRecord, EvalRecord } from "./loader.js";
14
15
  export interface AgentInvocationContext {
15
16
  agent: Agent;
16
17
  phase: string;
18
+ /**
19
+ * The ROLE of the chair this invocation seats (Chair.role) — the seat's name within its phase.
20
+ * Threaded so buildPrompt can name the seat, and so two chairs seating the SAME agent in one
21
+ * phase do NOT receive byte-identical prompts: the division of labour a standard declares between
22
+ * them has to reach the model, not live only in the role names. Absent for a hand-built ctx (the
23
+ * text-seal literals and other tests that construct a context directly) — buildPrompt renders the
24
+ * seat only when a role is present, so those prompts stay valid and unchanged.
25
+ */
26
+ role?: string | undefined;
17
27
  gig_id?: string | undefined;
18
28
  /**
19
29
  * THE INSTITUTION'S DATA, delivered to the player it was supplied for: slot name → value, taken
@@ -39,6 +49,8 @@ export interface AgentInvocationContext {
39
49
  onEvent?: (ev: AgentStreamEvent) => void;
40
50
  signal?: AbortSignal | undefined;
41
51
  depth?: Depth | undefined;
52
+ effort?: Effort | undefined;
53
+ max_context_tokens?: number | undefined;
42
54
  realization?: Realization | undefined;
43
55
  venue?: Venue | undefined;
44
56
  substrateMcpConfigs?: Readonly<Record<string, unknown>> | undefined;
@@ -48,6 +60,16 @@ export interface AgentInvocationContext {
48
60
  } | undefined;
49
61
  turn_budget?: number | undefined;
50
62
  turn_reserve?: number | undefined;
63
+ resume?: boolean | undefined;
64
+ resume_keep_prompt?: boolean | undefined;
65
+ prime?: {
66
+ area: string;
67
+ } | undefined;
68
+ fork?: {
69
+ primer_session_id: string;
70
+ stale_paths: readonly string[];
71
+ frontier?: string;
72
+ } | undefined;
51
73
  }
52
74
  export interface AgentStreamEvent {
53
75
  type: string;
@@ -72,6 +94,15 @@ export type GigProgressEvent = {
72
94
  /** types actually SEALED */
73
95
  output_types: string[];
74
96
  duration_ms: number;
97
+ /**
98
+ * #seat-metrics — the ms from chair start to the FIRST write the chair's child emitted (a
99
+ * tool_use whose tool is Write/Edit/MultiEdit/NotebookEdit), and the context the seat carried
100
+ * then (input + cache_read + cache_creation of the last assistant usage BEFORE that write).
101
+ * A chair that never wrote records BOTH as null — present, never absent, never a stand-in 0,
102
+ * so "wrote at t=0" and "never wrote / never measured" cannot collide.
103
+ */
104
+ first_write_ms: number | null;
105
+ context_tokens_at_first_write: number | null;
75
106
  /** #243 — types the chair's output_contract PROMISED. Equal to output_types when the
76
107
  * chair delivered everything; the difference is what `missing_output_types` names. */
77
108
  promised_output_types?: string[];
@@ -80,6 +111,37 @@ export type GigProgressEvent = {
80
111
  /** #240 — `*_sha` fields the engine could not tie to any consumed input or the gig
81
112
  * payload. Sealed as "" rather than guessed; listed here so the gap is visible. */
82
113
  unresolved_sha_fields?: string[];
114
+ /** #seat-effort (O5) — the reasoning effort the seat actually ran at, as resolved by the
115
+ * runtime (dispatch ▷ agent ▷ tier ▷ medium). Present for a model chair; absent for a skill
116
+ * chair, which runs no model at an effort. */
117
+ effort?: Effort;
118
+ /** contract-chair-session-continuity-v1 (O4) — the seat's `claude` session id (the uuid
119
+ * derived from (gig_id, role)) and whether THIS invocation RESUMED it (an amend round) rather
120
+ * than opening it. Present for a model chair; absent for a skill chair, which runs no session. */
121
+ session_id?: string;
122
+ resumed?: boolean;
123
+ /** contract-amend-resume-prompt-v1 (F1) — set when this seat's amend RESUME found no session
124
+ * and fell back COLD (a fresh --session-id spawn with the full prompt). The fallback never
125
+ * fails the chair, but it is never silent either: this records that a resume was ATTEMPTED and
126
+ * did not happen, rather than `resumed: true` claiming a continuation that never occurred.
127
+ * Absent when no fallback fired. */
128
+ resume_fallback?: boolean;
129
+ /** contract-seat-primer-v1 (O3) — a forked chair records the primer it warm-started from: the
130
+ * seat-primer record's id, the primer seat's own session_id, and the commit it sealed at.
131
+ * Present only when the fork actually resumed the primer (absent on a cold fallback). */
132
+ forked_from?: {
133
+ id: string;
134
+ session_id: string;
135
+ commit: string;
136
+ };
137
+ /** contract-seat-primer-v1 (O4) — the primer files whose working-tree blob differs from the
138
+ * blob recorded at priming (empty when none changed). Named in the fork's prompt too. Present
139
+ * on a successful fork. */
140
+ primer_stale_paths?: string[];
141
+ /** contract-seat-primer-v1 (F1/F2) — the fork could not warm-start (no primer for this
142
+ * agent+area → "primer_missing", or the primer's session could not be resumed → a reason
143
+ * naming that session). The chair ran COLD and did not fail; this records why, never silently. */
144
+ fork_fallback?: string;
83
145
  } | {
84
146
  type: "chair_failed";
85
147
  phase: string;
@@ -172,25 +234,25 @@ export interface RunDeps {
172
234
  skill_dirs?: ReadonlyMap<string, string> | undefined;
173
235
  evals?: ReadonlyMap<string, EvalRecord> | undefined;
174
236
  /**
175
- * Optional cost-budget input. When omitted (default), no budget enforcement
176
- * runs — preserving v0 back-compat. When present, the runtime tracks
177
- * per-gig BudgetState matching budget-state.json schema: balance =
178
- * opening - spent + credit.
237
+ * Optional cost-budget input, in US DOLLARS ({ max_usd }). When omitted (default), or when
238
+ * present without a `max_usd`, no dollar enforcement runs — preserving v0 back-compat.
179
239
  *
180
- * The cycle is RESERVE SETTLE (#232). At chair-prep the runtime computes
181
- * cost-of-append (base + k*size(input)) and compares it against
182
- * `balance - reserved`; short BudgetExhausted. Passing chairs RESERVE the
183
- * cost. `spent` moves only when a chair's invocation SUCCEEDS, which is what
184
- * the contract always claimed and what the code did not do: prep runs
185
- * eagerly for the whole ready batch, so a batch member tripping the gate
186
- * used to leave every earlier member of that batch charged for work no
187
- * invoker ever started.
240
+ * When a ceiling is set the runtime tracks per-gig settled spend (the invokers' own
241
+ * `result`-event USD) and, at each dispatch-batch boundary (O2), refuses to start the NEXT
242
+ * batch once settled spend reaches `max_usd` the batch already running is never interrupted.
243
+ * There is no pre-invocation reservation and no append-unit proxy: payload size does not gate.
188
244
  *
189
- * The final BudgetState is returned in GigResult.budget_state, and is also
190
- * attached to a BudgetExhausted / mid-gig error so a FAILED gig can still
191
- * report what it cost.
245
+ * The final BudgetState is returned in GigResult.budget_state, and is also attached to a
246
+ * BudgetExhausted / mid-gig error so a FAILED gig can still report what it cost.
192
247
  */
193
248
  budget?: BudgetInput | undefined;
249
+ /**
250
+ * O6 — the gig reserve POOL, in turns, decoupled from any money budget. When set it opens the
251
+ * pool and OVERRIDES `Standard.reserve_pool` deterministically (no max, no sum). Absent → the
252
+ * standard default, then 0 (no pool). A turn pool in play yields a BudgetState even with no
253
+ * dollar ceiling: its pool fields are filled, its dollar fields omitted.
254
+ */
255
+ turn_pool?: number | undefined;
194
256
  onProgress?: ((ev: GigProgressEvent) => void) | undefined;
195
257
  gig_id?: string | undefined;
196
258
  /**
@@ -220,6 +282,20 @@ export interface RunDeps {
220
282
  * the thing that actually spends. Absent = each agent's own `depth_profile` stands.
221
283
  */
222
284
  depth?: Depth | undefined;
285
+ /**
286
+ * #seat-effort — the reasoning effort this gig was dispatched at, threaded to the resolver so
287
+ * dispatch effort wins over the agent's declared effort and the tier default (resolveEffort).
288
+ * Absent = no dispatch effort, so the agent's own `effort` or its tier default stands. Sibling of
289
+ * `depth`; the dispatch door threads it beside `depth` (src/server.ts).
290
+ */
291
+ effort?: Effort | undefined;
292
+ /**
293
+ * contract-seat-context-ceiling-v1 (O2) — the per-round context ceiling this gig was dispatched at,
294
+ * threaded to the resolver so a dispatch ceiling wins over the agent's declared `max_context_tokens`
295
+ * (resolveMaxContextTokens). Absent = no dispatch ceiling, so the agent's own field — or NONE — stands.
296
+ * Sibling of `effort`; the dispatch door threads it beside `effort` (src/server.ts).
297
+ */
298
+ max_context_tokens?: number | undefined;
223
299
  /**
224
300
  * Set by `runChart` (src/chart.ts) when this gig is a movement of an arrangement. Absent = a
225
301
  * plain single-standard run, byte-identical to every run before charts existed.
@@ -376,49 +452,41 @@ export interface RunDeps {
376
452
  * the room declines to populate (an empty read-only workspace) and no git credential is minted.
377
453
  */
378
454
  repoUrl?: string | undefined;
455
+ /**
456
+ * The directory whose git objects the SEAL stamps law and change addresses from (records-by-address,
457
+ * contract-records-by-address-v1). When a sealed `red-spec` record carries `laws` or a `change-set`
458
+ * record carries `changes`, the seal replaces those entries with ones the engine stamps from git in
459
+ * THIS directory — `blob_sha`/`tests` for a law, `blob_sha`/`patch_sha256`/`bytes` for a change —
460
+ * via `stampLawAddresses`/`stampChangeAddresses`. Stamping NEVER reads `process.cwd()`: a record
461
+ * carrying `laws`/`changes` sealed with no `tree_root` refuses with `tree_root_unknown`. Absent AND
462
+ * the sealed records carry only `diffs` (the pre-migration shape) = no stamping, byte-identical to
463
+ * before this field existed. Every door that runs a gig names the tree it stamps from; it is never
464
+ * an ambient host path.
465
+ */
466
+ tree_root?: string | undefined;
379
467
  }
380
468
  /**
381
- * Per-gig cost-budget input. Honors budget-state.json schema (PR #56). Only
382
- * `opening` is required for v0 enforcement; the rest are recomputed.
383
- *
384
- * COST FORMULA (v0, tunable):
385
- * cost = base_cost + k * size_bytes(input)
386
- * defaults: base_cost = 1, k = 0.1
469
+ * Per-gig cost-budget input. A budget is US DOLLARS (operator decision 2026-09-16): the
470
+ * single field is `max_usd`, the per-gig dollar ceiling.
387
471
  *
388
- * Where size_bytes(input) = JSON.stringify(canonical context).length.
472
+ * ENFORCEMENT (O2). The ceiling is checked against SETTLED spend — the invokers' own
473
+ * `result`-event `total_cost_usd`, reconciled at each dispatch-batch boundary — never a
474
+ * pre-invocation estimate. A batch already running is allowed to finish; the NEXT batch does
475
+ * not start once settled spend reaches `max_usd`. There is no append-unit proxy and no
476
+ * per-chair reservation: payload size does not decide whether a chair runs (I8/O3).
389
477
  *
390
- * WHAT THIS IS AND IS NOT (#233). `opening`/`spent`/`balance` are SYNTHETIC APPEND UNITS
391
- * see `BudgetState.unit`. They are not dollars and were never converted to dollars; an
392
- * `opening: 1000` that reads like a dollar figure to an operator is a coincidence of scale.
393
- * The real, settled figure is `BudgetState.settled_usd`, reconciled from the model's own
394
- * `result` events at each batch boundary. Two honest limits on the synthetic gate:
478
+ * The retired append-unit knobs (`opening`, `base_cost`, `k`) and the retired `pool` field are
479
+ * gone. The reserve pool now opens from `RunDeps.turn_pool` (else `Standard.reserve_pool`),
480
+ * needs no money budget, and is orthogonal to the dollar ledger a draw moves
481
+ * `BudgetState.pool_remaining` only, never `spent_usd`.
395
482
  *
396
- * 1. It is a proxy for prompt size, not a price. It has no model tier, no output side, no
397
- * skills/charter/schema bytes only the agent slug, phase, consumed input CONTENT and
398
- * the gig payload. It is a rate limiter on context growth, nothing more.
399
- * 2. A USD figure cannot gate a chair before that chair runs, because `prepareChair` runs
400
- * for the WHOLE ready batch before any invocation — a chair cannot see its batch
401
- * siblings' settled cost. So reconciliation happens at BATCH BOUNDARIES, and any dollar
402
- * bound built on it would be a cap plus one batch of slack, never a hard stop. No such
403
- * bound is wired: there is no per-chair dollar estimator, and inventing one would be
404
- * guessing. `settled_usd` reports; it does not enforce.
483
+ * `max_usd` is optional at the type level so a drain with no ceiling can pass `{}` ("no
484
+ * enforcement"); every door that accepts a budget validates it (a positive finite number)
485
+ * before anything runs.
405
486
  */
406
487
  export interface BudgetInput {
407
- opening: number;
408
- /** base cost per agent invocation, in append units. Default 1. */
409
- base_cost?: number;
410
- /** per-byte multiplier on consumed-input size, in append units. Default 0.1. */
411
- k?: number;
412
- /**
413
- * #turn-budget — the gig-level reserve POOL, in turns: a shared quantity a budget-exhausted chair
414
- * draws from, capped per chair by its own `turn_reserve`. This dispatch-payload value is the
415
- * PRIMARY source and OVERRIDES `Standard.reserve_pool` deterministically when both are present
416
- * (no max, no sum). Orthogonal to `opening`/`base_cost`/`k` — those are append-units, this is
417
- * turns, and a draw moves `pool_remaining` only, never `spent`/`balance`. Absent → the standard
418
- * default, then 0 (no pool). Distinct from 0 only in that 0 could equally be an authored empty
419
- * pool; either way a chair reaching for a reserve finds nothing and is recorded as starved.
420
- */
421
- pool?: number;
488
+ /** The per-gig ceiling, in US dollars. Absent → no dollar enforcement. */
489
+ max_usd?: number;
422
490
  }
423
491
  /**
424
492
  * #turn-budget — one attributable draw against the gig reserve pool. `denied` marks a chair that
@@ -434,54 +502,48 @@ export interface ReserveDraw {
434
502
  denied?: boolean;
435
503
  }
436
504
  /**
437
- * Per-gig budget snapshot. Mirrors fields of domain_types/budget-state.json
438
- * (PR #56) that are runtime-tractable in v0. balance = opening - spent + credit.
505
+ * Per-gig budget snapshot. Present whenever a dollar ceiling OR a turn pool is in play (O6):
506
+ * the POOL fields (`pool_remaining`, `draws`) are filled regardless of money, and the DOLLAR
507
+ * fields (`max_usd`, `spent_usd`, `unit: "usd"`) only when a ceiling is set.
439
508
  *
440
- * The `agent_state` mirrors the budget-state.json enum:
441
- * active — currently spending, balance > cost-of-next-append
442
- * yielding — below cost-of-next-append, paused (used when partial)
443
- * depleted — balance <= 0 OR < cost-of-next-append, hard stop
509
+ * The `agent_state` enum:
510
+ * active — running normally
511
+ * yielding — a seated chair is currently drawing its reserve (D1)
512
+ * depleted — a drawing chair spent its reserve+pool without landing, OR the dollar
513
+ * ceiling stopped the next batch
444
514
  * awaiting_grade — work shipped, external grader contacted (v0 unused)
445
- * settled — cycle closed, closing populated (v0 set on success)
515
+ * settled — cycle closed on success
446
516
  */
447
517
  export interface BudgetState {
448
- opening: number;
449
- /** Cost of chairs that ACTUALLY RAN AND SUCCEEDED. Reserved-but-unsettled cost is not here. */
450
- spent: number;
451
- credit: number;
452
- balance: number;
453
518
  agent_state: "active" | "yielding" | "depleted" | "awaiting_grade" | "settled";
454
519
  /** Slug of the agent whose invocation tripped depletion. null when solvent. */
455
520
  depleted_agent: string | null;
456
- /** Wall-clock when balance first crossed below cost-of-next-append. null while solvent. */
521
+ /** Wall-clock when the gig crossed into depletion. null while solvent. */
457
522
  depleted_at: string | null;
458
- base_cost: number;
459
- k: number;
460
523
  /**
461
- * #233 the denomination of opening/spent/balance/base_cost/k, stated rather than assumed.
462
- * These are a synthetic proxy for consumed context bytes. They are NOT dollars, and nothing
463
- * converts between the two. Read `settled_usd` for money.
524
+ * The dollar ceiling this gig runs under, echoed onto the snapshot. Present ONLY when a
525
+ * ceiling is set (a turn-pool-only gig omits it).
464
526
  */
465
- unit: "append-units";
527
+ max_usd?: number;
466
528
  /**
467
- * #233 — REAL settled model spend for this gig so far, in USD, reconciled from the invokers'
468
- * own `result` events at each dispatch-batch boundary. This is the number `src/ledger.ts`
469
- * calls settled spend; the budget gate above never used it, even though it was live and
470
- * in-scope. Reporting only — see the BudgetInput docstring for why it cannot gate.
471
- * 0 when no invoker reported cost (stubbed invokers, skill-only gigs).
529
+ * REAL settled model spend for this gig so far, in USD, reconciled from the invokers' own
530
+ * `result` events at each dispatch-batch boundary. This is what the ceiling is enforced
531
+ * against (O2). Present ONLY under a ceiling; 0 when no invoker reported cost.
472
532
  */
473
- settled_usd: number;
533
+ spent_usd?: number;
534
+ /** The denomination of the dollar fields, stated rather than assumed. Present ONLY under a ceiling. */
535
+ unit?: "usd";
474
536
  /**
475
- * #turn-budget — turns remaining in the gig reserve pool (Item 2). Seeded from the dispatch
476
- * `pool` (else `Standard.reserve_pool`, else 0), drawn down as chairs cross into reserve, never
477
- * negative and never re-increased in v0 (strict draw-down, no preemption). Orthogonal to the
478
- * append-unit ledger above: a draw moves ONLY this number.
537
+ * Turns remaining in the gig reserve pool. Seeded from `RunDeps.turn_pool` (else
538
+ * `Standard.reserve_pool`, else 0), drawn down as chairs cross into reserve, never negative and
539
+ * never re-increased in v0 (strict draw-down). Orthogonal to the dollar ledger: a draw moves
540
+ * ONLY this number, never `spent_usd`.
479
541
  */
480
542
  pool_remaining: number;
481
543
  /**
482
- * #turn-budget — the attributable draw ledger (Item 2). One record per chair that reached for a
483
- * reserve, granted or denied, so a post-run reader can see who drew, how much, and what the pool
484
- * had left — and so a starved chair is visible rather than a silent no-op.
544
+ * The attributable draw ledger. One record per chair that reached for a reserve, granted or
545
+ * denied, so a post-run reader can see who drew, how much, and what the pool had left — and so
546
+ * a starved chair is visible rather than a silent no-op.
485
547
  */
486
548
  draws: ReserveDraw[];
487
549
  }
@@ -728,39 +790,72 @@ export declare class GigAborted extends Error {
728
790
  /** The human-readable cause behind an AbortSignal, whatever shape the aborter used. */
729
791
  export declare function abortReasonText(signal: AbortSignal): string;
730
792
  /**
731
- * Raised when a gig's budget cannot cover the next agent's cost-of-append.
732
- * Carries the agent_slug, the available balance, and the required cost so
733
- * the caller can render the exact reason. The in-memory BudgetState is
734
- * also attached for downstream telemetry.
793
+ * Raised when a gig's SETTLED dollar spend reaches its `max_usd` ceiling and the next batch may
794
+ * not start (O2/O5). Denominated in dollars: `spent_usd`, `max_usd`, `unit: "usd"`, and a message
795
+ * that names the amounts with `$` and `usd` — never append-units. The in-memory BudgetState is
796
+ * attached so a caller can render the full snapshot.
735
797
  */
736
798
  export declare class BudgetExhausted extends Error {
737
799
  readonly agent_slug: string;
738
- readonly balance: number;
739
- readonly cost: number;
800
+ readonly spent_usd: number;
801
+ readonly max_usd: number;
802
+ readonly unit: "usd";
740
803
  readonly state: BudgetState;
741
- constructor(agent_slug: string, balance: number, cost: number, state: BudgetState);
804
+ constructor(agent_slug: string, spent_usd: number, max_usd: number, state: BudgetState);
742
805
  }
743
806
  /**
744
- * Cost-of-append for an agent invocation, in synthetic append units (see BudgetState.unit).
745
- * Deterministic function of the input context size same input same cost. Keeps cost
746
- * calculation inside the runtime (not the invoker) so budget enforcement cannot be spoofed by
747
- * a misbehaving invoker.
748
- *
749
- * #233 — this used to serialize `input_ids`: the UUIDs of the upstream outputs a chair
750
- * consumes, not their data. An upstream output contributed exactly 36 bytes whether it was a
751
- * one-line signal or a 40-page draft, so the proxy was not even monotonic in the thing that
752
- * drives real cost. It now measures the CONTENT the invoker actually receives.
753
- *
754
- * Still excluded, honestly: resolved skills, the agent charter, type schemas, model tier,
755
- * max_tool_calls, and the entire output side. This is a rate limiter on consumed context, not
756
- * a price. Money is `BudgetState.settled_usd`.
807
+ * Raised when a gig under a dollar ceiling cannot VERIFY its spend (F3): a settled invocation
808
+ * reported usage but no `total_cost_usd`, so the runtime cannot know whether the next batch is
809
+ * affordable. Fail-closed no further batch starts. `reason` is the typed `budget_unverifiable`,
810
+ * and the message names the chairs whose dollar spend is unknown.
757
811
  */
758
- export declare function computeAppendCost(ctx: {
759
- agent: Agent;
760
- phase: string;
761
- inputs: readonly OutputRecord[];
762
- gig_input: Record<string, unknown>;
763
- }, base_cost: number, k: number): number;
812
+ export declare class BudgetUnverifiable extends Error {
813
+ readonly reason = "budget_unverifiable";
814
+ readonly chairs: readonly string[];
815
+ readonly state: BudgetState;
816
+ constructor(chairs: readonly string[], state: BudgetState);
817
+ }
818
+ /**
819
+ * The model that DID a chair's work: the model that WROTE the most output tokens across the chair's
820
+ * `modelUsage` breakdown — NOT whichever key the CLI listed first. Claude Code spends a small
821
+ * background call on a fast model before the real work, and that model is listed FIRST while writing
822
+ * almost nothing, so a first-key stamp names a model that did none of the chair's work. Output
823
+ * tokens are the honest signal of which model produced the answer. Ties break on the model id
824
+ * (lexicographic ascending), so the stamp is deterministic regardless of the breakdown's key order.
825
+ * An empty map (a transport that reported no per-model breakdown) yields undefined — nothing to
826
+ * stamp, exactly as before.
827
+ */
828
+ export declare function workingModel(outputByModel: ReadonlyMap<string, number>): string | undefined;
829
+ type LawAddress = {
830
+ path: string;
831
+ commit: string;
832
+ blob_sha?: string;
833
+ tests?: string[];
834
+ };
835
+ type ChangeAddress = {
836
+ path: string;
837
+ base: string;
838
+ blob_sha?: string;
839
+ patch_sha256?: string;
840
+ bytes?: number;
841
+ };
842
+ /**
843
+ * Stamp each law's `blob_sha` (`git rev-parse <commit>:<path>`) and `tests` (the it/test titles in
844
+ * that blob, in file order) from a supplied `{path, commit}`, reading git in `tree_root`.
845
+ * REFUSALS: no `tree_root` → `tree_root_unknown` (never a `process.cwd()` fallback); an address that
846
+ * does not resolve (unknown commit, or a path absent at that commit) → `law_record_unresolvable`
847
+ * naming `path@commit`; a seat-supplied `blob_sha`/`tests` that disagrees with git → `law_bytes_mismatch`
848
+ * naming the path and field.
849
+ */
850
+ export declare function stampLawAddresses(laws: readonly LawAddress[], tree_root: string | undefined): Array<Required<LawAddress>>;
851
+ /**
852
+ * Stamp each change's `blob_sha` (`git hash-object` of the file in `tree_root`, or the literal
853
+ * `"deleted"` when the file is absent from the tree), `patch_sha256` (sha256 of `git diff <base> --
854
+ * <path>` in `tree_root`) and `bytes` (that diff's length) from a supplied `{path, base}`.
855
+ * REFUSALS: no `tree_root` → `tree_root_unknown`; a seat-supplied `blob_sha`/`patch_sha256`/`bytes`
856
+ * that disagrees with git → `law_bytes_mismatch` naming the path and field.
857
+ */
858
+ export declare function stampChangeAddresses(changes: readonly ChangeAddress[], tree_root: string | undefined): Array<Required<ChangeAddress>>;
764
859
  /**
765
860
  * The structural identity of a pipeline: the standard's phase graph plus each bound agent's
766
861
  * type surface. Deterministic across machines for a given structure.
@@ -776,3 +871,4 @@ export declare function genomeHash(standard: Standard): string;
776
871
  * this record satisfy this declared type" differently is the #263 defect wearing a new hat. */
777
872
  export declare function outputSatisfiesType(output: OutputRecord, declared: string): boolean;
778
873
  export declare function runGig(standard: Standard, gigInput: Record<string, unknown>, deps: RunDeps): Promise<GigResult>;
874
+ export {};