@tangle-network/agent-eval 0.190.1 → 0.192.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.
Files changed (167) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/dist/adapters/http.d.ts +2 -2
  3. package/dist/{agent-profile-DNV_U6QR.d.ts → agent-profile-DDfIjdyS.d.ts} +3 -3
  4. package/dist/{agent-profile-DNV_U6QR.d.ts.map → agent-profile-DDfIjdyS.d.ts.map} +1 -1
  5. package/dist/analyst/index.d.ts +11 -11
  6. package/dist/analyst/index.js +5 -5
  7. package/dist/{insight-report-CvPkEIcC.d.ts → analyze-runs-CPiKLJFs.d.ts} +73 -3
  8. package/dist/analyze-runs-CPiKLJFs.d.ts.map +1 -0
  9. package/dist/{attribute-vocabulary-DLJ6303h.d.ts → attribute-vocabulary-CcXqHODT.d.ts} +23 -12
  10. package/dist/attribute-vocabulary-CcXqHODT.d.ts.map +1 -0
  11. package/dist/{benchmark-command-BXIr_k8D.js → benchmark-command-C458yEFK.js} +9 -9
  12. package/dist/{benchmark-command-BXIr_k8D.js.map → benchmark-command-C458yEFK.js.map} +1 -1
  13. package/dist/benchmarks/index.d.ts +3 -3
  14. package/dist/benchmarks/index.js +3 -3
  15. package/dist/campaign/index.d.ts +6 -6
  16. package/dist/campaign/index.js +8 -7
  17. package/dist/{campaign-B7q74uIh.js → campaign-BVQVBEfH.js} +13 -325
  18. package/dist/campaign-BVQVBEfH.js.map +1 -0
  19. package/dist/{campaign-evidence-D40-LHIL.js → campaign-evidence-DcQiYhJI.js} +18 -154
  20. package/dist/campaign-evidence-DcQiYhJI.js.map +1 -0
  21. package/dist/claim-V9Zqbq0J.js +54 -0
  22. package/dist/claim-V9Zqbq0J.js.map +1 -0
  23. package/dist/cli.js +99 -2
  24. package/dist/cli.js.map +1 -1
  25. package/dist/client-wFyDisxi.d.ts +236 -0
  26. package/dist/client-wFyDisxi.d.ts.map +1 -0
  27. package/dist/contract/index.d.ts +10 -11
  28. package/dist/contract/index.js +10 -140
  29. package/dist/contract/index.js.map +1 -1
  30. package/dist/{default-registry-B5HrwrPM.d.ts → default-registry-DdqA_-_o.d.ts} +6 -6
  31. package/dist/{default-registry-B5HrwrPM.d.ts.map → default-registry-DdqA_-_o.d.ts.map} +1 -1
  32. package/dist/{default-registry-16I-Bxlf.js → default-registry-xMLX160E.js} +3 -3
  33. package/dist/{default-registry-16I-Bxlf.js.map → default-registry-xMLX160E.js.map} +1 -1
  34. package/dist/{define-agent-eval-DPizhHfy.js → define-agent-eval-DQuos3Aw.js} +30 -113
  35. package/dist/define-agent-eval-DQuos3Aw.js.map +1 -0
  36. package/dist/{define-agent-eval-DblGedQk.d.ts → define-agent-eval-DcludNJS.d.ts} +25 -38
  37. package/dist/define-agent-eval-DcludNJS.d.ts.map +1 -0
  38. package/dist/diagnosis/index.d.ts +2 -2
  39. package/dist/diagnosis/index.js +1 -1
  40. package/dist/{dspy-rlm-engine-Cs5LzJ-f.js → dspy-rlm-engine-BX34vPVY.js} +3 -3
  41. package/dist/{dspy-rlm-engine-Cs5LzJ-f.js.map → dspy-rlm-engine-BX34vPVY.js.map} +1 -1
  42. package/dist/{engine-BkLCnZQX.d.ts → engine-C1DIAEpn.d.ts} +4 -4
  43. package/dist/{engine-BkLCnZQX.d.ts.map → engine-C1DIAEpn.d.ts.map} +1 -1
  44. package/dist/evaluation.d.ts +2 -2
  45. package/dist/{exact-types-CfpP2A4Z.d.ts → exact-types-KGxBWH4b.d.ts} +2 -2
  46. package/dist/{exact-types-CfpP2A4Z.d.ts.map → exact-types-KGxBWH4b.d.ts.map} +1 -1
  47. package/dist/experiment/index.d.ts +1 -1
  48. package/dist/experiment/index.js +2 -1
  49. package/dist/experiment/index.js.map +1 -1
  50. package/dist/{external-optimizer-process-BnSmrkgL.js → external-optimizer-process-D-Sab4v3.js} +3 -62
  51. package/dist/external-optimizer-process-D-Sab4v3.js.map +1 -0
  52. package/dist/{external-optimizer-subprocess-kbcPu5po.js → external-optimizer-subprocess-kbqC-iWf.js} +65 -27
  53. package/dist/external-optimizer-subprocess-kbqC-iWf.js.map +1 -0
  54. package/dist/{extract-usage-BrQ8mCLX.js → extract-usage-DFATEuWW.js} +2 -2
  55. package/dist/{extract-usage-BrQ8mCLX.js.map → extract-usage-DFATEuWW.js.map} +1 -1
  56. package/dist/{feedback-trajectory-BYjh7NEM.d.ts → feedback-trajectory-BXCGTRkz.d.ts} +3 -3
  57. package/dist/{feedback-trajectory-BYjh7NEM.d.ts.map → feedback-trajectory-BXCGTRkz.d.ts.map} +1 -1
  58. package/dist/hosted/index.d.ts +66 -6
  59. package/dist/hosted/index.d.ts.map +1 -1
  60. package/dist/hosted/index.js +2 -2
  61. package/dist/{index-I4UJGRno.d.ts → index-Bj96W0jZ.d.ts} +28 -2
  62. package/dist/{index-I4UJGRno.d.ts.map → index-Bj96W0jZ.d.ts.map} +1 -1
  63. package/dist/{index-2e_MTznj.d.ts → index-DBoXFaz0.d.ts} +6 -6
  64. package/dist/{index-2e_MTznj.d.ts.map → index-DBoXFaz0.d.ts.map} +1 -1
  65. package/dist/{index-CWoIJHmy.d.ts → index-DNVzu9Vv.d.ts} +10 -104
  66. package/dist/index-DNVzu9Vv.d.ts.map +1 -0
  67. package/dist/{index-CJv56rhX.d.ts → index-DwQxdWve.d.ts} +351 -135
  68. package/dist/index-DwQxdWve.d.ts.map +1 -0
  69. package/dist/index.d.ts +16 -17
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +11 -11
  72. package/dist/jev.d.ts +2 -2
  73. package/dist/{journal-c3qY0SDP.js → journal-DvKCvjty.js} +94 -2
  74. package/dist/{journal-c3qY0SDP.js.map → journal-DvKCvjty.js.map} +1 -1
  75. package/dist/{kind-factory-ByZeXDqF.js → kind-factory-CdPPHtGZ.js} +10 -26
  76. package/dist/kind-factory-CdPPHtGZ.js.map +1 -0
  77. package/dist/ledger-core/index.d.ts +2 -2
  78. package/dist/ledger-core/index.js +2 -2
  79. package/dist/{llm-judge-BnxAv7ed.js → llm-judge-Z6MkTkd0.js} +1805 -2012
  80. package/dist/llm-judge-Z6MkTkd0.js.map +1 -0
  81. package/dist/{matrix-CNypzP-v.d.ts → matrix-CQMMrEQ5.d.ts} +2 -2
  82. package/dist/{matrix-CNypzP-v.d.ts.map → matrix-CQMMrEQ5.d.ts.map} +1 -1
  83. package/dist/multishot/golden/index.d.ts +1 -1
  84. package/dist/multishot/index.d.ts +2 -2
  85. package/dist/openapi.json +1 -1
  86. package/dist/{otel-spans-CQY1pNiN.js → otel-spans-DS7t1t1J.js} +8 -19
  87. package/dist/otel-spans-DS7t1t1J.js.map +1 -0
  88. package/dist/otlp-attributes-D9ptWaIJ.js +53 -0
  89. package/dist/otlp-attributes-D9ptWaIJ.js.map +1 -0
  90. package/dist/{prime-protocol-Fwvctmhm.d.ts → prime-protocol-T0i6xcAs.d.ts} +2 -2
  91. package/dist/{prime-protocol-Fwvctmhm.d.ts.map → prime-protocol-T0i6xcAs.d.ts.map} +1 -1
  92. package/dist/{produced-state-BXjXJHJT.js → produced-state-CVmCPQDJ.js} +3 -3
  93. package/dist/{produced-state-BXjXJHJT.js.map → produced-state-CVmCPQDJ.js.map} +1 -1
  94. package/dist/{registry-mAQVtuLx.d.ts → registry-Bu3lNole.d.ts} +3 -3
  95. package/dist/{registry-mAQVtuLx.d.ts.map → registry-Bu3lNole.d.ts.map} +1 -1
  96. package/dist/rl.d.ts +1 -1
  97. package/dist/rl.js +1 -1
  98. package/dist/{run-record-DnMFyg_g.js → run-record-tNnlQIrD.js} +2 -10
  99. package/dist/{run-record-DnMFyg_g.js.map → run-record-tNnlQIrD.js.map} +1 -1
  100. package/dist/search-ledger-Ck7tok0h.js +1517 -0
  101. package/dist/search-ledger-Ck7tok0h.js.map +1 -0
  102. package/dist/search-ledger-file-DY0AXX3W.js +27 -0
  103. package/dist/search-ledger-file-DY0AXX3W.js.map +1 -0
  104. package/dist/search-shipper-BG182p-U.js +781 -0
  105. package/dist/search-shipper-BG182p-U.js.map +1 -0
  106. package/dist/{semantic-concept-judge-ClB73cei.js → semantic-concept-judge-Bg-560H0.js} +4 -4
  107. package/dist/{semantic-concept-judge-ClB73cei.js.map → semantic-concept-judge-Bg-560H0.js.map} +1 -1
  108. package/dist/{skillopt-optimization-method-l2vDBtKp.js → skillopt-optimization-method-DoayuM6D.js} +6 -5
  109. package/dist/{skillopt-optimization-method-l2vDBtKp.js.map → skillopt-optimization-method-DoayuM6D.js.map} +1 -1
  110. package/dist/{statistical-heldout-CLpjYffJ.d.ts → statistical-heldout-C1Ej5Ce8.d.ts} +2 -2
  111. package/dist/{statistical-heldout-CLpjYffJ.d.ts.map → statistical-heldout-C1Ej5Ce8.d.ts.map} +1 -1
  112. package/dist/{store-otlp-84DH0OEH.js → store-otlp-BPowgPm6.js} +2 -2
  113. package/dist/{store-otlp-84DH0OEH.js.map → store-otlp-BPowgPm6.js.map} +1 -1
  114. package/dist/{store-tool-spans-DUiqyHvR.js → store-tool-spans-BcC_5ef-.js} +5 -5
  115. package/dist/{store-tool-spans-DUiqyHvR.js.map → store-tool-spans-BcC_5ef-.js.map} +1 -1
  116. package/dist/{store-tool-spans-BBXs8hDP.d.ts → store-tool-spans-ByLdU26j.d.ts} +5 -9
  117. package/dist/store-tool-spans-ByLdU26j.d.ts.map +1 -0
  118. package/dist/{task-failure-attributes-B34TiMBe.js → task-failure-attributes-CEqEfuIY.js} +17 -9
  119. package/dist/task-failure-attributes-CEqEfuIY.js.map +1 -0
  120. package/dist/{tool-groups-W7MJobX_.d.ts → tool-groups-DiBi16ns.d.ts} +3 -3
  121. package/dist/tool-groups-DiBi16ns.d.ts.map +1 -0
  122. package/dist/trace-attributes.d.ts +1 -1
  123. package/dist/trace-attributes.js +23 -75
  124. package/dist/trace-attributes.js.map +1 -1
  125. package/dist/trace-repair/index.d.ts +1 -1
  126. package/dist/traces.d.ts +11 -18
  127. package/dist/traces.d.ts.map +1 -1
  128. package/dist/traces.js +16 -16
  129. package/dist/traces.js.map +1 -1
  130. package/dist/{types-Cvqy7asY.d.ts → types-ByZslIlr.d.ts} +2 -2
  131. package/dist/{types-Cvqy7asY.d.ts.map → types-ByZslIlr.d.ts.map} +1 -1
  132. package/dist/{types-BvmWNjjs.d.ts → types-C1CAD70_.d.ts} +15 -16
  133. package/dist/types-C1CAD70_.d.ts.map +1 -0
  134. package/dist/{types-Bay1dh2o.d.ts → types-CeDfCRXp.d.ts} +11 -16
  135. package/dist/types-CeDfCRXp.d.ts.map +1 -0
  136. package/dist/wire/index.d.ts +1 -1
  137. package/docs/campaign-proposers.md +14 -16
  138. package/docs/hosted-ingest-spec.md +92 -133
  139. package/docs/public-api.md +46 -35
  140. package/docs/search-ledger.md +79 -1
  141. package/package.json +2 -2
  142. package/dist/analyze-runs-BvK4-wSs.d.ts +0 -75
  143. package/dist/analyze-runs-BvK4-wSs.d.ts.map +0 -1
  144. package/dist/attribute-vocabulary-DLJ6303h.d.ts.map +0 -1
  145. package/dist/campaign-B7q74uIh.js.map +0 -1
  146. package/dist/campaign-evidence-D40-LHIL.js.map +0 -1
  147. package/dist/client-BhEyAdfe.d.ts +0 -202
  148. package/dist/client-BhEyAdfe.d.ts.map +0 -1
  149. package/dist/client-QwJpsNYU.js +0 -655
  150. package/dist/client-QwJpsNYU.js.map +0 -1
  151. package/dist/define-agent-eval-DPizhHfy.js.map +0 -1
  152. package/dist/define-agent-eval-DblGedQk.d.ts.map +0 -1
  153. package/dist/external-optimizer-process-BnSmrkgL.js.map +0 -1
  154. package/dist/external-optimizer-subprocess-kbcPu5po.js.map +0 -1
  155. package/dist/index-CJv56rhX.d.ts.map +0 -1
  156. package/dist/index-CWoIJHmy.d.ts.map +0 -1
  157. package/dist/insight-report-CvPkEIcC.d.ts.map +0 -1
  158. package/dist/kind-factory-ByZeXDqF.js.map +0 -1
  159. package/dist/llm-judge-BnxAv7ed.js.map +0 -1
  160. package/dist/otel-spans-CQY1pNiN.js.map +0 -1
  161. package/dist/otlp-attributes-BpC_blLF.js +0 -83
  162. package/dist/otlp-attributes-BpC_blLF.js.map +0 -1
  163. package/dist/store-tool-spans-BBXs8hDP.d.ts.map +0 -1
  164. package/dist/task-failure-attributes-B34TiMBe.js.map +0 -1
  165. package/dist/tool-groups-W7MJobX_.d.ts.map +0 -1
  166. package/dist/types-Bay1dh2o.d.ts.map +0 -1
  167. package/dist/types-BvmWNjjs.d.ts.map +0 -1
