@tangle-network/agent-eval 0.189.0 → 0.190.1

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 (146) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/README.md +3 -2
  3. package/dist/adapters/http.d.ts +10 -1
  4. package/dist/adapters/http.d.ts.map +1 -1
  5. package/dist/adapters/http.js +75 -7
  6. package/dist/adapters/http.js.map +1 -1
  7. package/dist/analyst/index.d.ts +66 -3
  8. package/dist/analyst/index.d.ts.map +1 -1
  9. package/dist/analyst/index.js +212 -7
  10. package/dist/analyst/index.js.map +1 -1
  11. package/dist/{benchmark-command-BhhAYstU.js → benchmark-command-BXIr_k8D.js} +12 -11
  12. package/dist/benchmark-command-BXIr_k8D.js.map +1 -0
  13. package/dist/benchmarks/index.d.ts +1 -1
  14. package/dist/benchmarks/index.js +3 -3
  15. package/dist/campaign/index.d.ts +4 -4
  16. package/dist/campaign/index.js +7 -7
  17. package/dist/{campaign-BWoSQPSU.js → campaign-B7q74uIh.js} +256 -11
  18. package/dist/campaign-B7q74uIh.js.map +1 -0
  19. package/dist/{campaign-evidence-CBlGJ3kC.js → campaign-evidence-D40-LHIL.js} +6 -5
  20. package/dist/campaign-evidence-D40-LHIL.js.map +1 -0
  21. package/dist/{chat-client-C4dg7Ng_.js → chat-client-B_ItsSBw.js} +2 -2
  22. package/dist/{chat-client-C4dg7Ng_.js.map → chat-client-B_ItsSBw.js.map} +1 -1
  23. package/dist/{chat-json-call-JVGbfx95.js → chat-json-call-CXHBvUz8.js} +2 -2
  24. package/dist/{chat-json-call-JVGbfx95.js.map → chat-json-call-CXHBvUz8.js.map} +1 -1
  25. package/dist/claim-BGOUqoMq.d.ts +38 -0
  26. package/dist/claim-BGOUqoMq.d.ts.map +1 -0
  27. package/dist/cli.js +3 -3
  28. package/dist/contract/index.d.ts +4 -4
  29. package/dist/contract/index.js +8 -8
  30. package/dist/{default-registry-m2jhbG6Q.js → default-registry-16I-Bxlf.js} +2 -2
  31. package/dist/{default-registry-m2jhbG6Q.js.map → default-registry-16I-Bxlf.js.map} +1 -1
  32. package/dist/{define-agent-eval-98sgUaC1.js → define-agent-eval-DPizhHfy.js} +4 -4
  33. package/dist/{define-agent-eval-98sgUaC1.js.map → define-agent-eval-DPizhHfy.js.map} +1 -1
  34. package/dist/{define-agent-eval-q6890HU4.d.ts → define-agent-eval-DblGedQk.d.ts} +4 -3
  35. package/dist/define-agent-eval-DblGedQk.d.ts.map +1 -0
  36. package/dist/diagnosis/index.d.ts +14 -2
  37. package/dist/diagnosis/index.d.ts.map +1 -1
  38. package/dist/diagnosis/index.js +11 -4
  39. package/dist/diagnosis/index.js.map +1 -1
  40. package/dist/{dspy-rlm-engine-DLYttKBm.js → dspy-rlm-engine-Cs5LzJ-f.js} +3 -3
  41. package/dist/{dspy-rlm-engine-DLYttKBm.js.map → dspy-rlm-engine-Cs5LzJ-f.js.map} +1 -1
  42. package/dist/{eval-campaign-C0Q1Eeo_.js → eval-campaign-CwsBn0Gm.js} +2 -2
  43. package/dist/{eval-campaign-C0Q1Eeo_.js.map → eval-campaign-CwsBn0Gm.js.map} +1 -1
  44. package/dist/experiment/index.d.ts +2 -1
  45. package/dist/experiment/index.d.ts.map +1 -1
  46. package/dist/experiment/index.js +1 -1
  47. package/dist/exporters-XMCYJlqT.d.ts +161 -0
  48. package/dist/exporters-XMCYJlqT.d.ts.map +1 -0
  49. package/dist/{external-optimizer-process-C3quNeKV.js → external-optimizer-process-BnSmrkgL.js} +3 -3
  50. package/dist/{external-optimizer-process-C3quNeKV.js.map → external-optimizer-process-BnSmrkgL.js.map} +1 -1
  51. package/dist/{external-optimizer-subprocess-BDwgKLO1.js → external-optimizer-subprocess-kbcPu5po.js} +3 -3
  52. package/dist/{external-optimizer-subprocess-BDwgKLO1.js.map → external-optimizer-subprocess-kbcPu5po.js.map} +1 -1
  53. package/dist/{feedback-trajectory-B3ZSkfAq.d.ts → feedback-trajectory-BYjh7NEM.d.ts} +2 -2
  54. package/dist/{feedback-trajectory-B3ZSkfAq.d.ts.map → feedback-trajectory-BYjh7NEM.d.ts.map} +1 -1
  55. package/dist/{index-CnJOPR_E.d.ts → index-CJv56rhX.d.ts} +673 -244
  56. package/dist/index-CJv56rhX.d.ts.map +1 -0
  57. package/dist/{index-Dk1dOUfm.d.ts → index-CWoIJHmy.d.ts} +4 -4
  58. package/dist/{index-Dk1dOUfm.d.ts.map → index-CWoIJHmy.d.ts.map} +1 -1
  59. package/dist/{index-Bcc9PkOz.d.ts → index-D4pC7Tvd.d.ts} +3 -2
  60. package/dist/index-D4pC7Tvd.d.ts.map +1 -0
  61. package/dist/{index-BqDJ6fUK.d.ts → index-I4UJGRno.d.ts} +74 -2
  62. package/dist/index-I4UJGRno.d.ts.map +1 -0
  63. package/dist/index.d.ts +66 -17
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +375 -31
  66. package/dist/index.js.map +1 -1
  67. package/dist/{journal-CDP0Vhx_.js → journal-c3qY0SDP.js} +246 -5
  68. package/dist/journal-c3qY0SDP.js.map +1 -0
  69. package/dist/{kind-factory-BGwN0nE6.js → kind-factory-ByZeXDqF.js} +2 -2
  70. package/dist/{kind-factory-BGwN0nE6.js.map → kind-factory-ByZeXDqF.js.map} +1 -1
  71. package/dist/ledger-core/index.d.ts +2 -2
  72. package/dist/ledger-core/index.js +2 -2
  73. package/dist/{llm-client-DF9bPNYA.js → llm-client-KYQBh9C8.js} +2 -2
  74. package/dist/{llm-client-DF9bPNYA.js.map → llm-client-KYQBh9C8.js.map} +1 -1
  75. package/dist/{llm-judge-M_l_WXw2.js → llm-judge-BnxAv7ed.js} +1892 -1378
  76. package/dist/llm-judge-BnxAv7ed.js.map +1 -0
  77. package/dist/mint-C9Lojt1V.d.ts +147 -0
  78. package/dist/mint-C9Lojt1V.d.ts.map +1 -0
  79. package/dist/openapi.json +1 -1
  80. package/dist/pipelines/index.d.ts +1 -1
  81. package/dist/pipelines/index.js +1 -1
  82. package/dist/pipelines/index.js.map +1 -1
  83. package/dist/{produced-state-BOY98IJO.js → produced-state-BXjXJHJT.js} +4 -4
  84. package/dist/{produced-state-BOY98IJO.js.map → produced-state-BXjXJHJT.js.map} +1 -1
  85. package/dist/{raw-provider-sink-C96CcqeG.js → raw-provider-sink-DYh4Bszw.js} +2 -2
  86. package/dist/{raw-provider-sink-C96CcqeG.js.map → raw-provider-sink-DYh4Bszw.js.map} +1 -1
  87. package/dist/{redact-DxwlUAvh.js → redact-B7rt9Zot.js} +130 -10
  88. package/dist/redact-B7rt9Zot.js.map +1 -0
  89. package/dist/{redact-DPoH1-OW.d.ts → redact-CopuMxll.d.ts} +7 -5
  90. package/dist/redact-CopuMxll.d.ts.map +1 -0
  91. package/dist/rl.d.ts +3 -2
  92. package/dist/rl.d.ts.map +1 -1
  93. package/dist/rl.js +1 -1
  94. package/dist/rollout/index.d.ts +3 -2
  95. package/dist/search-ledger-types-C9anU2DX.d.ts +489 -0
  96. package/dist/search-ledger-types-C9anU2DX.d.ts.map +1 -0
  97. package/dist/{semantic-concept-judge-Cm2K2wAo.js → semantic-concept-judge-ClB73cei.js} +6 -6
  98. package/dist/{semantic-concept-judge-Cm2K2wAo.js.map → semantic-concept-judge-ClB73cei.js.map} +1 -1
  99. package/dist/{server-C8XvqCg8.js → server-DtetGGoA.js} +2 -2
  100. package/dist/{server-C8XvqCg8.js.map → server-DtetGGoA.js.map} +1 -1
  101. package/dist/{skillopt-optimization-method-BVSB676o.js → skillopt-optimization-method-l2vDBtKp.js} +363 -18
  102. package/dist/skillopt-optimization-method-l2vDBtKp.js.map +1 -0
  103. package/dist/{spans-W0o8pbEg.d.ts → spans-BWtjk_9c.d.ts} +2 -2
  104. package/dist/{spans-W0o8pbEg.d.ts.map → spans-BWtjk_9c.d.ts.map} +1 -1
  105. package/dist/{statistical-heldout-plAHG82H.d.ts → statistical-heldout-CLpjYffJ.d.ts} +2 -36
  106. package/dist/statistical-heldout-CLpjYffJ.d.ts.map +1 -0
  107. package/dist/{store-otlp-D0AV4cvB.js → store-otlp-84DH0OEH.js} +2 -2
  108. package/dist/{store-otlp-D0AV4cvB.js.map → store-otlp-84DH0OEH.js.map} +1 -1
  109. package/dist/{store-tool-spans-8PAyhRqb.d.ts → store-tool-spans-BBXs8hDP.d.ts} +2 -2
  110. package/dist/{store-tool-spans-8PAyhRqb.d.ts.map → store-tool-spans-BBXs8hDP.d.ts.map} +1 -1
  111. package/dist/{store-tool-spans-B_0mXvYl.js → store-tool-spans-DUiqyHvR.js} +5 -5
  112. package/dist/{store-tool-spans-B_0mXvYl.js.map → store-tool-spans-DUiqyHvR.js.map} +1 -1
  113. package/dist/traces.d.ts +3 -63
  114. package/dist/traces.d.ts.map +1 -1
  115. package/dist/traces.js +6 -195
  116. package/dist/traces.js.map +1 -1
  117. package/dist/wire/index.d.ts +1 -1
  118. package/dist/wire/index.js +1 -1
  119. package/docs/adapters-observability.md +31 -27
  120. package/docs/charter.md +1 -1
  121. package/docs/design/mlbenchmarks-book-review.md +1 -1
  122. package/docs/distributed-driver.md +1 -5
  123. package/docs/experiment.md +15 -0
  124. package/docs/public-api.md +181 -71
  125. package/docs/redaction.md +7 -1
  126. package/docs/search-ledger.md +174 -0
  127. package/docs/trace-contracts.md +48 -3
  128. package/package.json +1 -1
  129. package/dist/benchmark-command-BhhAYstU.js.map +0 -1
  130. package/dist/campaign-BWoSQPSU.js.map +0 -1
  131. package/dist/campaign-evidence-CBlGJ3kC.js.map +0 -1
  132. package/dist/define-agent-eval-q6890HU4.d.ts.map +0 -1
  133. package/dist/index-Bcc9PkOz.d.ts.map +0 -1
  134. package/dist/index-BqDJ6fUK.d.ts.map +0 -1
  135. package/dist/index-CnJOPR_E.d.ts.map +0 -1
  136. package/dist/journal-CDP0Vhx_.js.map +0 -1
  137. package/dist/llm-judge-M_l_WXw2.js.map +0 -1
  138. package/dist/mint-DsS38v5c.d.ts +0 -305
  139. package/dist/mint-DsS38v5c.d.ts.map +0 -1
  140. package/dist/redact-DPoH1-OW.d.ts.map +0 -1
  141. package/dist/redact-DxwlUAvh.js.map +0 -1
  142. package/dist/search-ledger-types-D7KDVg-o.d.ts +0 -302
  143. package/dist/search-ledger-types-D7KDVg-o.d.ts.map +0 -1
  144. package/dist/skillopt-optimization-method-BVSB676o.js.map +0 -1
  145. package/dist/statistical-heldout-plAHG82H.d.ts.map +0 -1
  146. package/docs/search-history-receipts.md +0 -233
