@tangle-network/agent-eval 0.123.0 → 0.123.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +151 -161
  3. package/dist/analyst/index.d.ts +9 -1
  4. package/dist/analyst/index.js +5 -5
  5. package/dist/authenticity/index.js +3 -2
  6. package/dist/authenticity/index.js.map +1 -1
  7. package/dist/belief-state/index.d.ts +45 -5
  8. package/dist/belief-state/index.js +41 -3
  9. package/dist/belief-state/index.js.map +1 -1
  10. package/dist/benchmarks/index.d.ts +2 -1
  11. package/dist/benchmarks/index.js +6 -6
  12. package/dist/campaign/index.d.ts +29 -33
  13. package/dist/campaign/index.js +6 -6
  14. package/dist/{chunk-A5S77LSE.js → chunk-4SOQ4ND2.js} +2 -2
  15. package/dist/{chunk-VJ7T5WIO.js → chunk-5YMKIFYP.js} +3 -3
  16. package/dist/{chunk-U5CHZ5M3.js → chunk-DNVPOYUS.js} +4 -4
  17. package/dist/{chunk-6WX7CBAR.js → chunk-E3HAD4A3.js} +19 -8
  18. package/dist/chunk-E3HAD4A3.js.map +1 -0
  19. package/dist/{chunk-LBAHQOBI.js → chunk-EBDOTTZJ.js} +37 -11
  20. package/dist/chunk-EBDOTTZJ.js.map +1 -0
  21. package/dist/{chunk-XJYR7XFV.js → chunk-GC4ATIKK.js} +1 -1
  22. package/dist/chunk-GC4ATIKK.js.map +1 -0
  23. package/dist/{chunk-HZJF4IUO.js → chunk-HQY7LBV2.js} +3 -3
  24. package/dist/{chunk-NJC7U437.js → chunk-J7S4YM27.js} +6 -5
  25. package/dist/chunk-J7S4YM27.js.map +1 -0
  26. package/dist/{chunk-S3UZOQ5Y.js → chunk-LOW3U7JZ.js} +2 -2
  27. package/dist/{chunk-OYZAPX5G.js → chunk-R226UZOI.js} +2 -2
  28. package/dist/{chunk-GS3FJGUF.js → chunk-RQP5UTK5.js} +120 -14
  29. package/dist/chunk-RQP5UTK5.js.map +1 -0
  30. package/dist/{chunk-DTJ6QUQB.js → chunk-VGRCHJON.js} +39 -7
  31. package/dist/chunk-VGRCHJON.js.map +1 -0
  32. package/dist/{chunk-G2GPNLSX.js → chunk-WMJR67FX.js} +3 -3
  33. package/dist/{chunk-FC5NDO3E.js → chunk-WXQTVEKM.js} +3 -3
  34. package/dist/cli.js +100 -10
  35. package/dist/cli.js.map +1 -1
  36. package/dist/contract/index.d.ts +97 -5
  37. package/dist/contract/index.js +9 -7
  38. package/dist/contract/index.js.map +1 -1
  39. package/dist/control.js +3 -3
  40. package/dist/fuzz.js +3 -2
  41. package/dist/fuzz.js.map +1 -1
  42. package/dist/hosted/index.d.ts +8 -2
  43. package/dist/index.d.ts +10 -2
  44. package/dist/index.js +13 -13
  45. package/dist/index.js.map +1 -1
  46. package/dist/openapi.json +1 -1
  47. package/dist/rl.d.ts +48 -12
  48. package/dist/rl.js +5 -5
  49. package/dist/storyboard/index.js +1 -1
  50. package/dist/storyboard/index.js.map +1 -1
  51. package/dist/traces.js +3 -3
  52. package/dist/wire/index.d.ts +61 -4
  53. package/dist/wire/index.js +2 -2
  54. package/docs/adapters-observability.md +6 -6
  55. package/docs/building-doctrine.md +5 -5
  56. package/docs/concepts.md +29 -29
  57. package/docs/customer-journeys.md +80 -155
  58. package/docs/design/loop-taxonomy.md +26 -27
  59. package/docs/design.md +70 -0
  60. package/docs/distributed-driver.md +14 -14
  61. package/docs/eval-surface-map.md +11 -11
  62. package/docs/hosted-ingest-spec.md +4 -4
  63. package/docs/improvement-glossary.md +38 -38
  64. package/docs/insight-report.md +32 -27
  65. package/docs/multi-shot-optimization.md +8 -8
  66. package/docs/research-report-methodology.md +9 -9
  67. package/docs/self-improvement-map.md +13 -13
  68. package/docs/trace-analysis.md +2 -2
  69. package/docs/wire-protocol.md +16 -16
  70. package/package.json +2 -1
  71. package/dist/chunk-6WX7CBAR.js.map +0 -1
  72. package/dist/chunk-DTJ6QUQB.js.map +0 -1
  73. package/dist/chunk-GS3FJGUF.js.map +0 -1
  74. package/dist/chunk-LBAHQOBI.js.map +0 -1
  75. package/dist/chunk-NJC7U437.js.map +0 -1
  76. package/dist/chunk-XJYR7XFV.js.map +0 -1
  77. package/docs/auto-research-loop-end-to-end.md +0 -186
  78. /package/dist/{chunk-A5S77LSE.js.map → chunk-4SOQ4ND2.js.map} +0 -0
  79. /package/dist/{chunk-VJ7T5WIO.js.map → chunk-5YMKIFYP.js.map} +0 -0
  80. /package/dist/{chunk-U5CHZ5M3.js.map → chunk-DNVPOYUS.js.map} +0 -0
  81. /package/dist/{chunk-HZJF4IUO.js.map → chunk-HQY7LBV2.js.map} +0 -0
  82. /package/dist/{chunk-S3UZOQ5Y.js.map → chunk-LOW3U7JZ.js.map} +0 -0
  83. /package/dist/{chunk-OYZAPX5G.js.map → chunk-R226UZOI.js.map} +0 -0
  84. /package/dist/{chunk-G2GPNLSX.js.map → chunk-WMJR67FX.js.map} +0 -0
  85. /package/dist/{chunk-FC5NDO3E.js.map → chunk-WXQTVEKM.js.map} +0 -0