@@ -1,133 +1,121 @@
1
1
  # Hosted-ingest wire spec: `2026-07-24.v1`
2
2
 
3
- This is the only hosted-ingest wire format implemented by the current package.
3
+ This is the only hosted-ingest wire format the current package implements.
4
4
  Clients and servers reject every other wire version.
5
5
 
6
- This is the contract between `@tangle-network/agent-eval` and any hosted
7
- or self-hosted orchestrator. A builder can:
6
+ This is the contract between `@tangle-network/agent-eval` and any hosted or self-hosted store.
7
+ A builder can use our store, self-host the reference receiver from `examples/hosted-ingest-server/`, or implement this spec.
8
8
 
9
- - Use our orchestrator at `https://orchestrator.tangle.tools/v1`.
10
- - Self-host the reference receiver from
11
- `examples/hosted-ingest-server/`.
12
- - Implement their own orchestrator against this spec.
9
+ The wire carries two streams:
13
10
 
14
- All three are wire-compatible by definition.
11
+ - **Search ledgers.** A producer ships a search's hash-chained ledger and the blobs its entries name.
12
+ The ledger is the search's record: nodes, edges, cells, decisions and the claim ([search ledger](./search-ledger.md)).
13
+ - **Trace spans.** OTLP-shaped spans with `tangle.*` pivots, so a store can join a cell to its execution.
14
+
15
+ The shapes are exported from `@tangle-network/agent-eval/hosted` as zod schemas.
16
+ A store imports them instead of copying them.
15
17
 