@@ -1,11 +1,16 @@
1
1
  # Composing agent-eval with your observability stack
2
2
 
3
- `@tangle-network/agent-eval` ships its own OpenTelemetry pipeline
4
- (`createOtelExporter`, from `@tangle-network/agent-eval/traces`) that
5
- emits spans for every cell, judge invocation, mutator proposal, and
6
- gate decision. **It's just OTel**: same protocol as Langfuse SDK,
7
- OpenLLMetry, Arize Phoenix, TraceAI, and the OpenTelemetry GenAI
8
- semantic conventions.
3
+ `@tangle-network/agent-eval` records runs and spans in a `TraceStore` and
4
+ writes them as OTLP/JSON: `exportRunAsOtlp(store, runId)` for one run and
5
+ `convertTraceStoresToOtlp` for a directory of stores, both from
6
+ `@tangle-network/agent-eval/traces`. **It's just OTel**: same protocol as
7
+ Langfuse SDK, OpenLLMetry, Arize Phoenix, TraceAI, and the OpenTelemetry
8
+ GenAI semantic conventions.
9
+
10
+ To stream spans to a collector while a run executes, use
11
+ `createOtelExporter` from `@tangle-network/agent-runtime`. It bounds its
12
+ queue, checks every response, and counts written and dropped spans, so a
13
+ missing trace is never mistaken for an empty run.
9
14
 