@@ -668,6 +668,13 @@ interface LlmClientOptions {
668
668
  deadlineMs?: number;
669
669
  /** Total provider attempts. Legacy option name; default 3 (1 initial + 2 retries). */
670
670
  maxRetries?: number;
671
+ /**
672
+ * Transport for requests that declare `jsonSchema`. `native` sends
673
+ * `response_format: json_schema`; `json-object` sends the broadly supported
674
+ * JSON mode and relies on the caller to include the schema in model-visible
675
+ * instructions. Default: `native`.
676
+ */
677
+ jsonSchemaTransport?: 'native' | 'json-object';
671
678
  /** Fetch implementation — defaults to global `fetch`. Override for custom transport (e.g. tests). */
672
679
  fetch?: typeof fetch;
673
680
  /**
@@ -691,6 +698,29 @@ interface LlmClientOptions {
691
698
  /** Override the redaction strategy for this call. Defaults to `defaultProviderRedactor`. */
692
699
  redactor?: ProviderRedactor;
693
700
  }
701
+ interface LlmRouteRequirements {
702
+ /**
703
+ * Throw if `opts.baseUrl` is undefined, i.e. the call would fall back to
704
+ * `DEFAULT_BASE_URL`. Set this for evaluation runs where silently using
705
+ * the public/free-tier router is a defect — the launch reviewer needs to
706
+ * know exactly which provider answered.
707
+ */
708
+ requireExplicitBaseUrl?: boolean;
709
+ /**
710
+ * Allowlist of acceptable base URLs. Strings match by prefix
711
+ * (case-insensitive); RegExps test against the full base URL.
712
+ */
713
+ allowedBaseUrls?: Array<string | RegExp>;
714
+ /** Blocklist that takes precedence over `allowedBaseUrls`. */
715
+ blockedBaseUrls?: Array<string | RegExp>;
716
+ /** Throw if no auth header / api key is configured. */
717
+ requireAuth?: boolean;
718
+ /**
719
+ * Logical provider id the configured `baseUrl` is expected to match (via
720
+ * `providerFromBaseUrl`). Mainly useful when paired with `requireExplicitBaseUrl`.
721
+ */
722
+ expectedProvider?: string;
723
+ }
694
724
 