16
18
  ---
17
19
 
18
20
  ## Transport
19
21
 
20
- Two endpoints, both `POST`, both JSON. Headers on every request:
22
+ Headers on every request:
21
23
 
22
24
  | Header | Value |
23
25
  |---|---|
24
- | `Authorization` | `Bearer <tenant-key>` (the orchestrator issues this) |
25
- | `Content-Type` | `application/json` |
26
- | `X-Tangle-Tenant-Id` | The tenant's stable id (the orchestrator's primary key for the tenant) |
27
- | `X-Tangle-Wire-Version` | `2026-07-24.v1` (this spec) |
28
- | `Idempotency-Key` | Non-empty request key, at most 256 characters; clients generate one per call and reuse it across retries |
26
+ | `Authorization` | `Bearer <tenant-key>` |
27
+ | `X-Tangle-Tenant-Id` | The tenant's stable id |
28
+ | `X-Tangle-Wire-Version` | `2026-07-24.v1` |
29
+ | `Idempotency-Key` | On `POST` and `PUT`: at most 256 characters, reused across retries |
29
30
 
30
- Responses are JSON of shape `{ accepted: number, rejected: Array<{ index, reason }> }`.
31
- Clients validate the complete response before returning it.
32
- The server can return 202 for asynchronous acceptance or 200 for synchronous acceptance.
31
+ A client retries network errors, 408, 429 and 5xx.
32
+ When the response carries `Retry-After` (delay-seconds or an HTTP date), the client waits exactly that long before the next attempt; otherwise it backs off exponentially.
33
33
 
34
- ### `POST /v1/ingest/eval-runs`
34
+ ---
35
35
 
36
- Body: `IngestEvalRunsRequest = { wireVersion, events: EvalRunEvent[] }`.
36
+ ## Search ledgers
37
37
 
38
- One ingest call per logical eval-run; generations stream in
39
- incrementally via repeated calls with the same `runId`. The
40
- orchestrator deduplicates by `(tenantId, runId, generation.index)`.
38
+ A producer ships in this order, so a store has an entry's content before the entry.
41
39
 
42
- ### `POST /v1/ingest/traces`
40
+ ### `PUT /v1/search-blobs/<sha256 hex>`
43
41
 
44
- Body: `IngestTracesRequest = { wireVersion, spans: TraceSpanEvent[] }`.
42
+ Body: the exact bytes an artifact ref names.
43
+ `Content-Type` is `application/json` for the JSON blobs the recorder writes, otherwise `application/octet-stream`.
45
44
 
46
- Standard OTLP-shaped spans with a few additional attributes
47
- (`tangle.runId`, `tangle.generation`, `tangle.cellId`,
48
- `tangle.scenarioId`) so the orchestrator can pivot between the
49
- eval-run stream and the underlying execution trace.
45
+ The store re-hashes the bytes and refuses a mismatch with 422.
46
+ The call is idempotent by content.
47
+ Response (`SearchBlobPutResponseSchema`): `{ sha256, byteLength, state }`, where `state` is `stored`, `masked` or `withheld`.
48
+ A store masks or withholds bytes its redaction scan or the tenant's content posture refuses; it never rejects the entry that names them.
50
49
 
51
- ---
50
+ ### `GET /v1/ingest/search-ledger/<searchId>/head`
52
51
 
53
- ## `EvalRunEvent`
52
+ Response (`SearchLedgerHeadSchema`): `{ searchId, nextSequence, headHash }`.
53
+ `nextSequence` is the number of entries the store holds, and `headHash` is the hash of the last one, or null when it holds none.
54
+ A restarted producer starts here.
54
55
 
55
- ```ts
56
- interface EvalRunEvent {
57
- runId: string // stable; same id across all generations of one run
58
- runDir: string // logical run directory (mem://... or filesystem path)
59
- timestamp: string // ISO-8601
60
- status: // lifecycle stage this event represents
61
- | 'started'
62
- | 'baseline-complete'
63
- | 'generation-complete'
64
- | 'gate-decided'
65
- | 'finished'
66
- | 'errored'
67
- labels: Record<string, string> // free-form (env, branch, model id, etc.)
68
- baseline?: EvalRunGenerationSnapshot // present when status >= baseline-complete
69
- generations: EvalRunGenerationSnapshot[]
70
- gateDecision?: // present when status >= gate-decided
71
- | 'ship' | 'hold' | 'need_more_work' | 'model_ceiling' | 'arch_ceiling'
72
- holdoutLift?: number // winner-on-holdout - baseline-on-holdout
73
- totalCostUsd: number
74
- totalDurationMs: number
75
- errorMessage?: string // present when status === 'errored'
76
- insightReport?: InsightReport // current report contract
77
- }
78
- ```
56
+ ### `POST /v1/ingest/search-ledger`
79
57
 
80
- ## `EvalRunGenerationSnapshot`
58
+ Body (`IngestSearchLedgerRequestSchema`):
81
59
 
82
60
  ```ts
83
- interface EvalRunGenerationSnapshot {
84
- index: number // 0 is baseline; 1..N are improvement generations
85
- surfaceHash: string // stable hash of the candidate surface (pivot key)
86
- surface?: MutableSurface // OMITTED to avoid PII when consumer prefers
87
- cells: EvalRunCellScore[]
88
- compositeMean: number | null // null when no cell has a task-quality label
89
- costUsd: number
90
- durationMs: number
61
+ {
62
+ wireVersion: '2026-07-24.v1'
63
+ searchId: string
64
+ runKind: 'optimization' | 'eval' // an eval is a one-node search
65
+ fromSequence: number // the sequence of lines[0]
66
+ lines: string[] // canonical ledger lines, without newlines
91
67
  }
92
68
  ```
93
69
 
94
- ## `EvalRunCellScore`
70
+ At most 1,000 lines and 1 MiB of line bytes per request.
71
+ Each line is the producer's own ledger bytes, so producer and store hash identical input.
95
72
 