10
15
  That means: if you already instrument your agent with any OTel-native
11
16
  observability tool, the two compose **for free at the protocol layer**.
@@ -18,11 +23,10 @@ code required.
18
23
  2. Configure your observability tool (TraceAI / Langfuse / OpenLLMetry /
19
24
  Phoenix) to register its instrumentations against a tracer provider that
20
25
  points at that endpoint.
21
- 3. Configure agent-eval's exporter (`createOtelExporter`, from
22
- `@tangle-network/agent-eval/traces`) against the same endpoint. It has no
23
- `@opentelemetry/*` SDK dependency of its own — it reads
24
- `OTEL_EXPORTER_OTLP_ENDPOINT` / `OTEL_EXPORTER_OTLP_HEADERS` directly, so
25
- pointing both sides at the same collector is usually just sharing env vars.
26
+ 3. Post agent-eval's OTLP export (`exportRunAsOtlp`) to the same endpoint's
27
+ `/v1/traces`, or stream with agent-runtime's `createOtelExporter`, which
28
+ reads `OTEL_EXPORTER_OTLP_ENDPOINT` / `OTEL_EXPORTER_OTLP_HEADERS`.
29
+ Neither needs an `@opentelemetry/*` SDK dependency.
26
30
  4. Run a campaign. Both sets of spans land at your OTel collector.