695
725
  declare const RubricDimensionSchema: z.ZodObject<{
696
726
  id: z.ZodString;
@@ -1124,6 +1154,8 @@ interface HandleJudgeOptions {
1124
1154
  costLedger?: CostLedgerHandle;
1125
1155
  costPhase?: string;
1126
1156
  llm?: LlmClientOptions;
1157
+ defaultModel?: string;
1158
+ routeRequirements?: LlmRouteRequirements;
1127
1159
  signal?: AbortSignal;
1128
1160
  }
1129
1161
  declare function handleJudge(req: JudgeRequest, options?: HandleJudgeOptions): Promise<JudgeResult>;
@@ -1161,6 +1193,20 @@ declare function handleFeedbackIngest(req: FeedbackTrajectory, stores: Ingestion
1161
1193
 
1162
1194
  declare function buildOpenApi(packageVersion: string): OpenAPIObject;
1163
1195
 
1196
+ /**
1197
+ * stdio RPC transport.
1198
+ *
1199
+ * For batch / cron use without a running server. The Python client falls
1200
+ * back to this when no server is reachable.
1201
+ *
1202
+ * Protocol (line-delimited JSON over stdin/stdout):
1203
+ * IN: one JSON object on stdin: {"method":"judge","params":{...}}
1204
+ * OUT: one JSON object on stdout: {"result":{...}} or {"error":{...}}
1205
+ *
1206
+ * One request per process invocation. To pipeline many calls, the client
1207
+ * writes JSONL to stdin and reads JSONL from stdout — see batch mode below.
1208
+ */
1209
+
1164
1210
  interface RpcRequest {
1165
1211
  method: 'judge' | 'listRubrics' | 'version';
1166
1212
  params?: unknown;
@@ -1175,11 +1221,16 @@ interface RpcError {
1175
1221
  details?: unknown;
1176
1222
  };
1177
1223
  }
1178
- declare function dispatchRpc(req: RpcRequest): Promise<RpcSuccess | RpcError>;
1224
+ interface RpcOptions {
1225
+ llm?: LlmClientOptions;
1226
+ judgeModel?: string;
1227
+ llmRouteRequirements?: LlmRouteRequirements;
1228
+ }
1229
+ declare function dispatchRpc(req: RpcRequest, options?: RpcOptions): Promise<RpcSuccess | RpcError>;
1179
1230
  /** Read one JSON request from stdin, write one JSON response to stdout. */
1180
- declare function runRpcOnce(method?: string): Promise<number>;
1231
+ declare function runRpcOnce(method?: string, options?: RpcOptions): Promise<number>;
1181
1232
  /** Read JSONL requests from stdin, write JSONL responses to stdout. */
1182
- declare function runRpcBatch(method?: string): Promise<number>;
1233
+ declare function runRpcBatch(method?: string, options?: RpcOptions): Promise<number>;
1183
1234
 
1184
1235
  /**
1185
1236
  * Built-in rubrics shipped with agent-eval.
@@ -1218,6 +1269,12 @@ declare function listBuiltinRubrics(): {
1218
1269
  interface CreateAppOptions {
1219
1270
  /** Stores wired to the ingestion endpoints. */
1220
1271
  stores?: IngestionStores;
1272
+ /** Model provider used by `/v1/judge`. */
1273
+ llm?: LlmClientOptions;
1274
+ /** Default judge model when a request does not provide one. */
1275
+ judgeModel?: string;
1276
+ /** Model route checks applied before every judge call. */
1277
+ llmRouteRequirements?: LlmRouteRequirements;
1221
1278
  /**
1222
1279
  * Bearer-token auth. When provided, every endpoint EXCEPT `/healthz`
1223
1280
  * and `/v1/version` requires `Authorization: Bearer <token>`. The
@@ -1257,4 +1314,4 @@ interface StartedServer {
1257
1314
  */
1258
1315
  declare function startServerAsync(opts?: ServeOptions): Promise<StartedServer>;
1259
1316
 
1260
- export { BUILTIN_RUBRICS, type ErrorResponse, ErrorResponseSchema, type FailureMode, FailureModeSchema, FeedbackAttemptSchema, type FeedbackIngestResponse, FeedbackIngestResponseSchema, FeedbackLabelSchema, type FeedbackTrajectory, FeedbackTrajectorySchema, type HandleJudgeOptions, HealthResponseSchema, type IngestionStores, type JudgeRequest, JudgeRequestSchema, type JudgeResult, JudgeResultSchema, type ListRubricsResponse, ListRubricsResponseSchema, type Rubric, type RubricDimension, RubricDimensionSchema, type RubricInfo, RubricInfoSchema, RubricSchema, type ServeOptions, type StartedServer, type TraceEvent, TraceEventSchema, type TracesIngestRequest, TracesIngestRequestSchema, type TracesIngestResponse, TracesIngestResponseSchema, type VersionResponse, VersionResponseSchema, WIRE_VERSION, WireError, buildOpenApi, createApp, dispatchRpc, getBuiltinRubric, handleFeedbackIngest, handleJudge, handleListRubrics, handleTracesIngest, handleVersion, hashRubric, listBuiltinRubrics, runRpcBatch, runRpcOnce, startServer, startServerAsync };
1317
+ export { BUILTIN_RUBRICS, type ErrorResponse, ErrorResponseSchema, type FailureMode, FailureModeSchema, FeedbackAttemptSchema, type FeedbackIngestResponse, FeedbackIngestResponseSchema, FeedbackLabelSchema, type FeedbackTrajectory, FeedbackTrajectorySchema, type HandleJudgeOptions, HealthResponseSchema, type IngestionStores, type JudgeRequest, JudgeRequestSchema, type JudgeResult, JudgeResultSchema, type ListRubricsResponse, ListRubricsResponseSchema, type RpcOptions, type Rubric, type RubricDimension, RubricDimensionSchema, type RubricInfo, RubricInfoSchema, RubricSchema, type ServeOptions, type StartedServer, type TraceEvent, TraceEventSchema, type TracesIngestRequest, TracesIngestRequestSchema, type TracesIngestResponse, TracesIngestResponseSchema, type VersionResponse, VersionResponseSchema, WIRE_VERSION, WireError, buildOpenApi, createApp, dispatchRpc, getBuiltinRubric, handleFeedbackIngest, handleJudge, handleListRubrics, handleTracesIngest, handleVersion, hashRubric, listBuiltinRubrics, runRpcBatch, runRpcOnce, startServer, startServerAsync };
@@ -34,8 +34,8 @@ import {
34
34
  runRpcOnce,
35
35
  startServer,
36
36
  startServerAsync
37
- } from "../chunk-LBAHQOBI.js";
38
- import "../chunk-NJC7U437.js";
37
+ } from "../chunk-EBDOTTZJ.js";
38
+ import "../chunk-J7S4YM27.js";
39
39
  import "../chunk-BGVTIE2C.js";
40
40
  import "../chunk-VI2UW6B6.js";
41
41
  import "../chunk-PC4UYEBM.js";
@@ -3,7 +3,7 @@
3
3
  `@tangle-network/agent-eval` ships its own OpenTelemetry pipeline
4
4
  (`@tangle-network/agent-eval/telemetry`) that emits spans for every
5
5
  cell, judge invocation, mutator proposal, and gate decision. **It's
6
- just OTel** same protocol as Langfuse SDK, OpenLLMetry, Arize
6
+ just OTel**: same protocol as Langfuse SDK, OpenLLMetry, Arize
7
7
  Phoenix, TraceAI, and the OpenTelemetry GenAI semantic conventions.
8
8
 
9
9
  That means: if you already instrument your agent with any OTel-native
@@ -11,14 +11,14 @@ observability tool, the two compose **for free at the protocol layer**.
11
11
  This doc shows the composition pattern; no agent-eval-specific adapter
12
12
  code required.
13
13
 
14
- ## TL;DR one OTel context, two emitters
14
+ ## TL;DR: one OTel context, two emitters
15
15
 
16
16
  1. Set up a shared OTel tracer provider in your process (or service mesh).
17
17
  2. Configure your observability tool (TraceAI / Langfuse / OpenLLMetry /
18
18
  Phoenix) to register its instrumentations against that provider.
19
19
  3. Configure agent-eval's `/telemetry` exporter against the same provider.
20
20
  4. Run a campaign. Both sets of spans land at your OTel collector.
21
- 5. Filter / route / fan-out at the collector layer Jaeger, Tempo,
21
+ 5. Filter / route / fan-out at the collector layer: Jaeger, Tempo,
22
22
  Phoenix, Langfuse cloud, your private collector, whatever.
23
23
 
24
24
  The Tangle substrate doesn't compete with the observability tool;
@@ -92,7 +92,7 @@ provider.addSpanProcessor(new SimpleSpanProcessor(
92
92
  provider.register()
93
93
 
94
94
  // 2. Your observability tool registers against the global provider.
95
- // Example for TraceAI / OpenLLMetry / Langfuse call their init.
95
+ // Example for TraceAI / OpenLLMetry / Langfuse: call their init.
96
96
  // (See each tool's docs.)
97
97
 
98
98
  // 3. agent-eval is already OTel-native; it picks up the same global
@@ -101,12 +101,12 @@ provider.register()
101
101
  import { setOtelExporter } from '@tangle-network/agent-eval/telemetry'
102
102
  setOtelExporter({ kind: 'otel-global' }) // use the global provider
103
103
 
104
- // 4. Run your campaign both sets of spans land at the collector.
104
+ // 4. Run your campaign: both sets of spans land at the collector.
105
105
  import { runEval } from '@tangle-network/agent-eval/contract'
106
106
  await runEval({ /* ... */ })
107
107
  ```
108
108
 
109
- That's it. No new adapter shipping required the libs are already
109
+ That's it. No new adapter shipping required: the libs are already
110
110
  designed to live in the same OTel ecosystem.
111
111
 
112
112
  ## When you'd want a deeper, code-level adapter
@@ -4,7 +4,7 @@ How every fleet agent that consumes `agent-eval` is built. Each rule is mechanic
4
4
 
5
5
  ## 1. Defaults must be provably reachable
6
6
 
7
- Every hard-coded model id or endpoint default is verifiable against the live router. Membership in `{baseUrl}/models` is the free check; an optional 1-token probe per model confirms the router will actually serve it. A default the router cannot serve is a config bug caught before the run, not a runtime surprise that silently degrades into a stub. Backend ids are namespaced by binding: cli-bridge ids (`claude-code/*`, `kimi-code/*`, `opencode/*`) never appear as defaults in code reachable from production bridge use is an explicit env opt-in, never an implicit fallback.
7
+ Every hard-coded model id or endpoint default is verifiable against the live router. Membership in `{baseUrl}/models` is the free check; an optional 1-token probe per model confirms the router will actually serve it. A default the router cannot serve is a config bug caught before the run, not a runtime surprise that silently degrades into a stub. Backend ids are namespaced by binding: cli-bridge ids (`claude-code/*`, `kimi-code/*`, `opencode/*`) never appear as defaults in code reachable from production: bridge use is an explicit env opt-in, never an implicit fallback.
8
8
 
9
9
  Enforced by: `preflightModels` (membership + optional probe) and `assertModelsServed` (gate that names every unreachable id with status + detail).
10
10
 
@@ -12,13 +12,13 @@ Enforced by: `preflightModels` (membership + optional probe) and `assertModelsSe
12
12
 
13
13
  When a request fails, one direct call against the live endpoint bisects platform-versus-client before any code-level debugging begins. A 401 from the router on a `model_not_found` is the platform telling you the default is dead; a connection refused is the platform being unreachable. Establish which side is at fault with a probe first, then debug only the side that is actually broken.
14
14
 
15
- Enforced by: `preflightModels({ probe: true })` the probe is the platform-side bisection, carrying the router's own `error.message` back to the caller.
15
+ Enforced by: `preflightModels({ probe: true })`: the probe is the platform-side bisection, carrying the router's own `error.message` back to the caller.
16
16
 
17
17
  ## 3. Agent-produced findings are hypotheses
18
18
 
19
19
  Enumeration of candidate problems may fan out to agents, but agent output is not evidence. Truth comes from probes against ground truth, not from an agent's assertion. Every classification carries quoted evidence, and nothing unverified is merged or reported as fact. A confident-sounding agent claim with no probe behind it is a hypothesis awaiting falsification.
20
20
 
21
- Enforced by: `assertRealBackend` over the resulting `RunRecord[]` an agent that claims success while the backend was never called reads as a stub, not a pass.
21
+ Enforced by: `assertRealBackend` over the resulting `RunRecord[]`: an agent that claims success while the backend was never called reads as a stub, not a pass.
22
22
 
23
23
  ## 4. Experiment integrity checklist
24
24
 
@@ -30,7 +30,7 @@ Any lift or benchmark claim satisfies all of the following before it is reported
30
30
  - The same scorer and the same items on both sides of any comparison.
31
31
  - A leakage check from builder inputs into the evaluation set.
32
32
  - Cross-family judge panels, with inter-rater reliability reported and gated.
33
- - Missing evidence is never scored as zero fail loud over fabricate.
33
+ - Missing evidence is never scored as zero: fail loud over fabricate.
34
34
  - No optional stopping: the stopping rule is fixed before the run.
35
35
 
36
36
  Enforced by: `pairedBootstrap` (CI), `assertCrossFamily` (panel diversity), `interRaterReliability` (agreement), and `assertRealBackend` (no stub run masquerading as a result).
@@ -39,4 +39,4 @@ Enforced by: `pairedBootstrap` (CI), `assertCrossFamily` (panel diversity), `int
39
39
 
40
40
  A drifted default is the symptom of a missing convention. The fix ships the convention and its guard alongside the one-line correction, so the same drift cannot recur silently. Patching the single dead id without adding the preflight gate leaves the class open; the next default rots the same way.
41
41
 
42
- Enforced by: `assertModelsServed` wired into the campaign preflight the guard that turns "this one model was dead" into "no campaign spends tokens against an unreachable default."
42
+ Enforced by: `assertModelsServed` wired into the campaign preflight: the guard that turns "this one model was dead" into "no campaign spends tokens against an unreachable default."
package/docs/concepts.md CHANGED
@@ -16,17 +16,17 @@ can; drop to the raw functions when you need lower-level control.
16
16
 
17
17
  | Function | When to call it | What you give it | What you get back |
18
18
  |---|---|---|---|
19
- | **`defineAgentEval()`** | You have scenarios, an agent, a judge, and a baseline surface, and you want one object you can score or improve. | scenarios, agent, judge, baseline surface | `{ evaluate(), improve() }` where `evaluate()` returns a campaign result and `improve()` returns a decision packet |
20
- | **`selfImprove()`** | You have a closed loop scenarios, judge, agent in hand, and you want the substrate to propose better candidates + gate them. | scenarios, agent, judge, baseline surface | `SelfImproveResult.insight: InsightReport` + ship/hold verdict + winner surface |
19
+ | **`defineAgentEval()`** | You have scenarios, an agent, a judge, and a baseline surface, and you want one object you can score or improve. | scenarios, agent, judge, baseline surface | `{ evaluate(), improve() }` where `evaluate()` returns a campaign result and `improve()` returns a report |
20
+ | **`selfImprove()`** | You have a closed loop: scenarios, judge, agent in hand, and you want the substrate to propose better candidates + gate them. | scenarios, agent, judge, baseline surface | `SelfImproveResult.insight: InsightReport` + ship/hold verdict + winner surface |
21
21
  | **`loadEvalFixtureScenarios()`** | You want agents to add evals as folders with `PROMPT.md`, checks, and starter files. | `evals/<name>/PROMPT.md + EVAL.ts + package.json` | `Scenario[]` that runs through `runCampaign`; pair with `planEvalFixtureRun()` before spending tokens |
22
22
  | **`analyzeRuns()`** | You have observed runs (production traces, an approve/reject corpus, a CSV gold set) and want the same rigor packet without invoking an agent. | `RunRecord[]` + optional flags | `InsightReport` |
23
- | **Intake adapters** (`fromFeedbackTable`, `fromOtelSpans`) | Your data isn't already in `RunRecord` shape it's in Obsidian, Sheets, an OTel collector, etc. | source-specific input | `RunRecord[]` ready to pipe into `analyzeRuns()` |
23
+ | **Intake adapters** (`fromFeedbackTable`, `fromOtelSpans`) | Your data isn't already in `RunRecord` shape: it's in Obsidian, Sheets, an OTel collector, etc. | source-specific input | `RunRecord[]` ready to pipe into `analyzeRuns()` |
24
24
 
25
- The customer maturity stages logs only → ratings → closed loop map to these
25
+ The customer maturity stages: logs only → ratings → closed loop: map to these
26
26
  entry points. See [`customer-journeys.md`](./customer-journeys.md) for the
27
27
  runnable walkthroughs.
28
28
 
29
- The shape of the answer `InsightReport` is identical across all three paths. Distributional summary, paired-bootstrap lift CI, judge stats, inter-rater agreement, cost-quality Pareto, failure clusters, contamination check, outcome correlation, release axes, and a ranked recommendations array. Walked through section-by-section in [`insight-report.md`](./insight-report.md).
29
+ The shape of the answer: `InsightReport`: is identical across all three paths. Distributional summary, paired-bootstrap lift CI, judge stats, inter-rater agreement, cost-quality Pareto, failure clusters, contamination check, outcome correlation, release axes, and a ranked recommendations array. Walked through section-by-section in [`insight-report.md`](./insight-report.md).
30
30
 
31
31
  ## The layering rule
32
32
 
@@ -39,7 +39,7 @@ The test: *does this concept make sense WITHOUT a running agent loop?* If yes, i
39
39
  | Thing | What it is | One-line example |
40
40
  |---|---|---|
41
41
  | **Judge** | A function that scores one piece of output. | "Did this scaffold implement async fetching?" |
42
- | **Rubric** | The recipe a judge uses what to score on, with what weights. | "Score on buyer_quality (0.5), voice (0.3), signal (0.2)." |
42
+ | **Rubric** | The recipe a judge uses: what to score on, with what weights. | "Score on buyer_quality (0.5), voice (0.3), signal (0.2)." |
43
43
  | **Verifier** | A pipeline of judges run in order, with dependencies. | "install → typecheck → build → semantic" |
44
44
  | **Feedback trajectory** | A multi-shot record of attempts, approvals, rejections, edits, metrics, and policy outcomes. | "draft → user rejects → revised draft → approved → measured" |
45
45
 
@@ -66,7 +66,7 @@ that can seed memory, replay scenarios, and optimization.
66
66
  | **Harness** | A description of *how to run* the artifact: setup command, test command, working dir, timeout. |
67
67
  | **Sandbox driver** | The thing that actually executes commands inside the harness. Local subprocess, or remote container. |
68
68
  | **Layer** | One stage of a verifier pipeline (install, typecheck, build, semantic, …). |
69
- | **Finding** | A specific issue a judge found file, line, severity, message. |
69
+ | **Finding** | A specific issue a judge found: file, line, severity, message. |
70
70
  | **Trace store** | The append-only log of every span/event during a run. Replay = read this back. |
71
71
  | **Composite score** | A 0..1 number combining all dimensions. The single number you gate on. |
72
72
  | **Rubric version** | A stable hash of the rubric. Scores from different rubric versions are not comparable. |
@@ -103,30 +103,30 @@ L1 app-build Does the artifact build / typecheck / test?
103
103
 
104
104
 
105
105
  L2 app-runtime Does the artifact actually run end-to-end?
106
- (Dynamic signal only worth checking if L1 passed.)
106
+ (Dynamic signal: only worth checking if L1 passed.)
107
107
  ```
108
108
 
109
109
  `BuilderSession` orchestrates this. It opens at `startChat`, runs the build at `ship`, runs the runtime check at `runAppScenario`. Each layer emits a trace span. Composite score aggregates them with `scoreProject`.
110
110
 
111
111
  Why three? Because each catches a different failure mode:
112
- - L0 misses agent crashed mid-generation, you have a half-written file.
113
- - L1 misses files exist but typecheck fails. LLM judges can't reliably catch this.
114
- - L2 misses code compiles but does the wrong thing at runtime.
112
+ - L0 misses: agent crashed mid-generation, you have a half-written file.
113
+ - L1 misses: files exist but typecheck fails. LLM judges can't reliably catch this.
114
+ - L2 misses: code compiles but does the wrong thing at runtime.
115
115
 
116
116
  If you only check one layer, you ship the bugs that the other two layers would have caught.
117
117
 
118
118
  ## How rubrics work
119
119
 
120
120
  A rubric describes:
121
- 1. **Dimensions** the axes you score on (e.g. `buyer_quality`, `voice`, `signal`).
122
- 2. **Weights** how to combine dimensions into a composite (`0.5 * buyer_quality + 0.3 * voice + 0.2 * signal`).
123
- 3. **Failure modes** named patterns the judge looks for ("ai-cadence", "vague-claim").
124
- 4. **Wins** named positive patterns ("specific-component", "earned-detail").
125
- 5. **System prompt** what to tell the judging LLM about the persona and the task.
121
+ 1. **Dimensions**: the axes you score on (e.g. `buyer_quality`, `voice`, `signal`).
122
+ 2. **Weights**: how to combine dimensions into a composite (`0.5 * buyer_quality + 0.3 * voice + 0.2 * signal`).
123
+ 3. **Failure modes**: named patterns the judge looks for ("ai-cadence", "vague-claim").
124
+ 4. **Wins**: named positive patterns ("specific-component", "earned-detail").
125
+ 5. **System prompt**: what to tell the judging LLM about the persona and the task.
126
126
 
127
- Built-in rubrics ship in `src/wire/rubrics.ts` (e.g. `anti-slop` for technical-buyer voice). You can also pass a rubric inline the same shape, just defined at the call site.
127
+ Built-in rubrics ship in `src/wire/rubrics.ts` (e.g. `anti-slop` for technical-buyer voice). You can also pass a rubric inline: the same shape, just defined at the call site.
128
128
 
129
- A rubric is plain data. The hash of that data is the `rubricVersion`. Two scores are only comparable if they used the same `rubricVersion` change the rubric and you start a new comparison series.
129
+ A rubric is plain data. The hash of that data is the `rubricVersion`. Two scores are only comparable if they used the same `rubricVersion`: change the rubric and you start a new comparison series.
130
130
 
131
131
  ## How verifiers work
132
132
 
@@ -141,14 +141,14 @@ const verifier = new MultiLayerVerifier([
141
141
  ])
142
142
 
143
143
  const report = await verifier.run({ env: { runner, workdir, ... } })
144
- report.allPass // boolean every layer passed
145
- report.blendedScore // 0..1 weighted aggregate
144
+ report.allPass // boolean: every layer passed
145
+ report.blendedScore // 0..1: weighted aggregate
146
146
  report.layers // per-layer status, findings, duration
147
147
  ```
148
148
 
149
149
  Two rules that will save you bugs:
150
150
 
151
- 1. **Run both gates.** Build gates catch code that doesn't compile; structural assertions catch missing files. Run both unconditionally they catch orthogonal failures.
151
+ 1. **Run both gates.** Build gates catch code that doesn't compile; structural assertions catch missing files. Run both unconditionally: they catch orthogonal failures.
152
152
 
153
153
  2. **Pair LLM judges with build outcomes.** An LLM judge will rate non-compiling code as "looks right" (0.8). Always short-circuit on `buildOutcome.passed === false` before any LLM judging.
154
154
 
@@ -159,7 +159,7 @@ Two questions to answer before trusting any LLM judge:
159
159
  1. **Does it agree with humans?** `calibrateJudge(golden, candidate)` reports Pearson, MAE, integer-rounded κ, and worst-N miscalibrations vs a human golden set.
160
160
  2. **Does it agree with itself / other judges?** `continuousAgreement(scores)` and `calibrateJudgeContinuous(golden, candidate)` report κ_w + ICC(2,1) + Pearson + Spearman with bootstrap 95% CIs on the raw [0,1] scores.
161
161
 
162
- Why two κ flavours: the original `calibrateJudge` rounds scores to ints before computing κ. For fine-grained judges that loses information 0.78 vs 0.81 both round to "1" and look perfectly agreed. Use `calibrateJudgeContinuous` (or `continuousAgreement` for N≥2 raters) when scores are continuous. ICC(2,1) catches systematic bias that Pearson misses: if judge B scores 2× judge A, Pearson stays ≈ 1 while ICC drops that's the signal.
162
+ Why two κ flavours: the original `calibrateJudge` rounds scores to ints before computing κ. For fine-grained judges that loses information: 0.78 vs 0.81 both round to "1" and look perfectly agreed. Use `calibrateJudgeContinuous` (or `continuousAgreement` for N≥2 raters) when scores are continuous. ICC(2,1) catches systematic bias that Pearson misses: if judge B scores 2× judge A, Pearson stays ≈ 1 while ICC drops: that's the signal.
163
163
 
164
164
  Bias probes (`positionalBias`, `verbosityBias`, `selfPreference`) cover the orthogonal failure modes: position-dependent scoring, length-correlated scoring, and judge-prefers-its-own-family.
165
165
 
@@ -178,7 +178,7 @@ builder-session [span]
178
178
  └── scenario.run [span]
179
179
  ```
180
180
 
181
- Spans are append-only and have stable ids replay is reading the same store back. OTLP export ships them out for distributed tracing.
181
+ Spans are append-only and have stable ids: replay is reading the same store back. OTLP export ships them out for distributed tracing.
182
182
 
183
183
  You usually should not build this tree by hand. Product runtimes,
184
184
  `runAgentControlLoop`, harnesses, and verifiers should emit it while they run.
@@ -187,12 +187,12 @@ release decision.
187
187
 
188
188
  ## Where to go next
189
189
 
190
- - **Confused by "GEPA / HALO / trace analysis / proposers everywhere"?** → [self-improvement-map.md](./self-improvement-map.md) one loop, four roles, the proposer catalog (production vs bench-only), and why `gepa-refine` is the same loop on a test bench.
191
- - **Which `run*` primitive do I use, and how do I grade produced state?** → [eval-surface-map.md](./eval-surface-map.md) the campaign/matrix/optimization/gate primitives as a pick-by-"use-when" table, plus the produced-state grading composition (verifyCompletion-as-judge there is no persona-dispatch wrapper) and the in-band body contract.
192
- - **Need the layman feature map?** → [feature-guide.md](./feature-guide.md) what each primitive does, when to use it, integration patterns, and guardrails.
193
- - **Just want to score a string against a rubric?** → [wire-protocol.md](./wire-protocol.md) HTTP/RPC interface, pluggable from any language.
194
- - **Need a reusable driver/worker/evaluator loop?** → [control-runtime.md](./control-runtime.md) generic runtime plus coding, browser, computer-use, and research integration patterns.
195
- - **Want review feedback to become eval/optimization data?** → [feedback-trajectories.md](./feedback-trajectories.md) turn feedback into datasets, optimizer rows, and preference memory.
190
+ - **Confused by "GEPA / HALO / trace analysis / proposers everywhere"?** → [self-improvement-map.md](./self-improvement-map.md): one loop, four roles, the proposer catalog (production vs bench-only), and why `gepa-refine` is the same loop on a test bench.
191
+ - **Which `run*` primitive do I use, and how do I grade produced state?** → [eval-surface-map.md](./eval-surface-map.md): the campaign/matrix/optimization/gate primitives as a pick-by-"use-when" table, plus the produced-state grading composition (verifyCompletion-as-judge: there is no persona-dispatch wrapper) and the in-band body contract.
192
+ - **Need the layman feature map?** → [feature-guide.md](./feature-guide.md): what each primitive does, when to use it, integration patterns, and guardrails.
193
+ - **Just want to score a string against a rubric?** → [wire-protocol.md](./wire-protocol.md): HTTP/RPC interface, pluggable from any language.
194
+ - **Need a reusable driver/worker/evaluator loop?** → [control-runtime.md](./control-runtime.md): generic runtime plus coding, browser, computer-use, and research integration patterns.
195
+ - **Want review feedback to become eval/optimization data?** → [feedback-trajectories.md](./feedback-trajectories.md): turn feedback into datasets, optimizer rows, and preference memory.
196
196
  - **Building a code-generator eval?** → Start with `BuilderSession`, `SandboxHarness`, and `MultiLayerVerifier`.
197
197
  - **Multi-layer verifier?** → Use [control-runtime.md](./control-runtime.md) and `MultiLayerVerifier` for ordered gates with dependencies.
198
198
  - **Adding a new judge or rubric?** → `src/wire/rubrics.ts` for the cross-language path; `src/anti-slop.ts` and `src/judges.ts` for the in-process path.