96
- ```ts
97
- interface EvalRunCellScore {
98
- scenarioId: string
99
- rep: number // 0 for the default; > 0 when reps > 1
100
- compositeMean: number | null // null when the cell is unscored
101
- dimensions: Record< // successful scores; failed or missing judges are absent
102
- string,
103
- Record<string, number>
104
- >
105
- terminalOutcome: 'succeeded' | 'failed' | 'cancelled' | 'incomplete' | 'unknown'
106
- executionErrorCount: number | null // null when the producer cannot classify errors
107
- errorMessage?: string // present for a dispatch or judge error
108
- }
109
- ```
73
+ The store applies `admitSearchLedgerBatch` to the batch, in one transaction:
74
+
75
+ 1. `fromSequence` past the store's head: `409 sequence_gap`.
76
+ 2. Each line must verify alone with `parseSearchLedgerLine`: the schema tag, the entry and event schemas, canonical bytes, its `entryHash`, and its `searchId`. A line that does not: 422.
77
+ 3. A line below the head with the stored hash is a no-op; a different hash is `409 chain_conflict`.
78
+ 4. The first new line must extend the stored head; if it does not, `409 chain_conflict`.
79
+ 5. The new entries pass the `SearchState` state machine, or the batch returns 422 and stores nothing.
80
+
81
+ Response (`SearchLedgerHeadSchema`): the head after the batch.
82
+ A 409 body (`SearchLedgerConflictSchema`) is `{ error: 'sequence_gap' | 'chain_conflict', message, head }`.
83
+
84
+ A producer resends from `head.nextSequence` after a gap.
85
+ It stops on a fork: the store holds a different chain for the same search, and nothing is overwritten.
86
+
87
+ `runKind` is fixed by the first batch; a later batch with another kind is a 422.
88
+
89
+ ### The shipper
110
90
 
111
- ## `TraceSpanEvent`
91
+ `shipSearchLedger({ tenant, ledger: { path, searchId }, runKind })` ships every complete line of a ledger file and returns the store's head and blob counts.
92
+ `startSearchShipper(...)` tails the file while the search runs: the search never waits on the network, and `stop()` ships the rest.
93
+ `agent-eval search ship <ledger> --run-kind optimization|eval` does the same from a terminal, reading the store from `TANGLE_INGEST_URL`, `TANGLE_INGEST_API_KEY` and `TANGLE_TENANT_ID`.
94
+ `selfImprove({ hostedTenant, searchLedger })` runs the tailing shipper for its own ledger.
95
+
96
+ `content: 'digests'` ships entries without blobs, so the store holds refs and digests but no text.
97
+ A blob whose local bytes are missing or do not match their ref is not uploaded and is reported under `blobs.missing`; the entries still ship.
98
+
99
+ ---
100
+
101
+ ## Trace spans
102
+
103
+ ### `POST /v1/ingest/traces`
104
+
105
+ Body (`IngestTracesRequestSchema`): `{ wireVersion, spans: TraceSpanEvent[] }`.
106
+ Response (`IngestResponseSchema`): `{ accepted, rejected: Array<{ index, reason }> }`.
112
107
 
113
108
  ```ts
114
109
  interface TraceSpanEvent {
115
- // Standard OTel
116
110
  traceId: string
117
111
  spanId: string
118
112
  parentSpanId?: string
119
113
  name: string
120
- startTimeUnixNano: string // canonical unsigned 64-bit integer encoded in base 10
121
- endTimeUnixNano: string // canonical unsigned 64-bit integer encoded in base 10
114
+ startTimeUnixNano: string // canonical unsigned 64-bit integer in base 10
115
+ endTimeUnixNano: string
122
116
  attributes: Record<string, string | number | boolean>
123
- events?: Array<{
124
- timeUnixNano: string // canonical unsigned 64-bit integer encoded in base 10
125
- name: string
126
- attributes?: Record<string, string | number | boolean>
127
- }>
128
- status?: { code: 'OK' | 'ERROR' | 'UNSET', message? }
129
-
130
- // Tangle additions (all optional) for pivoting
117
+ events?: Array<{ timeUnixNano: string; name: string; attributes?: Record<string, string | number | boolean> }>
118
+ status?: { code: 'OK' | 'ERROR' | 'UNSET'; message?: string }
131
119
  'tangle.runId'?: string
132
120
  'tangle.generation'?: number
133
121
  'tangle.cellId'?: string
@@ -135,59 +123,30 @@ interface TraceSpanEvent {
135
123
  }
136
124
  ```
137
125
 
126
+ A store keeps at most one span per `(tenantId, traceId, spanId)`.
127
+ It accepts an exact duplicate as stored and rejects a conflicting payload with the same identity.
128
+ When an `Idempotency-Key` matches a request from the same tenant in the last 24 hours, it returns the recorded response.
129
+
138
130
  ---
139
131
 
140
132
  ## Server requirements
141
133
 
142
- Any orchestrator implementing this spec MUST:
143
-
144
- 1. **Validate auth**: reject without `Authorization` header (401), with a
145
- mismatched bearer token (401), or without a recognized `X-Tangle-Tenant-Id`
146
- (404).
147
- 2. **Validate wire version**: reject incompatible wire versions (400 with
148
- a clear error message). The major component is the breaking-change axis.
149
- 3. **Validate tenant isolation**: queries with `tenantId` X never return
150
- data tagged with `tenantId` Y. Test this adversarially.
151
- 4. **Honor idempotency**: require an `Idempotency-Key`; when it matches a prior request to the same endpoint from the same tenant in the last 24 hours, return the same response without processing the body again.
152
- 5. **Deduplicate spans**: store at most one span for each `(tenantId, traceId, spanId)` identity.
153
- Accept an exact duplicate as already stored and reject a conflicting payload with the same identity.
154
- 6. **Keep run state monotonic**: accept forward lifecycle transitions, but never replace `finished` or `errored` with a late event.
155
- Delayed events can add a missing generation without replacing terminal totals, labels, or status.
156
- 7. **Persist eval-runs durably**: at least the event + cell scores must
157
- survive an orchestrator restart. Trace spans MAY be best-effort.
158
- 8. **Provide read access**: GET endpoints for the tenant to list + fetch
159
- their own runs. Wire format for reads is NOT part of this spec: each
160
- orchestrator can pick its own (REST + JSON, gRPC, GraphQL).
161
-
162
- Servers SHOULD also:
163
-
164
- - Provide a webhook callback per tenant for `gate-decided` events.
165
- - Provide a billable-events emitter (Stripe meter / equivalent) per ingest
166
- call so consumption can be metered.
167
- - Provide a dashboard or API to view + diff per-scenario lifts over time.
134
+ A store that implements this spec must:
135
+
136
+ 1. Reject a request without a valid bearer token (401) or with an unknown tenant (404).
137
+ 2. Reject every wire version other than `2026-07-24.v1` (400) and name the accepted one.
138
+ 3. Isolate tenants: a read for tenant X never returns tenant Y's data, and a blob, search or span of another tenant reads as absent.
139
+ 4. Apply the search-ledger batch rule above, and store a batch whole or not at all.
140
+ 5. Keep search entries, blobs and their metadata durably; trace spans may be best-effort.
168
141
 
169
142
  ---
170
143
 
171
144
  ## Reference implementation
172
145
 
173
- `examples/hosted-ingest-server/` is a Hono receiver for local development and contract tests.
174
- It validates auth, request and response shapes, versions, exact nanosecond strings, request keys, span identity, and monotonic run state.
175
- It is not production storage because process restart clears its in-memory data.
146
+ `examples/hosted-ingest-server/` is an in-memory Hono receiver for local development.
147
+ It applies `admitSearchLedgerBatch` and `SearchState` to every batch, re-hashes blobs, and serves `GET /v1/searches/<searchId>` with the replayed audit.
148
+ A process restart clears it.
176
149
 
177
150
  ```sh
178
151
  TENANT_KEY=dev-token TENANT_ID=acme pnpm tsx examples/hosted-ingest-server/server.ts
179
152
  ```