27
31
  5. Filter / route / fan-out at the collector layer: Jaeger, Tempo,
28
32
  Phoenix, Langfuse cloud, your private collector, whatever.
@@ -63,8 +67,8 @@ it*. Unified at the trace level, you see both as one timeline per cell.
63
67
  - OSS auto-instrumentation library; OTel-native by design.
64
68
  - Wide framework coverage (LangChain, LlamaIndex, Haystack, OpenAI,
65
69
  Anthropic).
66
- - Compose: set up Traceloop's exporter; agent-eval's exporter shares
67
- the same trace context per cell.
70
+ - Compose: set up Traceloop's exporter and post agent-eval's OTLP export
71
+ to the same collector.
68
72
 
69
73
  ### Arize Phoenix
70
74
 
@@ -93,18 +97,18 @@ provider.register()
93
97
  // Example for TraceAI / OpenLLMetry / Langfuse: call their init.
94
98
  // (See each tool's docs.)
95
99
 
96
- // 3. agent-eval's exporter is not built on the OTel SDK provider above —
97
- // it's a minimal OTLP/JSON poster with no `@opentelemetry/*` dependency
98
- // of its own. It reads the same OTEL_EXPORTER_OTLP_ENDPOINT env var, so
99
- // pointing it at the same collector is usually the only step needed:
100
- import { createOtelExporter } from '@tangle-network/agent-eval/traces'
101
- const exporter = createOtelExporter() // undefined if no endpoint is configured
102
- // Feed it spans as your campaign's TraceEmitter closes them; call
103
- // `exporter?.shutdown()` when the campaign ends to flush pending spans.
104
-
105
- // 4. Run your campaign: both sets of spans land at the collector.
106
- import { runEval } from '@tangle-network/agent-eval/contract'
107
- await runEval({ /* ... */ })
100
+ // 3. Run your campaign, then post each run's OTLP/JSON to the same collector.
101
+ // exportRunAsOtlp is not built on the OTel SDK provider above and needs no
102
+ // `@opentelemetry/*` dependency. Check the response: a collector that
103
+ // refuses the batch is a lost trace, not an empty one.
104
+ import { exportRunAsOtlp } from '@tangle-network/agent-eval/traces'
105
+ const body = await exportRunAsOtlp(store, runId)
106
+ const res = await fetch('http://localhost:4318/v1/traces', {
107
+ method: 'POST',
108
+ headers: { 'content-type': 'application/json' },
109
+ body: JSON.stringify(body),
110
+ })
111
+ if (!res.ok) throw new Error(`collector refused the trace: HTTP ${res.status}`)
108
112
  ```
109
113
 
110
114
  That's it. No new adapter shipping required: the libs are already
@@ -132,8 +136,8 @@ works today without them.
132
136
 
133
137
  No new dependencies. No new peer deps. No `@traceai/*`, no
134
138
  `@langfuse/*`, no `@opentelemetry/*` in our manifest. You bring the
135
- observability stack you want; agent-eval's exporter emits the same
136
- OTLP wire format independently, keyed on the endpoint you point it at.
139
+ observability stack you want; agent-eval's OTLP export is the same wire
140
+ format, posted to the endpoint you choose.
137
141
 
138
142
 
139
143
  ## Supervisor-run resource receipts
package/docs/charter.md CHANGED
@@ -36,7 +36,7 @@ Outcome association can motivate an experiment; it cannot establish that changin
36
36
 
37
37
  **Can another reader verify the evidence?**
38
38
  [Evidence receipts](./experiment.md) bind reports to declared identities and provenance.
39
- [Search-history receipts](./search-history-receipts.md) account for planned and attempted search slots.
39
+ The [search ledger](./search-ledger.md) records every node, edge and cell of a search, and its receipt proves the search closed.
40
40
  [Verdict certifications](./verdicts.md) name the checker and its unverified assumptions.
41
41
  The [evidence registry](../evidence/README.md) retains published measurements and their freshness state.
42
42
 
@@ -116,7 +116,7 @@ These are implementation findings, not an assessment of adoption in every consum
116
116
  | Sequential testing | [sequential gate](../../src/campaign/gates/sequential.ts), [e-process](../../src/statistics/sequential-eprocess.ts) | Present. Optional stopping within a valid stream differs from adapting hypotheses across streams or counting dependent replicas as independent evidence. |
117
117
  | Search/final separation | [selfImprove](../../src/contract/self-improve.ts), [method comparison](../../src/campaign/presets/compare-optimization-methods.ts) | Present within calls. Final cases are withheld from method inputs. A persistent cross-campaign exposure policy is missing from these paths. |
118
118
  | Dataset identity and access | [Dataset](../../src/dataset.ts), [contamination helpers](../../src/contamination-guard.ts), [labeled store](../../src/campaign/labeled-store/fs-adapter.ts) | Partial. Hashes, split labels, mutation locks, temporal sampling, and access logs exist. They do not establish secrecy, lineage independence, or one-time certification use. |
119
- | Complete search history | [SearchLedger](../../src/campaign/search-ledger.ts), [history receipt documentation](../search-history-receipts.md) | Present. Reuse the canonical ledger; do not create another optimizer event log. Requiring complete history remains a caller policy. |
119
+ | Complete search history | [SearchLedger](../../src/campaign/search-ledger.ts), [search ledger documentation](../search-ledger.md) | Present. Reuse the canonical ledger; do not create another optimizer event log. Requiring complete history remains a caller policy. |
120
120
  | Evidence identity and authority | [EvidenceReceipt](../../src/experiment/evidence-receipt.ts), [campaign receipts](../../src/experiment/campaign-evidence.ts), [registry](../../src/experiment/evidence-record.ts) | Present. These bind identities and preserve declared authority. Hashes and authority labels alone do not prove independent execution or valid sampling. |
121
121
  | Judge quality and drift | [calibration](../../src/judge-calibration.ts), [sentinel](../../src/meta-eval/sentinel.ts), [plants](../../src/meta-eval/plants.ts) | Present. Per-candidate residual bias, ranking validity, and independent evaluator admission need composition. Position and self-preference helpers exist internally; only verbosity has a root public export. |
122
122
  | Multiple objectives | [promotion policy](../../src/campaign/gates/promotion-policy.ts), [production gate](../../src/campaign/gates/default-production-gate.ts) | Present. Per-dimension regression guards and evidence vectors exist. Explicit target-population weights and aggregation sensitivity remain useful additions. |
@@ -142,7 +142,7 @@ round-robin, region-affinity from a previous run, scheduling table).
142
142
  | **Auth** | Bearer token on `Authorization`; pluggable via `auth: string \| () => string \| Promise<string>` for rotation/refresh. |
143
143
  | **Payload size** | Server enforces `maxBodyBytes` (default 10 MB). |
144
144
  | **Traces** | Both ends emit OTel: if both point at the same OTLP collector, you get a unified trace per cell. See `docs/adapters-observability.md`. |
145
- | **Cost** | Worker's `ctx.cost.runPaidCall(...)` writes durable receipts in the worker process. Roll up those receipts server-side and attach them to worker telemetry; they are not forwarded to the coordinator automatically. |
145
+ | **Cost** | Worker's `ctx.cost.runPaidCall(...)` writes durable receipts in the worker's own `CostLedger`. `runDispatchServer` returns them with the artifact; `httpDispatch` replays each one into the coordinator's `ctx.cost`, so the coordinator's `CostLedger` — its summary, its cost ceiling, `CampaignCellResult.costUsd` — sees remote spend exactly like an in-process cell's. A worker whose `contextFactory` never wires a real cost meter (the default `NOOP_COST`) sends no receipts, so a real deployment must wire one. A dispatch that fails after paying for part of its work still returns those receipts with its error, so a remote failure never drops spend on the floor. |
146
146
 
147
147
  ## Running the reference example
148
148
 
@@ -164,10 +164,6 @@ and using `cellPlacement` to fan across many of them.
164
164
 
165
165
  ## Known gaps + follow-ups
166
166
 
167
- - **Cost roll-up across the wire**: worker-side `ctx.cost` observations
168
- stay on the worker. We need to forward them in the response body so
169
- `defaultProductionGate`'s `budgetUsd` ceiling reflects total spend, not
170
- coordinator-side spend. Tracked as a 0.45.x follow-up.
171
167
  - **Per-cell artifact streaming**: when the worker writes intermediate artifacts through `ctx.artifacts.write`, those files remain in worker storage.
172
168
  Multi-worker campaigns need a shared `CampaignStorage` implementation reachable from both sides.
173
169
  This package does not include an S3 or GCS implementation.
@@ -273,6 +273,21 @@ The statistical machinery underneath is re-exported from its existing homes; thi
273
273
  `HypothesisManifest` stays as the lightweight single-metric registration; `sealExperiment` is the full-design registration.
274
274
  The trace-repair admission machinery (`buildDenominatorChain`, oracle determinism, control policy) keeps its repair vocabulary in `./trace-repair`; this module is the general form new experiments should register against.
275
275
 
276
+ ## Bind final measurements to execution evidence
277
+
278
+ `compareOptimizationMethods` and `selfImprove({ method })` accept optional `evidence: CampaignEvidenceContext`.
279
+ It requires the caller's pursuit, evaluator, environment, authority, and attestation provenance.
280
+ Eval does not infer independent authority or certify those external declarations.
281
+
282
+ Each measured baseline and winner receives an `EvidenceReceipt`.
283
+ Eval derives candidate, input-set, output, and result digests from the executed surface and complete campaign.
284
+ A missing or deferred final measurement cannot produce a receipt.
285
+ Receipts describe measurements; they do not override the release gate or replace the method's selected winner.
286
+
287
+ `createCampaignEvidenceReceipt` provides the same binding for other complete campaign consumers.
288
+ Changing an output changes its output digest; changing a judge result changes its measurement digest.
289
+ The final receipt retains caller authority, including `candidate-self-report`, without upgrading it.
290
+
276
291
  ## Where this sits
277
292
 
278
293
  The [charter](./charter.md) describes current package ownership and host responsibilities.