180
-
181
- Send events with [`createHostedClient`](../src/hosted/client.ts) from `@tangle-network/agent-eval/hosted`.
182
- Call `client.ingestEvalRun(event)` with a valid `EvalRunEvent` after configuring the client's endpoint, tenant ID, and API key.
183
- For `selfImprove`, configure `hostedTenant` as shown in the [receiver example](../examples/hosted-ingest-server/).
184
- The receiver's authenticated `GET /v1/runs` endpoint lists ingested runs.
185
-
186
- ---
187
-
188
- ## Version
189
-
190
- `HostedWireVersion` is `"2026-07-24.v1"`.
191
- The current clients emit only this value.
192
- Servers return 400 for every other value and list the accepted version.
193
- There are no compatibility readers or migration branches.
@@ -7,11 +7,11 @@ Generated by `pnpm api:census` on demand — this is a dated reading, not a gate
7
7
  | measure | count |
8
8
  | --- | --- |
9
9
  | export subpaths | 32 |
10
- | published value exports (subpath x symbol) | 1500 |
11
- | distinct symbols | 1313 |
12
- | production | 978 |
10
+ | published value exports (subpath x symbol) | 1511 |
11
+ | distinct symbols | 1324 |
12
+ | production | 992 |
13
13
  | planned | 268 |
14
- | none | 254 |
14
+ | none | 251 |
15
15
 
16
16
  Type-only exports are not listed: a type binds no runtime surface, and removing one cannot break a caller at run time.
17
17
 
@@ -152,7 +152,7 @@ The `none` set was reviewed symbol by symbol on 2026-08-21. Four rules decided m
152
152
  | `checkTraceContracts` | production | creative-agent:eval/lib/trace-contracts.ts |
153
153
  | `clamp01` | production | agent-dev-container:products/intelligence/api/src/lib/consultant/executor.ts |
154
154
  | `classifyFailure` | production | phony:products/builder/api/src/eval/autoresearch/trace-analyst.ts |
155
- | `classifyFailureReason` | production | this package: src/diagnosis/first-failure.ts:28 |
155
+ | `classifyFailureReason` | production | this package: src/diagnosis/first-failure.ts:39 |
156
156
  | `cliffsDelta` | production | agent-builder:src/lib/.server/eval/loops/differential-eval.ts |
157
157
  | `CODING_HARNESSES` | production | agent-runtime:src/runtime/define-leaderboard.ts |
158
158
  | `cohensD` | production | starter-foundry:examples/recruiter-eval-workspace/eval/src/eval/regression/gate.ts |
@@ -402,7 +402,7 @@ The `none` set was reviewed symbol by symbol on 2026-08-21. Four rules decided m
402
402
  | `scorePolicyEditReadiness` | none | — |
403
403
  | `scoreRedTeamOutput` | production | agent-dev-container:products/intelligence/api/src/lib/optimization-gate.ts |
404
404
  | `scoreTraceInsightReadiness` | production | blueprint-agent:scripts/experiments/lib/analyze-vb-run/report-html-sections.ts |
405
- | `searchCellRunId` | production | this package: src/campaign/search-ledger-recording.ts:24 |
405
+ | `searchCellRunId` | production | this package: src/campaign/search-ledger-recording.ts:25 |
406
406
  | `seatPresets` | production | supervisor-lab:bench/comms/judges.ts |
407
407
  | `selfImprove` | production | agent-app:src/eval-campaign/index.ts |
408
408
  | `SEMANTIC_CONCEPT_JUDGE_VERSION` | production | blueprint-agent:scripts/experiments/lib/semantic-audit.ts |
@@ -584,7 +584,7 @@ The `none` set was reviewed symbol by symbol on 2026-08-21. Four rules decided m
584
584
  | `rlmEngineLimits` | none | only this package's tests: src/analyst/definition-parity.test.ts:26 |
585
585
  | `roundAgentRxStep` | production | this package: src/analyst/benchmark-agentrx-calibration.ts:2 |
586
586
  | `runAnalystBenchmark` | production | this package: benchmarks/trace-analysis/codetracebench-glm52-20260730/summarize-codetracer.mjs:6 |
587
- | `runAnalystBenchmarkCommand` | production | this package: src/cli.ts:17 |
587
+ | `runAnalystBenchmarkCommand` | production | this package: src/cli.ts:18 |
588
588
  | `runPrimeExchange` | production | this package: src/analyst/benchmark-runner-prime.ts:19 |
589
589
  | `runTraceAnalyst` | production | this package: scripts/gepa-analyst-campaign.ts:71 |
590
590
  | `scoreAnalystFindings` | production | this package: scripts/gepa-analyst-campaign.ts:57 |
@@ -644,7 +644,7 @@ The `none` set was reviewed symbol by symbol on 2026-08-21. Four rules decided m
644
644
 
645
645
  ### `./campaign`
646
646
 
647
- 143 value exports — 91 production, 26 planned, 26 none.
647
+ 144 value exports — 92 production, 26 planned, 26 none.
648
648
 
649
649
  | symbol | consumer | evidence |
650
650
  | --- | --- | --- |
@@ -662,7 +662,7 @@ The `none` set was reviewed symbol by symbol on 2026-08-21. Four rules decided m
662
662
  | `buildTraceAnalystSurfaceDispatch` | none | only this package's tests: src/campaign/analyst-surface.test.ts:4 |
663
663
  | `campaignBreakdown` | production | this package: src/campaign/external-text-evaluation.ts:11 |
664
664
  | `campaignMeanComposite` | production | agent-dev-container:products/intelligence/api/src/lib/optimization-engine.ts |
665
- | `campaignMeasurementDigest` | production | this package: src/contract/self-improve-method.ts:13 |
665
+ | `campaignMeasurementDigest` | production | this package: src/contract/self-improve-method.ts:14 |
666
666
  | `campaignScenarioIdentity` | production | agent-runtime:src/improvement/method-identity.ts |
667
667
  | `campaignSplitDigest` | production | discovery-lab:tools/profile-population.mjs |
668
668
  | `campaignSplitDigestFromIdentities` | production | agent-runtime:src/improvement/method-identity.ts |
@@ -679,7 +679,7 @@ The `none` set was reviewed symbol by symbol on 2026-08-21. Four rules decided m
679
679
  | `createProfileMatrixPlan` | production | discovery-lab:tools/run-profile-confirmation.mjs |
680
680
  | `createReferenceEquivalenceJudge` | none | only this package's tests: src/reference-equivalence-judge.test.ts:13 |
681
681
  | `createRunCostLedger` | production | agent-dev-container:products/intelligence/api/src/lib/eval-engine.ts |
682
- | `createSearchHistoryReceipt` | production | this package: src/campaign/search-ledger-recording.ts:26 |
682
+ | `createSearchHistoryReceipt` | production | this package: src/campaign/search-ledger-recording.ts:27 |
683
683
  | `crowdedFrontierParent` | planned | doc: docs/campaign-proposers.md |
684
684
  | `decodeExternalTextCandidate` | production | agent-runtime:src/improvement/method-execution.ts |
685
685
  | `DEFAULT_EXTERNAL_OPTIMIZER_CALLBACK_LIMITS` | none | — |
@@ -724,6 +724,7 @@ The `none` set was reviewed symbol by symbol on 2026-08-21. Four rules decided m
724
724
  | `pairHoldout` | production | agent-dev-container:products/intelligence/api/src/lib/run-provenance.ts |
725
725
  | `paretoPolicy` | none | only this package's tests: src/campaign/gates/promotion-policy.test.ts:3 |
726
726
  | `paretoSignificanceGate` | production | agent-app:src/eval-campaign/index.ts |
727
+ | `parseSearchLedgerLine` | production | this package: src/hosted/search-ledger-wire.ts:24 |
727
728
  | `phoenixEvaluatorJudge` | none | only this package's tests: src/campaign/upstream-evaluators.test.ts:6 |
728
729
  | `planCampaignRun` | production | this package: src/campaign/fixtures.ts:5 |
729
730
  | `planEvalFixtureRun` | planned | example: examples/eval-fixtures-quickstart/index.ts:11 |
@@ -755,21 +756,21 @@ The `none` set was reviewed symbol by symbol on 2026-08-21. Four rules decided m
755
756
  | `scoreDiscrimination` | production | supervisor-lab:bench/comms/seat-discrimination.ts |
756
757
  | `scoreUserStory` | production | blueprint-agent:scripts/experiments/eval/launch-scoreboard/scoreboard-core.ts |
757
758
  | `SEARCH_ESTIMATOR` | planned | doc: docs/search-ledger.md |
758
- | `SEARCH_LEDGER_SCHEMA` | production | this package: src/campaign/search-ledger.ts:40 |
759
- | `searchCellId` | production | this package: src/campaign/search-ledger-recording.ts:56 |
759
+ | `SEARCH_LEDGER_SCHEMA` | production | this package: src/campaign/search-ledger.ts:41 |
760
+ | `searchCellId` | production | this package: src/campaign/search-ledger-recording.ts:57 |
760
761
  | `searchCellSetDigest` | planned | doc: docs/search-ledger.md |
761
762
  | `searchEdgeId` | planned | doc: docs/search-ledger.md |
762
763
  | `searchHistoryCoverageRow` | production | this package: src/campaign/optimization-method.ts:14 |
763
764
  | `SearchHistoryRequiredError` | none | — |
764
- | `SearchLedgerConflictError` | production | this package: src/campaign/search-ledger.ts:33 |
765
+ | `SearchLedgerConflictError` | production | this package: src/campaign/search-ledger.ts:34 |
765
766
  | `SearchLedgerError` | production | this package: src/campaign/estimate-node.ts:20 |
766
767
  | `SearchLedgerIntegrityError` | production | this package: src/campaign/search-ledger-file.ts:10 |
767
- | `searchNodeId` | production | this package: src/campaign/search-ledger-recording.ts:56 |
768
+ | `searchNodeId` | production | this package: src/campaign/search-ledger-recording.ts:57 |
768
769
  | `searchPosterior` | planned | doc: docs/search-ledger.md |
769
770
  | `SearchRecorder` | production | this package: src/campaign/gepa-search-import.ts:23 |
770
- | `SearchState` | production | this package: src/campaign/search-ledger.ts:47 |
771
+ | `SearchState` | production | this package: src/campaign/search-ledger.ts:48 |
771
772
  | `SearchStateView` | production | this package: src/campaign/estimate-node.ts:28 |
772
- | `searchTaskSetDigest` | production | this package: src/campaign/search-ledger-recording.ts:56 |
773
+ | `searchTaskSetDigest` | production | this package: src/campaign/search-ledger-recording.ts:57 |
773
774
  | `searchUnitScores` | production | this package: src/campaign/estimate-node.ts:28 |
774
775
  | `selectDiscriminative` | none | only this package's tests: src/campaign/scenario-selection.test.ts:2 |
775
776
  | `sequentialDecide` | planned | doc: docs/experiment.md |
@@ -785,7 +786,7 @@ The `none` set was reviewed symbol by symbol on 2026-08-21. Four rules decided m
785
786
  | `traceAnalystQualityJudge` | production | this package: scripts/gepa-analyst-campaign.ts:74 |
786
787
  | `transientDispatchFailure` | planned | doc: docs/eval-surface-map.md |
787
788
  | `userStoryScoreboard` | production | blueprint-agent:scripts/experiments/eval/launch-scoreboard/run.ts |
788
- | `validateSearchLedgerEvent` | production | this package: src/campaign/search-ledger-recording.ts:27 |
789
+ | `validateSearchLedgerEvent` | production | this package: src/campaign/search-ledger-recording.ts:28 |
789
790
  | `verifyCodeSurface` | production | agent-runtime:src/candidate-execution/builder.ts |
790
791
  | `verifyLoopProvenanceRecord` | none | only this package's tests: src/campaign/provenance-integrity.test.ts:5 |
791
792
  | `verifySearchHistoryArtifact` | production | this package: src/campaign/optimization-method.ts:14 |
@@ -794,7 +795,7 @@ The `none` set was reviewed symbol by symbol on 2026-08-21. Four rules decided m
794
795
 
795
796
  ### `./contract`
796
797
 
797
- 65 value exports — 41 production, 14 planned, 10 none.
798
+ 62 value exports — 41 production, 14 planned, 7 none.
798
799
 
799
800
  | symbol | consumer | evidence |
800
801
  | --- | --- | --- |
@@ -808,9 +809,6 @@ The `none` set was reviewed symbol by symbol on 2026-08-21. Four rules decided m
808
809
  | `createReferenceEquivalenceJudge` | none | only this package's tests: src/reference-equivalence-judge.test.ts:13 |
809
810
  | `defaultProductionGate` | production | agent-app:src/eval-campaign/index.ts |
810
811
  | `defineAgentEval` | planned | example: examples/evaluate-a-change/index.ts:10 |
811
- | `diffGenerations` | none | only this package's tests: tests/contract-diff.test.ts:2 |
812
- | `diffRunBaselineToWinner` | none | only this package's tests: tests/contract-diff.test.ts:2 |
813
- | `diffRuns` | none | only this package's tests: tests/contract-diff.test.ts:2 |
814
812
  | `evalReportingSuite` | none | only this package's tests: tests/contract-eval-reporting-suite.test.ts:19 |
815
813
  | `evaluatePairedMeasurements` | production | this package: src/contract/profile-measured-comparison.ts:26 |
816
814
  | `externalTextOptimizationMethod` | production | agent-app:src/eval-campaign/index.ts |
@@ -1012,20 +1010,33 @@ The `none` set was reviewed symbol by symbol on 2026-08-21. Four rules decided m
1012
1010
 
1013
1011
  ### `./hosted`
1014
1012
 
1015
- 11 value exports — 7 production, 2 planned, 2 none.
1013
+ 24 value exports — 20 production, 2 planned, 2 none.
1016
1014
 
1017
1015
  | symbol | consumer | evidence |
1018
1016
  | --- | --- | --- |
1017
+ | `admitSearchLedgerBatch` | planned | example: examples/hosted-ingest-server/server.ts:30 |
1019
1018
  | `createHostedClient` | production | traces:src/index.ts |
1020
- | `EvalRunEventSchema` | planned | example: examples/hosted-ingest-server/server.ts:33 |
1021
1019
  | `HOSTED_WIRE_VERSION` | production | agent-dev-container:packages/sdk-data/src/sink/intelligence-sink.ts |
1022
1020
  | `hostedClientFromEnv` | production | traces:src/index.ts |
1021
+ | `HostedRequestError` | none | — |
1023
1022
  | `hostedTenantFromEnv` | production | creative-agent:eval/self-improve.ts |
1024
- | `IngestEvalRunsRequestSchema` | production | this package: src/hosted/client.ts:19 |
1025
- | `IngestResponseSchema` | production | this package: src/hosted/client.ts:19 |
1026
- | `IngestTracesRequestSchema` | production | this package: src/hosted/client.ts:19 |
1027
- | `InsightReportSchema` | none | only this package's tests: tests/contract-analyze-runs.test.ts:29 |
1028
- | `TraceSpanEventSchema` | planned | example: examples/hosted-ingest-server/server.ts:33 |
1023
+ | `IngestResponseSchema` | production | this package: src/hosted/client.ts:22 |
1024
+ | `IngestSearchLedgerRequestSchema` | production | this package: src/hosted/client.ts:23 |
1025
+ | `IngestTracesRequestSchema` | production | this package: src/hosted/client.ts:22 |
1026
+ | `SEARCH_LEDGER_BATCH_MAX_BYTES` | production | this package: src/hosted/search-shipper.ts:18 |
1027
+ | `SEARCH_LEDGER_BATCH_MAX_LINES` | production | this package: src/hosted/search-shipper.ts:18 |
1028
+ | `SEARCH_LEDGER_INGEST_PATH` | production | this package: src/hosted/client.ts:23 |
1029
+ | `searchBlobPath` | production | this package: src/hosted/client.ts:23 |
1030
+ | `SearchBlobPutResponseSchema` | production | this package: src/hosted/client.ts:23 |
1031
+ | `searchLedgerArtifactRefs` | production | this package: src/hosted/search-shipper.ts:18 |
1032
+ | `SearchLedgerConflictSchema` | production | this package: src/hosted/client.ts:23 |
1033
+ | `searchLedgerHeadPath` | production | this package: src/hosted/client.ts:23 |
1034
+ | `SearchLedgerHeadSchema` | production | this package: src/hosted/client.ts:23 |
1035
+ | `SearchRunKindSchema` | production | this package: src/search-command.ts:13 |
1036
+ | `SearchShipConflictError` | production | this package: src/search-command.ts:14 |
1037
+ | `shipSearchLedger` | production | this package: src/contract/self-improve-method.ts:24 |
1038
+ | `startSearchShipper` | production | this package: src/contract/self-improve.ts:66 |
1039
+ | `TraceSpanEventSchema` | planned | example: examples/hosted-ingest-server/server.ts:29 |
1029
1040
  | `UnixNanoTimestampSchema` | none | — |
1030
1041
 
1031
1042
  ### `./jev`
@@ -1368,7 +1379,7 @@ The `none` set was reviewed symbol by symbol on 2026-08-21. Four rules decided m
1368
1379
  | `ROLLOUT_ROLES` | production | this package: src/rollout/interchange/harbor.ts:60 |
1369
1380
  | `ROLLOUT_SCHEMA` | production | this package: src/rollout/interchange/harbor.ts:60 |
1370
1381
  | `ROLLOUT_SPLITS` | production | this package: src/rollout/interchange/harbor.ts:60 |
1371
- | `runRolloutReleaseCli` | production | this package: src/cli.ts:19 |
1382
+ | `runRolloutReleaseCli` | production | this package: src/cli.ts:20 |
1372
1383
  | `scoreOrigin` | production | this package: src/rollout/mint.ts:39 |
1373
1384
  | `scrubLines` | production | supervisor-lab:bench/vertical-rollout-package.ts |
1374
1385
  | `scrubRolloutLine` | none | only this package's tests: src/rollout/release/scrub.test.ts:4 |
@@ -1429,7 +1440,7 @@ The `none` set was reviewed symbol by symbol on 2026-08-21. Four rules decided m
1429
1440
  | `renderSupervisorRunMarkdown` | production | discovery-lab:experiments/0005-run-visibility/render-run.mjs |
1430
1441
  | `reportSupervisorRound` | planned | named in agent-runtime (bind not in the import graph) |
1431
1442
  | `rollupSupervisorRuns` | production | discovery-lab:tools/disco.mjs |
1432
- | `runSupervisorRunCommand` | production | this package: src/cli.ts:20 |
1443
+ | `runSupervisorRunCommand` | production | this package: src/cli.ts:22 |
1433
1444
  | `RUNTIME_FAILED_STATUS` | none | — |
1434
1445
  | `runtimeSupervisorRunReader` | none | only this package's tests: src/supervisor-run/index.test.ts:2 |
1435
1446
  | `showMeasured` | production | this package: src/supervisor-run/render.ts:8 |
@@ -1774,7 +1785,7 @@ The `none` set was reviewed symbol by symbol on 2026-08-21. Four rules decided m
1774
1785
 
1775
1786
  | symbol | consumer | evidence |
1776
1787
  | --- | --- | --- |
1777
- | `buildOpenApi` | production | this package: src/cli.ts:22 |
1788
+ | `buildOpenApi` | production | this package: src/cli.ts:24 |
1778
1789
  | `createApp` | planned | doc: docs/wire-protocol.md |
1779
1790
  | `dispatchRpc` | planned | doc: docs/wire-protocol.md |
1780
1791
  | `ErrorResponseSchema` | production | this package: src/wire/openapi.ts:15 |
@@ -1785,7 +1796,7 @@ The `none` set was reviewed symbol by symbol on 2026-08-21. Four rules decided m
1785
1796
  | `handleJudge` | production | this package: src/wire/rpc.ts:15 |
1786
1797
  | `handleListRubrics` | production | this package: src/wire/rpc.ts:15 |
1787
1798
  | `handleTracesIngest` | production | this package: src/wire/server.ts:20 |
1788
- | `handleVersion` | production | this package: src/cli.ts:21 |
1799
+ | `handleVersion` | production | this package: src/cli.ts:23 |
1789
1800
  | `hashRubric` | production | this package: src/wire/handlers.ts:22 |
1790
1801
  | `HealthResponseSchema` | production | this package: src/wire/openapi.ts:15 |
1791
1802
  | `JudgeRequestSchema` | production | this package: src/wire/openapi.ts:15 |
@@ -1795,10 +1806,10 @@ The `none` set was reviewed symbol by symbol on 2026-08-21. Four rules decided m
1795
1806
  | `RUBRIC_VERSION_SCHEME` | none | — |
1796
1807
  | `RubricDimensionSchema` | none | only this package's tests: tests/wire/schemas.test.ts:12 |
1797
1808
  | `RubricSchema` | none | only this package's tests: tests/wire/schemas.test.ts:12 |
1798
- | `runRpcBatch` | production | this package: src/cli.ts:23 |
1799
- | `runRpcOnce` | production | this package: src/cli.ts:23 |
1809
+ | `runRpcBatch` | production | this package: src/cli.ts:25 |
1810
+ | `runRpcOnce` | production | this package: src/cli.ts:25 |
1800
1811
  | `startServer` | production | creative-agent:eval/ingestion-server.ts |
1801
- | `startServerAsync` | production | this package: src/cli.ts:24 |
1812
+ | `startServerAsync` | production | this package: src/cli.ts:26 |
1802
1813
  | `TraceEventSchema` | planned | named in insurance-agent (bind not in the import graph) |
1803
1814
  | `TracesIngestRequestSchema` | production | this package: src/wire/openapi.ts:15 |
1804
1815
  | `TracesIngestResponseSchema` | production | this package: src/wire/openapi.ts:15 |
@@ -134,13 +134,87 @@ const cellId = await recorder.allocateCell({ nodeId: root.nodeId, taskId, split:
134
134
  await recorder.settleCell({ cellId, outcome, accounting, identity, runRecord })
135
135
  ```
136
136
 
137
- `runOptimization({ searchLedger: { ledger, identity } })` and `selfImprove` record through the recorder and return the receipt on `searchHistory`.
137
+ `runOptimization` and `selfImprove` run on the kernel below and return the receipt on `searchHistory`.
138
138
  The loop's scenarios are its proposer's feedback, so they are the train split; its promotions are budget decisions and it makes no claim.
139
139
 
140
140
  `gepaOptimizationMethod({ searchLedger: { identity } })` records GEPA's search when it finishes.
141
141
  `importGepaPopulation` turns the population into nodes and `correlated` edges and reports collapsed duplicates.
142
142
  `importExternalEvaluations` turns every callback evaluation into an `external` cell; a candidate GEPA evaluated but kept out of its population gets an `unknown` edge and is decided `pruned`.
143
143
 
144
+ ## Run a search: the kernel
145
+
146
+ `runSearch` is the one loop every optimizer runs on.
147
+ It separates three decisions: where to expand (a `SearchPolicy`), where to spend rollouts (a `SearchAllocator`), and what to claim (the claim step on the sealed test split).
148
+ There is no generation barrier.
149
+ A lane that frees up takes the next allocated cell: claim cells first, then rung and root cells, then screens, then train cells.
150
+ The policy proposes when no cell waits, fewer than twice the lanes' capacity run, and the cap admits one proposal and its expected screens.
151
+
152
+ ```ts
153
+ import { incumbent, runSearch, SearchRecorder, uniform } from '@tangle-network/agent-eval/campaign'
154
+
155
+ const policy = incumbent({ patience: 3 })
156
+ const allocation = uniform({ reps: 1 })
157
+ const recorder = await SearchRecorder.open({ ledger }, {
158
+ ...opening,
159
+ policy: { expansion: policy.name, allocation: allocation.name, seed },
160
+ })
161
+ const { state, leader, reason } = await runSearch({
162
+ recorder, root, codec, policy, allocation, proposer, executor, maxExpansions: 10,
163
+ })
164
+ ```
165
+
166
+ The ports:
167
+
168
+ - **Executor:** `lanes()` declares pools of slots, each `hard` (it enforces `cellUsd` per cell) or `estimate` (it cannot); `place(cell)` picks a cell's lane; `run(work)` runs one attempt and returns its outcome, accounting and identity; `adopt(work)` returns an attempt an earlier process finished, or null.
169
+ An environment fault is an `errored` outcome; a rejection stops the search.
170
+ - **Proposer:** `propose({ parents, operator, leader })` returns children with a label, a rationale and optional typed `attribution`, plus the operation's accounting.
171
+ Its output is stored as a `proposal` blob on `operation-recorded` before any child is registered.
172
+ - **Codec:** `node(recorder, artifact)` content-addresses an artifact, `diff` stores the parent-to-child diff, and `load` reads a node's artifact back.
173
+ - **Policy:** `expand(view)` returns parents and an operator, or null to wait; `leader(view)` names the node the search keeps.
174
+ The view holds the policy split (selection, or train when a search has none) and no test cell.
175
+ `incumbent({ patience })` is the hill climb: it expands the leader once every earlier child is screened, and a node that scored every unit of its screen leads when it beats the leader on the units they share.
176
+ `crowdedFrontierParent({ seed })` draws the parent from the Pareto frontier by a seeded crowded tournament and keeps the incumbent's leader rule.
177
+ - **Allocator:** `plan(state, nodeId)` lists the cells a node needs now; the kernel allocates the ones the ledger lacks.
178
+ `uniform({ reps })` gives the root every train and selection task as `root` cells, and every other node every train task (`train`) and selection task (`screen`).
179
+
180
+ **Budget.**
181
+ Every reservation passes the ledger's admission rule: committed spend plus open reservations plus the unspent claim reserve plus the new hold stays within `maxUsd`.
182
+ The kernel checks `state.budget.headroomUsd` first and prices an expansion as one proposal plus `childrenPerProposal` screens.
183
+ A hard lane holds its maximum; an estimate lane holds 1.5 times the p99 of its settled cells once 20 settled, else its prior.
184
+ Spend above a hold is recorded as overspend, never refused.
185
+ Expansion stops at `maxNodes`, `maxExpansions`, the deadline, after `patience` expansions without a new leader, when the cap cannot admit one more expansion, or when the proposer stops.
186
+ Allocated cells still run; at the deadline the ones not yet started are cancelled.
187
+ At close the leader is decided `selected` when it has a scored cell, every other undecided node `rejected` with its estimate against the leader, and the search closes with no claim.
188
+
189
+ **Resume.**
190
+ The ledger is the only checkpoint.
191
+ Running the kernel again on an open ledger replays it and continues.
192
+ An operation that started without a result is recorded `failed` with an unknown cost and a floor of 0, and the next proposal runs under a new operation id.
193
+ A recorded proposal whose children were not all registered is finished from its stored output.
194
+ A cell the ledger shows unsettled is offered to `executor.adopt` before its first dispatch, so an attempt that finished before the restart is recorded once and not run again.
195
+ Aborting the `signal` pauses the search: in-flight cells are aborted, a scored result that still arrives is recorded, an attempt that ends in an error while the search stops stays unsettled (the error may be the interruption), and the ledger stays open.
196
+ One kernel runs a ledger file at a time on a host: a second one is refused by a pid lock beside the ledger, and a killed holder's lock is reclaimed.
197
+ A closed ledger returns its result; more work on a closed search is a new search.
198
+
199
+ `scripts/search-sim.ts` runs the real kernel, ledger and policies over a seeded synthetic objective, proposer and executor, and `kill-resume` SIGKILLs it at random ledger positions and compares the resumed search with an uninterrupted one.
200
+
201
+ ## Ship a search
202
+
203
+ A hosted store (Intelligence, or the reference receiver in `examples/hosted-ingest-server/`) receives a search through the [hosted ingest wire](./hosted-ingest-spec.md).
204
+ The shipper reads the ledger file, uploads the blobs each entry names, and posts the entries from the store's head.
205
+ A restarted shipper, a lost response, or a store that lost data continues from the store's head; a store that holds a different chain for the same search stops it with `SearchShipConflictError`.
206
+
207
+ ```ts
208
+ import { shipSearchLedger, startSearchShipper } from '@tangle-network/agent-eval/hosted'
209
+
210
+ const shipper = startSearchShipper({ tenant, ledger: { path: ledger.path, searchId }, runKind: 'optimization' })
211
+ // ...the search appends to its ledger; the shipper tails it...
212
+ const shipped = await shipper.stop() // { head, localLines, batches, blobs: { uploaded, missing, ... } }
213
+ ```
214
+
215
+ `selfImprove({ hostedTenant, searchLedger })` does this for its own ledger.
216
+ `agent-eval search ship <ledger> --run-kind optimization|eval` finishes or resumes a ship from a terminal.
217
+
144
218
  ## Receipts and `require-complete`
145
219
 
146
220
  `createSearchHistoryReceipt({ producerId, runId, ledger })` reads the ledger's bytes, replays them, and binds the byte digest, the audit digest, and a bounded summary.
@@ -169,6 +243,10 @@ Those claims need the sealed test split, the claim's power check, and held-out e
169
243
  - `src/campaign/search-state.ts`: `SearchState`, the invariants and read model, and the id functions.
170
244
  - `src/campaign/estimate-node.ts`: `estimateNode`, `estimateNodeFromCells` and `searchPosterior`.
171
245
  - `src/campaign/search-ledger-recording.ts`: `SearchRecorder` and the surface helpers.
246
+ - `src/campaign/search-kernel.ts`: `runSearch`, the executor, proposer and codec ports, and `searchPolicyView`.
247
+ - `src/campaign/search-policy.ts`: `SearchPolicy`, `incumbent` and `crowdedFrontierParent`.
248
+ - `src/campaign/allocation.ts`: `SearchAllocator` and `uniform`.
249
+ - `src/campaign/presets/run-optimization.ts`: `runOptimization` as a search on the kernel.
172
250
  - `src/campaign/gepa-search-import.ts`: the GEPA population and evaluation importers.
173
251
  - `src/campaign/search-history-receipt.ts`: receipts and admission.
174
252
  - `src/ledger-core/`: hashing, locking, durable appends, chain verification, and the trusted-head pin.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-eval",
3
- "version": "0.190.1",
3
+ "version": "0.192.0",
4
4
  "description": "Evaluate and improve AI agents from runs, traces, judges, and feedback. Compare candidates, cluster failures, measure lift, and gate releases.",
5
5
  "homepage": "https://github.com/tangle-network/agent-eval#readme",
6
6
  "repository": {
@@ -221,7 +221,7 @@
221
221
  "@hono/node-server": "^2.1.1",
222
222
  "@tangle-network/agent-core": "^0.9.6",
223
223
  "@tangle-network/agent-interface": "^2.0.0",
224
- "@tangle-network/agent-trace-contract": "^1.0.2",
224
+ "@tangle-network/agent-trace-contract": "^1.2.0",
225
225
  "hono": "^4.13.5",
226
226
  "linear-sum-assignment": "1.0.9",
227
227
  "re2js": "2.8.6",