@tangle-network/agent-eval 0.102.0 → 0.103.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 (80) hide show
  1. package/dist/adapters/http.d.ts +2 -2
  2. package/dist/adapters/langchain.d.ts +2 -2
  3. package/dist/adapters/otel.d.ts +4 -4
  4. package/dist/analyst/index.d.ts +8 -8
  5. package/dist/{analyze-runs-BlJRBniC.d.ts → analyze-runs-Cd-A_K4l.d.ts} +3 -3
  6. package/dist/belief-state/index.d.ts +3 -3
  7. package/dist/benchmarks/index.d.ts +2 -2
  8. package/dist/campaign/index.d.ts +14 -14
  9. package/dist/campaign/index.js +34 -11
  10. package/dist/campaign/index.js.map +1 -1
  11. package/dist/{chunk-G6S73VA7.js → chunk-2NSLDY4B.js} +3 -2
  12. package/dist/{chunk-G6S73VA7.js.map → chunk-2NSLDY4B.js.map} +1 -1
  13. package/dist/{chunk-4LWD6GC7.js → chunk-6FIAJHCU.js} +2 -2
  14. package/dist/{chunk-PMF5WIBX.js → chunk-7RBJANJD.js} +2 -2
  15. package/dist/{chunk-BOETF6BU.js → chunk-B2TMQM62.js} +2 -2
  16. package/dist/{chunk-QUCGGMYM.js → chunk-HV5PBTJF.js} +3 -3
  17. package/dist/{chunk-CMJSTXUR.js → chunk-IXOV77YF.js} +105 -18
  18. package/dist/chunk-IXOV77YF.js.map +1 -0
  19. package/dist/{chunk-52CCCXU3.js → chunk-NTVWIH24.js} +104 -43
  20. package/dist/chunk-NTVWIH24.js.map +1 -0
  21. package/dist/chunk-RQNOLV3I.js +855 -0
  22. package/dist/chunk-RQNOLV3I.js.map +1 -0
  23. package/dist/{chunk-JCUREYF5.js → chunk-U3IDYATS.js} +2 -2
  24. package/dist/{chunk-LSCBODPQ.js → chunk-XKA6ZGEY.js} +11 -2
  25. package/dist/chunk-XKA6ZGEY.js.map +1 -0
  26. package/dist/{code-agent-session-B6ZcDwyA.d.ts → code-agent-session-Ce-9u7YM.d.ts} +1 -1
  27. package/dist/contract/index.d.ts +16 -16
  28. package/dist/contract/index.js +5 -5
  29. package/dist/{control-DC8TELh0.d.ts → control-C8RmK9H4.d.ts} +1 -1
  30. package/dist/control.d.ts +2 -2
  31. package/dist/control.js +2 -2
  32. package/dist/{corpus-ONOzGFmG.d.ts → corpus-CiSzzLa5.d.ts} +1 -1
  33. package/dist/{default-registry-Dhrc__SE.d.ts → default-registry-ZhqsTr4K.d.ts} +2 -2
  34. package/dist/diagnose.d.ts +3 -3
  35. package/dist/diagnose.js +1 -1
  36. package/dist/{gepa-bxuDoaO9.d.ts → gepa-DeyPTlvx.d.ts} +1 -1
  37. package/dist/hosted/index.d.ts +4 -4
  38. package/dist/{index-W96macmS.d.ts → index-B-bFgiAF.d.ts} +1 -1
  39. package/dist/index.d.ts +27 -23
  40. package/dist/index.js +26 -10
  41. package/dist/index.js.map +1 -1
  42. package/dist/{insight-report-C02J3q4T.d.ts → insight-report-k0sRTzKg.d.ts} +1 -1
  43. package/dist/{kind-factory-OgqQSvLi.d.ts → kind-factory-D0nk7AKV.d.ts} +1 -1
  44. package/dist/meta-eval/index.d.ts +2 -2
  45. package/dist/multishot/index.d.ts +2 -2
  46. package/dist/openapi.json +1 -1
  47. package/dist/{policy-edit-Dccm9tyA.d.ts → policy-edit-BDQzzsBU.d.ts} +2 -2
  48. package/dist/{pre-registration-BjGZf9YA.d.ts → pre-registration-mWG2w8d-.d.ts} +45 -12
  49. package/dist/product-benchmark/index.d.ts +104 -1
  50. package/dist/product-benchmark/index.js +15 -1
  51. package/dist/{provenance-BEITkFII.d.ts → provenance-BhJm32vN.d.ts} +3 -3
  52. package/dist/{release-report-B1tA6pKu.d.ts → release-report-BQ1Ziyu-.d.ts} +2 -2
  53. package/dist/reporting.d.ts +4 -4
  54. package/dist/{researcher-Ba2y1Foi.d.ts → researcher-B_ODTAJs.d.ts} +2 -2
  55. package/dist/rl.d.ts +8 -8
  56. package/dist/rl.js +2 -2
  57. package/dist/{rubric-predictive-validity-w7tun-q3.d.ts → rubric-predictive-validity-0MdjTt8R.d.ts} +1 -1
  58. package/dist/{run-campaign-RF3H6D4U.js → run-campaign-2L4WCJHR.js} +2 -2
  59. package/dist/{run-record-DEwidcqn.d.ts → run-record-MRdJ-Kq2.d.ts} +12 -1
  60. package/dist/{runtime-trajectory-OJDaTYHN.d.ts → runtime-trajectory-8w0_jmtR.d.ts} +1 -1
  61. package/dist/{semantic-concept-judge-J8xvjdc3.d.ts → semantic-concept-judge-D-IlH5v1.d.ts} +2 -2
  62. package/dist/{summary-report-C4uzRWh8.d.ts → summary-report-C0nnxOD8.d.ts} +1 -1
  63. package/dist/traces.d.ts +1 -1
  64. package/dist/traces.js +2 -2
  65. package/dist/{types-fWqEJm7h.d.ts → types-DFI_Z-ZL.d.ts} +18 -1
  66. package/dist/{types-BEzCBMQD.d.ts → types-Dz9cKF0g.d.ts} +1 -1
  67. package/dist/workflow/index.d.ts +4 -4
  68. package/dist/workflow/index.js +1 -1
  69. package/package.json +1 -1
  70. package/dist/chunk-52CCCXU3.js.map +0 -1
  71. package/dist/chunk-63MBSQTX.js +0 -350
  72. package/dist/chunk-63MBSQTX.js.map +0 -1
  73. package/dist/chunk-CMJSTXUR.js.map +0 -1
  74. package/dist/chunk-LSCBODPQ.js.map +0 -1
  75. /package/dist/{chunk-4LWD6GC7.js.map → chunk-6FIAJHCU.js.map} +0 -0
  76. /package/dist/{chunk-PMF5WIBX.js.map → chunk-7RBJANJD.js.map} +0 -0
  77. /package/dist/{chunk-BOETF6BU.js.map → chunk-B2TMQM62.js.map} +0 -0
  78. /package/dist/{chunk-QUCGGMYM.js.map → chunk-HV5PBTJF.js.map} +0 -0
  79. /package/dist/{chunk-JCUREYF5.js.map → chunk-U3IDYATS.js.map} +0 -0
  80. /package/dist/{run-campaign-RF3H6D4U.js.map → run-campaign-2L4WCJHR.js.map} +0 -0
@@ -243,6 +243,7 @@ export {
243
243
  validateRunRecord,
244
244
  isRunRecord,
245
245
  parseRunRecordSafe,
246
- roundTripRunRecord
246
+ roundTripRunRecord,
247
+ modelHasSnapshot
247
248
  };
248
- //# sourceMappingURL=chunk-G6S73VA7.js.map
249
+ //# sourceMappingURL=chunk-2NSLDY4B.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/run-record.ts"],"sourcesContent":["/**\n * Paper-grade RunRecord schema + runtime validator.\n *\n * Every run that participates in a promotion gate, paper table, or\n * researcher loop SHOULD be recorded as a `RunRecord`. The mandatory\n * fields are exactly those the paper \"Two Loops, Three Roles\" requires\n * for reproducibility: who/what/when/cost/seed/hash, plus the search vs\n * holdout split tag and either a `searchScore` or a `holdoutScore`.\n *\n * This is intentionally NOT a replacement for the rich `Run` /\n * `ProposeReviewReport` / `ScenarioResult` types already in the\n * package. Those are runtime structures with full provenance. A\n * `RunRecord` is the analysis-time projection — the JSON-friendly\n * row you'd put in a parquet file or paste into a notebook.\n *\n * Validate at the boundary:\n *\n * const rec = validateRunRecord(rawJson) // throws on missing\n * const ok = isRunRecord(rawJson) // boolean check\n * const rec = parseRunRecordSafe(rawJson) // { ok, value | error }\n *\n * The validator runs in pure TS — zod is intentionally NOT a\n * dependency. Round-trip tested in `tests/run-record.test.ts`.\n */\n\nimport type { AgentProfileCell } from './agent-profile-cell'\nimport { validateAgentProfileCell } from './agent-profile-cell'\nimport { ValidationError } from './errors'\nimport type { FailureClass } from './trace/schema'\n\n/** Search/dev/holdout split tag. 'search' is the paper-grade alias for the\n * combined train+test pool that the optimizer is allowed to read. */\nexport type RunSplitTag = 'search' | 'dev' | 'holdout'\n\nexport interface RunTokenUsage {\n input: number\n output: number\n cached?: number\n}\n\nexport interface RunJudgeMetadata {\n model: string\n promptVersion: string\n /** [0,1] confidence the judge declared. Constant judge confidence\n * across many runs is a fallback signal (see `canary.ts`). */\n confidence: number\n /** True if the judge degraded to a fallback path (rules-only,\n * prior-call cache, etc.). The canary uses this to alert. */\n fallback: boolean\n}\n\n/**\n * Per-judge / per-dimension breakdown for runs scored by an ensemble of\n * judges over a multi-dimensional rubric.\n *\n * The collapsed `outcome.searchScore` / `holdoutScore` carries the\n * composite the gate uses. The full breakdown belongs here so consumers\n * can answer \"which judge disagreed?\", \"which dimension dragged the\n * composite down?\", and \"did half the panel fail?\" without re-running.\n *\n * `perJudge[judgeId][dim]` is the canonical source; `perDimMean` and\n * `composite` are convenience projections — derivable but precomputed so\n * downstream IRR primitives (`interRaterReliability`,\n * `corpusInterRaterAgreement`) and reporters don't pay the same\n * aggregation twice.\n *\n * Fail-loud discipline: judges that errored out land in `failedJudges`\n * by id. A missing key in `perJudge` is ambiguous (silent zero vs not\n * run); the explicit list makes a partial-failure recorded as such.\n */\nexport interface JudgeScoresRecord {\n /** Per-judge per-dimension scores. `{ \"kimi-k2.6\": { helpfulness: 0.8, clarity: 0.7 }, ... }`. */\n perJudge: Record<string, Record<string, number>>\n /** Per-dim mean across judges. Convenience — derivable from `perJudge`. */\n perDimMean: Record<string, number>\n /** Composite mean across all dims and judges. Mirrors the score\n * the gate sees on `outcome.searchScore` / `holdoutScore`. */\n composite: number\n /** Judges that errored or returned an unparseable verdict. Recorded\n * by id (e.g. `['glm-5.1']`) so a partial-failure case is explicit,\n * not inferred from missing keys in `perJudge`. */\n failedJudges?: string[]\n /** Free-form notes the judges emitted (joined across judges or\n * first-judge only — consumer's choice). */\n notes?: string\n}\n\nexport interface RunOutcome {\n /** Score on the search/optimization split. Optional because a\n * holdout-only evaluation only fills `holdoutScore`. */\n searchScore?: number\n /** Score on the held-out split. Optional because a search-only run\n * only fills `searchScore`. At least one must be present. */\n holdoutScore?: number\n /** Bag of any other metric the run produced — judge dimensions,\n * pass/fail counters, latency stats, etc. Numeric only — keeps\n * reporters honest. */\n raw: Record<string, number>\n /** Per-judge / per-dim breakdown. Consumers writing ensemble\n * judgements populate this; substrate primitives like\n * `interRaterReliability` and `corpusInterRaterAgreement` accept\n * these records as input. Optional — single-judge or scalar-only\n * runs leave it unset. */\n judgeScores?: JudgeScoresRecord\n /** Authenticity / realness verdict — did the run build the REAL thing on the\n * intended infra, or fake it (see `./authenticity`)? Optional: only domains\n * with an authenticity config populate it. Carried in the corpus so the\n * flywheel / off-policy learning can optimize for real completion, not gamed\n * pass-rate. `score` is 0-1; `gated` is the anti-Goodhart flag — a gated run\n * must not count as a real success regardless of `score`. */\n realness?: { score: number; gated: boolean; reason?: string }\n}\n\n/**\n * Mandatory paper-grade fields for a single evaluation run. Optional\n * fields are extension points; mandatory fields throw if missing.\n *\n * Hash discipline:\n * - `promptHash` is the sha256 of the EFFECTIVE prompt sent to the\n * model (after any steering bundle merge).\n * - `configHash` is the sha256 of the effective run config (model,\n * temperature, tools, judges, splits). The pair (promptHash,\n * configHash) uniquely identifies an experiment cell.\n *\n * Model snapshot discipline:\n * - `model` MUST encode a snapshot version. Bare aliases like\n * `claude-sonnet-4` or `gpt-4o` are banned — they remap silently.\n * Use `claude-sonnet-4-6@2025-04-15` or `gpt-4o-2024-11-20`.\n */\nexport interface RunRecord {\n /** UUID for the run. */\n runId: string\n /** Logical experiment grouping (a treatment vs a baseline within\n * the same sweep should share `experimentId`). */\n experimentId: string\n /** Stable identifier for the candidate (variant) being run. The\n * promotion gate compares two `candidateId`s on matched items. */\n candidateId: string\n /** RNG seed for the run. Always recorded — silent re-seeding is\n * the most common cause of non-reproducible numbers. */\n seed: number\n /** Model identifier WITH snapshot version. */\n model: string\n /** sha256 of the effective prompt (post-steering). */\n promptHash: string\n /** sha256 of the effective config. */\n configHash: string\n /** Git SHA the harness was run from. */\n commitSha: string\n /** End-to-end wall-clock duration in milliseconds. */\n wallMs: number\n /** Time spent queued before execution started, if known. */\n queueMs?: number\n /** Total USD cost. Mandatory — runs without a cost number are\n * unbounded by definition and must not be admitted into the gate. */\n costUsd: number\n /** Token usage breakdown. */\n tokenUsage: RunTokenUsage\n /** Judge-side metadata, if a judge was used. */\n judgeMetadata?: RunJudgeMetadata\n /** Per-split scores + raw bag. */\n outcome: RunOutcome\n /** Canonical, cross-agent failure class drawn from the shared\n * `FAILURE_CLASSES` taxonomy. This is the aggregation key that makes\n * \"which failure dominates across the whole fleet\" answerable in ONE\n * vocabulary — every agent classifies against the same enum. Producers\n * set it via the substrate classifier; leave unset only when the failure\n * genuinely can't be classified. */\n failureClass?: FailureClass\n /** Free-form domain-specific failure detail, scoped UNDER `failureClass`\n * (e.g. failureClass='tool_recovery_failure', failureMode='forge_build_unsatisfied').\n * The within-agent drill-down; `failureClass` is the cross-agent key. */\n failureMode?: string\n /** Which split this run was drawn from. */\n splitTag: RunSplitTag\n /**\n * Stable scenario identifier the run was scored against. Optional for\n * backwards compatibility, but **strongly recommended**: every primitive\n * that pairs runs by scenario (preferences, paired stats, BT tournament)\n * keys on this. The campaign artifact populates it canonically; legacy\n * runs without it fall back to inference from `outcome.raw.scenario_id`\n * or `experimentId`.\n */\n scenarioId?: string\n /**\n * Canonical identity for the agent profile cell that produced this row:\n * profile artifact hash plus optional harness/model/prompt/reporting\n * dimensions. Use `agentProfile.cellId` to group persona sweeps and\n * longitudinal reports by the complete source profile, not by a loose\n * candidate label or opaque config hash.\n */\n agentProfile?: AgentProfileCell\n}\n\n// ── Validation ───────────────────────────────────────────────────────\n\nconst MANDATORY_TOP_LEVEL = [\n 'runId',\n 'experimentId',\n 'candidateId',\n 'seed',\n 'model',\n 'promptHash',\n 'configHash',\n 'commitSha',\n 'wallMs',\n 'costUsd',\n 'tokenUsage',\n 'outcome',\n 'splitTag',\n] as const\n\nconst SPLIT_TAGS: ReadonlyArray<RunSplitTag> = ['search', 'dev', 'holdout']\n\nexport class RunRecordValidationError extends ValidationError {\n readonly path: string\n constructor(message: string, path = '') {\n super(path ? `${message} (at ${path})` : message)\n this.path = path\n }\n}\n\n/**\n * Strict validator. Throws `RunRecordValidationError` on the first\n * missing or wrongly-typed field. Returns the input cast to\n * `RunRecord` on success — the validator does not coerce.\n */\nexport function validateRunRecord(input: unknown): RunRecord {\n if (input === null || typeof input !== 'object') {\n throw new RunRecordValidationError('expected object')\n }\n const obj = input as Record<string, unknown>\n\n for (const key of MANDATORY_TOP_LEVEL) {\n if (!(key in obj)) {\n throw new RunRecordValidationError(`missing mandatory field \"${key}\"`)\n }\n }\n\n expectString(obj.runId, 'runId')\n expectString(obj.experimentId, 'experimentId')\n expectString(obj.candidateId, 'candidateId')\n expectFiniteNumber(obj.seed, 'seed')\n expectString(obj.model, 'model')\n expectString(obj.promptHash, 'promptHash')\n expectString(obj.configHash, 'configHash')\n expectString(obj.commitSha, 'commitSha')\n expectFiniteNumber(obj.wallMs, 'wallMs')\n if (obj.queueMs !== undefined) expectFiniteNumber(obj.queueMs, 'queueMs')\n expectFiniteNumber(obj.costUsd, 'costUsd')\n\n // Snapshot discipline: bare model aliases are not paper-grade.\n if (!modelHasSnapshot(obj.model as string)) {\n throw new RunRecordValidationError(\n `model \"${obj.model}\" lacks a snapshot version (use 'name@YYYY-MM-DD' or 'name-YYYYMMDD')`,\n 'model',\n )\n }\n\n // Token usage.\n const tu = obj.tokenUsage\n if (tu === null || typeof tu !== 'object') {\n throw new RunRecordValidationError('tokenUsage must be an object', 'tokenUsage')\n }\n const tuRec = tu as Record<string, unknown>\n expectFiniteNumber(tuRec.input, 'tokenUsage.input')\n expectFiniteNumber(tuRec.output, 'tokenUsage.output')\n if (tuRec.cached !== undefined) expectFiniteNumber(tuRec.cached, 'tokenUsage.cached')\n\n // Judge metadata, optional.\n if (obj.judgeMetadata !== undefined) {\n const jm = obj.judgeMetadata\n if (jm === null || typeof jm !== 'object') {\n throw new RunRecordValidationError('judgeMetadata must be an object', 'judgeMetadata')\n }\n const jmRec = jm as Record<string, unknown>\n expectString(jmRec.model, 'judgeMetadata.model')\n expectString(jmRec.promptVersion, 'judgeMetadata.promptVersion')\n expectFiniteNumber(jmRec.confidence, 'judgeMetadata.confidence')\n if (typeof jmRec.fallback !== 'boolean') {\n throw new RunRecordValidationError(\n 'judgeMetadata.fallback must be boolean',\n 'judgeMetadata.fallback',\n )\n }\n }\n\n // Outcome.\n const out = obj.outcome\n if (out === null || typeof out !== 'object') {\n throw new RunRecordValidationError('outcome must be an object', 'outcome')\n }\n const outRec = out as Record<string, unknown>\n if (outRec.searchScore !== undefined)\n expectFiniteNumber(outRec.searchScore, 'outcome.searchScore')\n if (outRec.holdoutScore !== undefined)\n expectFiniteNumber(outRec.holdoutScore, 'outcome.holdoutScore')\n if (outRec.searchScore === undefined && outRec.holdoutScore === undefined) {\n throw new RunRecordValidationError(\n 'outcome must define searchScore or holdoutScore (or both)',\n 'outcome',\n )\n }\n const raw = outRec.raw\n if (raw === null || typeof raw !== 'object') {\n throw new RunRecordValidationError('outcome.raw must be an object', 'outcome.raw')\n }\n for (const [k, v] of Object.entries(raw as Record<string, unknown>)) {\n expectFiniteNumber(v, `outcome.raw.${k}`)\n }\n // Realness verdict, optional.\n if (outRec.realness !== undefined) {\n const r = outRec.realness\n if (r === null || typeof r !== 'object') {\n throw new RunRecordValidationError('outcome.realness must be an object', 'outcome.realness')\n }\n const rr = r as Record<string, unknown>\n expectFiniteNumber(rr.score, 'outcome.realness.score')\n if (typeof rr.gated !== 'boolean') {\n throw new RunRecordValidationError(\n 'outcome.realness.gated must be a boolean',\n 'outcome.realness.gated',\n )\n }\n }\n\n // Per-judge / per-dim breakdown, optional.\n if (outRec.judgeScores !== undefined) {\n validateJudgeScores(outRec.judgeScores, 'outcome.judgeScores')\n }\n\n // Failure mode optional.\n if (obj.failureMode !== undefined) expectString(obj.failureMode, 'failureMode')\n\n if (obj.agentProfile !== undefined) {\n try {\n const profile = validateAgentProfileCell(obj.agentProfile)\n if (profile.model !== undefined && profile.model !== obj.model) {\n throw new RunRecordValidationError(\n `agentProfile.model \"${profile.model}\" does not match model \"${obj.model}\"`,\n 'agentProfile.model',\n )\n }\n if (profile.promptHash !== undefined && profile.promptHash !== obj.promptHash) {\n throw new RunRecordValidationError(\n `agentProfile.promptHash \"${profile.promptHash}\" does not match promptHash \"${obj.promptHash}\"`,\n 'agentProfile.promptHash',\n )\n }\n } catch (error) {\n if (error instanceof RunRecordValidationError) throw error\n if (error instanceof Error) {\n throw new RunRecordValidationError(error.message, 'agentProfile')\n }\n throw error\n }\n }\n\n // Split tag.\n if (typeof obj.splitTag !== 'string' || !SPLIT_TAGS.includes(obj.splitTag as RunSplitTag)) {\n throw new RunRecordValidationError(\n `splitTag must be one of ${SPLIT_TAGS.join(', ')}, got ${String(obj.splitTag)}`,\n 'splitTag',\n )\n }\n\n return input as RunRecord\n}\n\n/** Boolean validator — convenience for filtering arrays. */\nexport function isRunRecord(input: unknown): input is RunRecord {\n try {\n validateRunRecord(input)\n return true\n } catch {\n return false\n }\n}\n\n/** Non-throwing validator — returns a discriminated union. */\nexport function parseRunRecordSafe(\n input: unknown,\n): { ok: true; value: RunRecord } | { ok: false; error: RunRecordValidationError } {\n try {\n return { ok: true, value: validateRunRecord(input) }\n } catch (e) {\n if (e instanceof RunRecordValidationError) return { ok: false, error: e }\n throw e\n }\n}\n\n/** Round-trip helper — `JSON.parse(JSON.stringify(record))` then validate. */\nexport function roundTripRunRecord(record: RunRecord): RunRecord {\n const json = JSON.stringify(record)\n return validateRunRecord(JSON.parse(json))\n}\n\n// ── Internals ────────────────────────────────────────────────────────\n\nfunction expectString(value: unknown, path: string): void {\n if (typeof value !== 'string' || value.length === 0) {\n throw new RunRecordValidationError(`expected non-empty string`, path)\n }\n}\n\nfunction expectFiniteNumber(value: unknown, path: string): void {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n throw new RunRecordValidationError(`expected finite number`, path)\n }\n}\n\nfunction validateJudgeScores(value: unknown, path: string): void {\n if (value === null || typeof value !== 'object') {\n throw new RunRecordValidationError('judgeScores must be an object', path)\n }\n const rec = value as Record<string, unknown>\n\n const perJudge = rec.perJudge\n if (perJudge === null || typeof perJudge !== 'object') {\n throw new RunRecordValidationError('perJudge must be an object', `${path}.perJudge`)\n }\n for (const [judgeId, dims] of Object.entries(perJudge as Record<string, unknown>)) {\n if (dims === null || typeof dims !== 'object') {\n throw new RunRecordValidationError(\n 'per-judge entry must be an object of dimension scores',\n `${path}.perJudge.${judgeId}`,\n )\n }\n for (const [dim, score] of Object.entries(dims as Record<string, unknown>)) {\n expectFiniteNumber(score, `${path}.perJudge.${judgeId}.${dim}`)\n }\n }\n\n const perDimMean = rec.perDimMean\n if (perDimMean === null || typeof perDimMean !== 'object') {\n throw new RunRecordValidationError('perDimMean must be an object', `${path}.perDimMean`)\n }\n for (const [dim, mean] of Object.entries(perDimMean as Record<string, unknown>)) {\n expectFiniteNumber(mean, `${path}.perDimMean.${dim}`)\n }\n\n expectFiniteNumber(rec.composite, `${path}.composite`)\n\n if (rec.failedJudges !== undefined) {\n if (!Array.isArray(rec.failedJudges)) {\n throw new RunRecordValidationError(\n 'failedJudges must be an array of strings',\n `${path}.failedJudges`,\n )\n }\n for (let i = 0; i < rec.failedJudges.length; i++) {\n const id = rec.failedJudges[i]\n if (typeof id !== 'string' || id.length === 0) {\n throw new RunRecordValidationError(\n 'failedJudges entry must be a non-empty string',\n `${path}.failedJudges[${i}]`,\n )\n }\n }\n }\n\n if (rec.notes !== undefined && typeof rec.notes !== 'string') {\n throw new RunRecordValidationError('notes must be a string', `${path}.notes`)\n }\n}\n\n/**\n * Heuristic snapshot check. Accepts:\n * - `name@YYYY-MM-DD` (Anthropic style: `claude-sonnet-4-6@2025-04-15`)\n * - `name-YYYYMMDD` (OpenAI style: `gpt-4o-2024-11-20`)\n * - `name@<arbitrary-token>` (allow opaque snapshots like `@v3`)\n * - explicit `:date-...` Vertex-style tags\n *\n * Rejects bare aliases like `claude-sonnet-4` or `gpt-4o` that remap\n * silently as providers ship new snapshots.\n */\nfunction modelHasSnapshot(model: string): boolean {\n if (model.includes('@')) return true\n if (/-\\d{8}$/.test(model)) return true\n if (/-\\d{4}-\\d{2}-\\d{2}$/.test(model)) return true\n if (/:date-/.test(model)) return true\n return false\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/run-record.ts"],"sourcesContent":["/**\n * Paper-grade RunRecord schema + runtime validator.\n *\n * Every run that participates in a promotion gate, paper table, or\n * researcher loop SHOULD be recorded as a `RunRecord`. The mandatory\n * fields are exactly those the paper \"Two Loops, Three Roles\" requires\n * for reproducibility: who/what/when/cost/seed/hash, plus the search vs\n * holdout split tag and either a `searchScore` or a `holdoutScore`.\n *\n * This is intentionally NOT a replacement for the rich `Run` /\n * `ProposeReviewReport` / `ScenarioResult` types already in the\n * package. Those are runtime structures with full provenance. A\n * `RunRecord` is the analysis-time projection — the JSON-friendly\n * row you'd put in a parquet file or paste into a notebook.\n *\n * Validate at the boundary:\n *\n * const rec = validateRunRecord(rawJson) // throws on missing\n * const ok = isRunRecord(rawJson) // boolean check\n * const rec = parseRunRecordSafe(rawJson) // { ok, value | error }\n *\n * The validator runs in pure TS — zod is intentionally NOT a\n * dependency. Round-trip tested in `tests/run-record.test.ts`.\n */\n\nimport type { AgentProfileCell } from './agent-profile-cell'\nimport { validateAgentProfileCell } from './agent-profile-cell'\nimport { ValidationError } from './errors'\nimport type { FailureClass } from './trace/schema'\n\n/** Search/dev/holdout split tag. 'search' is the paper-grade alias for the\n * combined train+test pool that the optimizer is allowed to read. */\nexport type RunSplitTag = 'search' | 'dev' | 'holdout'\n\nexport interface RunTokenUsage {\n input: number\n output: number\n cached?: number\n}\n\nexport interface RunJudgeMetadata {\n model: string\n promptVersion: string\n /** [0,1] confidence the judge declared. Constant judge confidence\n * across many runs is a fallback signal (see `canary.ts`). */\n confidence: number\n /** True if the judge degraded to a fallback path (rules-only,\n * prior-call cache, etc.). The canary uses this to alert. */\n fallback: boolean\n}\n\n/**\n * Per-judge / per-dimension breakdown for runs scored by an ensemble of\n * judges over a multi-dimensional rubric.\n *\n * The collapsed `outcome.searchScore` / `holdoutScore` carries the\n * composite the gate uses. The full breakdown belongs here so consumers\n * can answer \"which judge disagreed?\", \"which dimension dragged the\n * composite down?\", and \"did half the panel fail?\" without re-running.\n *\n * `perJudge[judgeId][dim]` is the canonical source; `perDimMean` and\n * `composite` are convenience projections — derivable but precomputed so\n * downstream IRR primitives (`interRaterReliability`,\n * `corpusInterRaterAgreement`) and reporters don't pay the same\n * aggregation twice.\n *\n * Fail-loud discipline: judges that errored out land in `failedJudges`\n * by id. A missing key in `perJudge` is ambiguous (silent zero vs not\n * run); the explicit list makes a partial-failure recorded as such.\n */\nexport interface JudgeScoresRecord {\n /** Per-judge per-dimension scores. `{ \"kimi-k2.6\": { helpfulness: 0.8, clarity: 0.7 }, ... }`. */\n perJudge: Record<string, Record<string, number>>\n /** Per-dim mean across judges. Convenience — derivable from `perJudge`. */\n perDimMean: Record<string, number>\n /** Composite mean across all dims and judges. Mirrors the score\n * the gate sees on `outcome.searchScore` / `holdoutScore`. */\n composite: number\n /** Judges that errored or returned an unparseable verdict. Recorded\n * by id (e.g. `['glm-5.1']`) so a partial-failure case is explicit,\n * not inferred from missing keys in `perJudge`. */\n failedJudges?: string[]\n /** Free-form notes the judges emitted (joined across judges or\n * first-judge only — consumer's choice). */\n notes?: string\n}\n\nexport interface RunOutcome {\n /** Score on the search/optimization split. Optional because a\n * holdout-only evaluation only fills `holdoutScore`. */\n searchScore?: number\n /** Score on the held-out split. Optional because a search-only run\n * only fills `searchScore`. At least one must be present. */\n holdoutScore?: number\n /** Bag of any other metric the run produced — judge dimensions,\n * pass/fail counters, latency stats, etc. Numeric only — keeps\n * reporters honest. */\n raw: Record<string, number>\n /** Per-judge / per-dim breakdown. Consumers writing ensemble\n * judgements populate this; substrate primitives like\n * `interRaterReliability` and `corpusInterRaterAgreement` accept\n * these records as input. Optional — single-judge or scalar-only\n * runs leave it unset. */\n judgeScores?: JudgeScoresRecord\n /** Authenticity / realness verdict — did the run build the REAL thing on the\n * intended infra, or fake it (see `./authenticity`)? Optional: only domains\n * with an authenticity config populate it. Carried in the corpus so the\n * flywheel / off-policy learning can optimize for real completion, not gamed\n * pass-rate. `score` is 0-1; `gated` is the anti-Goodhart flag — a gated run\n * must not count as a real success regardless of `score`. */\n realness?: { score: number; gated: boolean; reason?: string }\n}\n\n/**\n * Mandatory paper-grade fields for a single evaluation run. Optional\n * fields are extension points; mandatory fields throw if missing.\n *\n * Hash discipline:\n * - `promptHash` is the sha256 of the EFFECTIVE prompt sent to the\n * model (after any steering bundle merge).\n * - `configHash` is the sha256 of the effective run config (model,\n * temperature, tools, judges, splits). The pair (promptHash,\n * configHash) uniquely identifies an experiment cell.\n *\n * Model snapshot discipline:\n * - `model` MUST encode a snapshot version. Bare aliases like\n * `claude-sonnet-4` or `gpt-4o` are banned — they remap silently.\n * Use `claude-sonnet-4-6@2025-04-15` or `gpt-4o-2024-11-20`.\n */\nexport interface RunRecord {\n /** UUID for the run. */\n runId: string\n /** Logical experiment grouping (a treatment vs a baseline within\n * the same sweep should share `experimentId`). */\n experimentId: string\n /** Stable identifier for the candidate (variant) being run. The\n * promotion gate compares two `candidateId`s on matched items. */\n candidateId: string\n /** RNG seed for the run. Always recorded — silent re-seeding is\n * the most common cause of non-reproducible numbers. */\n seed: number\n /** Model identifier WITH snapshot version. */\n model: string\n /** sha256 of the effective prompt (post-steering). */\n promptHash: string\n /** sha256 of the effective config. */\n configHash: string\n /** Git SHA the harness was run from. */\n commitSha: string\n /** End-to-end wall-clock duration in milliseconds. */\n wallMs: number\n /** Time spent queued before execution started, if known. */\n queueMs?: number\n /** Total USD cost. Mandatory — runs without a cost number are\n * unbounded by definition and must not be admitted into the gate. */\n costUsd: number\n /** Token usage breakdown. */\n tokenUsage: RunTokenUsage\n /** Judge-side metadata, if a judge was used. */\n judgeMetadata?: RunJudgeMetadata\n /** Per-split scores + raw bag. */\n outcome: RunOutcome\n /** Canonical, cross-agent failure class drawn from the shared\n * `FAILURE_CLASSES` taxonomy. This is the aggregation key that makes\n * \"which failure dominates across the whole fleet\" answerable in ONE\n * vocabulary — every agent classifies against the same enum. Producers\n * set it via the substrate classifier; leave unset only when the failure\n * genuinely can't be classified. */\n failureClass?: FailureClass\n /** Free-form domain-specific failure detail, scoped UNDER `failureClass`\n * (e.g. failureClass='tool_recovery_failure', failureMode='forge_build_unsatisfied').\n * The within-agent drill-down; `failureClass` is the cross-agent key. */\n failureMode?: string\n /** Which split this run was drawn from. */\n splitTag: RunSplitTag\n /**\n * Stable scenario identifier the run was scored against. Optional for\n * backwards compatibility, but **strongly recommended**: every primitive\n * that pairs runs by scenario (preferences, paired stats, BT tournament)\n * keys on this. The campaign artifact populates it canonically; legacy\n * runs without it fall back to inference from `outcome.raw.scenario_id`\n * or `experimentId`.\n */\n scenarioId?: string\n /**\n * Canonical identity for the agent profile cell that produced this row:\n * profile artifact hash plus optional harness/model/prompt/reporting\n * dimensions. Use `agentProfile.cellId` to group persona sweeps and\n * longitudinal reports by the complete source profile, not by a loose\n * candidate label or opaque config hash.\n */\n agentProfile?: AgentProfileCell\n}\n\n// ── Validation ───────────────────────────────────────────────────────\n\nconst MANDATORY_TOP_LEVEL = [\n 'runId',\n 'experimentId',\n 'candidateId',\n 'seed',\n 'model',\n 'promptHash',\n 'configHash',\n 'commitSha',\n 'wallMs',\n 'costUsd',\n 'tokenUsage',\n 'outcome',\n 'splitTag',\n] as const\n\nconst SPLIT_TAGS: ReadonlyArray<RunSplitTag> = ['search', 'dev', 'holdout']\n\nexport class RunRecordValidationError extends ValidationError {\n readonly path: string\n constructor(message: string, path = '') {\n super(path ? `${message} (at ${path})` : message)\n this.path = path\n }\n}\n\n/**\n * Strict validator. Throws `RunRecordValidationError` on the first\n * missing or wrongly-typed field. Returns the input cast to\n * `RunRecord` on success — the validator does not coerce.\n */\nexport function validateRunRecord(input: unknown): RunRecord {\n if (input === null || typeof input !== 'object') {\n throw new RunRecordValidationError('expected object')\n }\n const obj = input as Record<string, unknown>\n\n for (const key of MANDATORY_TOP_LEVEL) {\n if (!(key in obj)) {\n throw new RunRecordValidationError(`missing mandatory field \"${key}\"`)\n }\n }\n\n expectString(obj.runId, 'runId')\n expectString(obj.experimentId, 'experimentId')\n expectString(obj.candidateId, 'candidateId')\n expectFiniteNumber(obj.seed, 'seed')\n expectString(obj.model, 'model')\n expectString(obj.promptHash, 'promptHash')\n expectString(obj.configHash, 'configHash')\n expectString(obj.commitSha, 'commitSha')\n expectFiniteNumber(obj.wallMs, 'wallMs')\n if (obj.queueMs !== undefined) expectFiniteNumber(obj.queueMs, 'queueMs')\n expectFiniteNumber(obj.costUsd, 'costUsd')\n\n // Snapshot discipline: bare model aliases are not paper-grade.\n if (!modelHasSnapshot(obj.model as string)) {\n throw new RunRecordValidationError(\n `model \"${obj.model}\" lacks a snapshot version (use 'name@YYYY-MM-DD' or 'name-YYYYMMDD')`,\n 'model',\n )\n }\n\n // Token usage.\n const tu = obj.tokenUsage\n if (tu === null || typeof tu !== 'object') {\n throw new RunRecordValidationError('tokenUsage must be an object', 'tokenUsage')\n }\n const tuRec = tu as Record<string, unknown>\n expectFiniteNumber(tuRec.input, 'tokenUsage.input')\n expectFiniteNumber(tuRec.output, 'tokenUsage.output')\n if (tuRec.cached !== undefined) expectFiniteNumber(tuRec.cached, 'tokenUsage.cached')\n\n // Judge metadata, optional.\n if (obj.judgeMetadata !== undefined) {\n const jm = obj.judgeMetadata\n if (jm === null || typeof jm !== 'object') {\n throw new RunRecordValidationError('judgeMetadata must be an object', 'judgeMetadata')\n }\n const jmRec = jm as Record<string, unknown>\n expectString(jmRec.model, 'judgeMetadata.model')\n expectString(jmRec.promptVersion, 'judgeMetadata.promptVersion')\n expectFiniteNumber(jmRec.confidence, 'judgeMetadata.confidence')\n if (typeof jmRec.fallback !== 'boolean') {\n throw new RunRecordValidationError(\n 'judgeMetadata.fallback must be boolean',\n 'judgeMetadata.fallback',\n )\n }\n }\n\n // Outcome.\n const out = obj.outcome\n if (out === null || typeof out !== 'object') {\n throw new RunRecordValidationError('outcome must be an object', 'outcome')\n }\n const outRec = out as Record<string, unknown>\n if (outRec.searchScore !== undefined)\n expectFiniteNumber(outRec.searchScore, 'outcome.searchScore')\n if (outRec.holdoutScore !== undefined)\n expectFiniteNumber(outRec.holdoutScore, 'outcome.holdoutScore')\n if (outRec.searchScore === undefined && outRec.holdoutScore === undefined) {\n throw new RunRecordValidationError(\n 'outcome must define searchScore or holdoutScore (or both)',\n 'outcome',\n )\n }\n const raw = outRec.raw\n if (raw === null || typeof raw !== 'object') {\n throw new RunRecordValidationError('outcome.raw must be an object', 'outcome.raw')\n }\n for (const [k, v] of Object.entries(raw as Record<string, unknown>)) {\n expectFiniteNumber(v, `outcome.raw.${k}`)\n }\n // Realness verdict, optional.\n if (outRec.realness !== undefined) {\n const r = outRec.realness\n if (r === null || typeof r !== 'object') {\n throw new RunRecordValidationError('outcome.realness must be an object', 'outcome.realness')\n }\n const rr = r as Record<string, unknown>\n expectFiniteNumber(rr.score, 'outcome.realness.score')\n if (typeof rr.gated !== 'boolean') {\n throw new RunRecordValidationError(\n 'outcome.realness.gated must be a boolean',\n 'outcome.realness.gated',\n )\n }\n }\n\n // Per-judge / per-dim breakdown, optional.\n if (outRec.judgeScores !== undefined) {\n validateJudgeScores(outRec.judgeScores, 'outcome.judgeScores')\n }\n\n // Failure mode optional.\n if (obj.failureMode !== undefined) expectString(obj.failureMode, 'failureMode')\n\n if (obj.agentProfile !== undefined) {\n try {\n const profile = validateAgentProfileCell(obj.agentProfile)\n if (profile.model !== undefined && profile.model !== obj.model) {\n throw new RunRecordValidationError(\n `agentProfile.model \"${profile.model}\" does not match model \"${obj.model}\"`,\n 'agentProfile.model',\n )\n }\n if (profile.promptHash !== undefined && profile.promptHash !== obj.promptHash) {\n throw new RunRecordValidationError(\n `agentProfile.promptHash \"${profile.promptHash}\" does not match promptHash \"${obj.promptHash}\"`,\n 'agentProfile.promptHash',\n )\n }\n } catch (error) {\n if (error instanceof RunRecordValidationError) throw error\n if (error instanceof Error) {\n throw new RunRecordValidationError(error.message, 'agentProfile')\n }\n throw error\n }\n }\n\n // Split tag.\n if (typeof obj.splitTag !== 'string' || !SPLIT_TAGS.includes(obj.splitTag as RunSplitTag)) {\n throw new RunRecordValidationError(\n `splitTag must be one of ${SPLIT_TAGS.join(', ')}, got ${String(obj.splitTag)}`,\n 'splitTag',\n )\n }\n\n return input as RunRecord\n}\n\n/** Boolean validator — convenience for filtering arrays. */\nexport function isRunRecord(input: unknown): input is RunRecord {\n try {\n validateRunRecord(input)\n return true\n } catch {\n return false\n }\n}\n\n/** Non-throwing validator — returns a discriminated union. */\nexport function parseRunRecordSafe(\n input: unknown,\n): { ok: true; value: RunRecord } | { ok: false; error: RunRecordValidationError } {\n try {\n return { ok: true, value: validateRunRecord(input) }\n } catch (e) {\n if (e instanceof RunRecordValidationError) return { ok: false, error: e }\n throw e\n }\n}\n\n/** Round-trip helper — `JSON.parse(JSON.stringify(record))` then validate. */\nexport function roundTripRunRecord(record: RunRecord): RunRecord {\n const json = JSON.stringify(record)\n return validateRunRecord(JSON.parse(json))\n}\n\n// ── Internals ────────────────────────────────────────────────────────\n\nfunction expectString(value: unknown, path: string): void {\n if (typeof value !== 'string' || value.length === 0) {\n throw new RunRecordValidationError(`expected non-empty string`, path)\n }\n}\n\nfunction expectFiniteNumber(value: unknown, path: string): void {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n throw new RunRecordValidationError(`expected finite number`, path)\n }\n}\n\nfunction validateJudgeScores(value: unknown, path: string): void {\n if (value === null || typeof value !== 'object') {\n throw new RunRecordValidationError('judgeScores must be an object', path)\n }\n const rec = value as Record<string, unknown>\n\n const perJudge = rec.perJudge\n if (perJudge === null || typeof perJudge !== 'object') {\n throw new RunRecordValidationError('perJudge must be an object', `${path}.perJudge`)\n }\n for (const [judgeId, dims] of Object.entries(perJudge as Record<string, unknown>)) {\n if (dims === null || typeof dims !== 'object') {\n throw new RunRecordValidationError(\n 'per-judge entry must be an object of dimension scores',\n `${path}.perJudge.${judgeId}`,\n )\n }\n for (const [dim, score] of Object.entries(dims as Record<string, unknown>)) {\n expectFiniteNumber(score, `${path}.perJudge.${judgeId}.${dim}`)\n }\n }\n\n const perDimMean = rec.perDimMean\n if (perDimMean === null || typeof perDimMean !== 'object') {\n throw new RunRecordValidationError('perDimMean must be an object', `${path}.perDimMean`)\n }\n for (const [dim, mean] of Object.entries(perDimMean as Record<string, unknown>)) {\n expectFiniteNumber(mean, `${path}.perDimMean.${dim}`)\n }\n\n expectFiniteNumber(rec.composite, `${path}.composite`)\n\n if (rec.failedJudges !== undefined) {\n if (!Array.isArray(rec.failedJudges)) {\n throw new RunRecordValidationError(\n 'failedJudges must be an array of strings',\n `${path}.failedJudges`,\n )\n }\n for (let i = 0; i < rec.failedJudges.length; i++) {\n const id = rec.failedJudges[i]\n if (typeof id !== 'string' || id.length === 0) {\n throw new RunRecordValidationError(\n 'failedJudges entry must be a non-empty string',\n `${path}.failedJudges[${i}]`,\n )\n }\n }\n }\n\n if (rec.notes !== undefined && typeof rec.notes !== 'string') {\n throw new RunRecordValidationError('notes must be a string', `${path}.notes`)\n }\n}\n\n/**\n * Heuristic snapshot check. Accepts:\n * - `name@YYYY-MM-DD` (Anthropic style: `claude-sonnet-4-6@2025-04-15`)\n * - `name-YYYYMMDD` (OpenAI style: `gpt-4o-2024-11-20`)\n * - `name@<arbitrary-token>` (allow opaque snapshots like `@v3`)\n * - explicit `:date-...` Vertex-style tags\n *\n * Rejects bare aliases like `claude-sonnet-4` or `gpt-4o` that remap\n * silently as providers ship new snapshots.\n */\nexport function modelHasSnapshot(model: string): boolean {\n if (model.includes('@')) return true\n if (/-\\d{8}$/.test(model)) return true\n if (/-\\d{4}-\\d{2}-\\d{2}$/.test(model)) return true\n if (/:date-/.test(model)) return true\n return false\n}\n"],"mappings":"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","names":[]}
@@ -13,7 +13,7 @@ import {
13
13
  } from "./chunk-PC4UYEBM.js";
14
14
  import {
15
15
  validateRunRecord
16
- } from "./chunk-G6S73VA7.js";
16
+ } from "./chunk-2NSLDY4B.js";
17
17
  import {
18
18
  TraceEmitter
19
19
  } from "./chunk-TVVP3ZZQ.js";
@@ -354,4 +354,4 @@ function defaultRunId(params) {
354
354
  export {
355
355
  runEvalCampaign
356
356
  };
357
- //# sourceMappingURL=chunk-4LWD6GC7.js.map
357
+ //# sourceMappingURL=chunk-6FIAJHCU.js.map
@@ -26,7 +26,7 @@ import {
26
26
  } from "./chunk-PC4UYEBM.js";
27
27
  import {
28
28
  validateRunRecord
29
- } from "./chunk-G6S73VA7.js";
29
+ } from "./chunk-2NSLDY4B.js";
30
30
  import {
31
31
  canonicalize,
32
32
  hashJson
@@ -1954,4 +1954,4 @@ export {
1954
1954
  createReplayFetch,
1955
1955
  iterateRawCalls
1956
1956
  };
1957
- //# sourceMappingURL=chunk-PMF5WIBX.js.map
1957
+ //# sourceMappingURL=chunk-7RBJANJD.js.map
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-YEHAEDUD.js";
5
5
  import {
6
6
  validateRunRecord
7
- } from "./chunk-G6S73VA7.js";
7
+ } from "./chunk-2NSLDY4B.js";
8
8
  import {
9
9
  TraceEmitter
10
10
  } from "./chunk-TVVP3ZZQ.js";
@@ -610,4 +610,4 @@ export {
610
610
  runProposeReviewAsControlLoop,
611
611
  controlFailureClassFromVerification
612
612
  };
613
- //# sourceMappingURL=chunk-BOETF6BU.js.map
613
+ //# sourceMappingURL=chunk-B2TMQM62.js.map
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  runCanaries,
3
3
  scoreRedTeamOutput
4
- } from "./chunk-52CCCXU3.js";
4
+ } from "./chunk-NTVWIH24.js";
5
5
  import {
6
6
  runCampaign
7
- } from "./chunk-LSCBODPQ.js";
7
+ } from "./chunk-XKA6ZGEY.js";
8
8
  import {
9
9
  detectRewardHacking
10
10
  } from "./chunk-AIGWQEME.js";
@@ -432,4 +432,4 @@ export {
432
432
  runEval,
433
433
  evolutionaryProposer
434
434
  };
435
- //# sourceMappingURL=chunk-QUCGGMYM.js.map
435
+ //# sourceMappingURL=chunk-HV5PBTJF.js.map
@@ -1,3 +1,6 @@
1
+ import {
2
+ recoverTruncatedJson
3
+ } from "./chunk-NTVWIH24.js";
1
4
  import {
2
5
  clamp01
3
6
  } from "./chunk-IN3SHQML.js";
@@ -224,20 +227,29 @@ function parseJudgeResponse(judgeName, resp) {
224
227
  }
225
228
 
226
229
  // src/completion-verifier.ts
230
+ import { randomUUID } from "crypto";
227
231
  function completionVerdict(input) {
228
232
  if (input.requirements.length === 0) {
229
233
  throw new Error(
230
234
  `completionVerdict: task '${input.taskId}' has no requirement checks \u2014 nothing to derive a verdict from`
231
235
  );
232
236
  }
233
- const satisfiedCount = input.requirements.filter((r) => r.satisfied).length;
234
- const completionRate = satisfiedCount / input.requirements.length;
235
- const fullyComplete = satisfiedCount === input.requirements.length;
237
+ const measurable = input.requirements.filter((r) => !r.unmeasured);
238
+ const unmeasuredCount = input.requirements.length - measurable.length;
239
+ if (measurable.length === 0) {
240
+ throw new Error(
241
+ `completionVerdict: task '${input.taskId}' has no measurable requirements \u2014 all ${input.requirements.length} correctness checks failed (${input.requirements[0]?.unmeasuredReason ?? "unknown reason"})`
242
+ );
243
+ }
244
+ const satisfiedCount = measurable.filter((r) => r.satisfied).length;
245
+ const completionRate = satisfiedCount / measurable.length;
246
+ const fullyComplete = unmeasuredCount === 0 && satisfiedCount === measurable.length;
236
247
  return {
237
248
  taskId: input.taskId,
238
249
  requirements: input.requirements,
239
250
  completionRate,
240
251
  fullyComplete,
252
+ unmeasuredCount,
241
253
  valid: fullyComplete,
242
254
  score: completionRate
243
255
  };
@@ -382,12 +394,18 @@ async function verifyCompletion(gold, state, checkCorrectness) {
382
394
  const match = assigned.get(i);
383
395
  const evidence = [];
384
396
  let correct = null;
397
+ let unmeasuredReason;
385
398
  if (match) {
386
399
  evidence.push(match.evidence);
387
400
  if (match.content !== null) {
388
- const r = await checkCorrectness(req, match.content);
389
- correct = r.correct;
390
- evidence.push(`correctness: ${r.correct ? "pass" : "fail"} \u2014 ${r.reason}`);
401
+ try {
402
+ const r = await checkCorrectness(req, match.content);
403
+ correct = r.correct;
404
+ evidence.push(`correctness: ${r.correct ? "pass" : "fail"} \u2014 ${r.reason}`);
405
+ } catch (err) {
406
+ unmeasuredReason = err instanceof JudgeParseError ? `checker response unparseable after retry: ${err.raw.slice(0, 200)}` : `checker call failed: ${err instanceof Error ? err.message : String(err)}`;
407
+ evidence.push(`correctness: UNMEASURED \u2014 ${unmeasuredReason}`);
408
+ }
391
409
  } else {
392
410
  evidence.push("correctness: not assessed \u2014 matched item carries no content");
393
411
  }
@@ -397,34 +415,55 @@ async function verifyCompletion(gold, state, checkCorrectness) {
397
415
  evidence.push(`no produced ${kind} matched this requirement`);
398
416
  }
399
417
  const structurallyPresent = match !== void 0;
400
- const satisfied = structurallyPresent && correct !== false;
418
+ const unmeasured = unmeasuredReason !== void 0;
419
+ const satisfied = structurallyPresent && !unmeasured && correct !== false;
401
420
  requirements.push({
402
421
  reqId: req.reqId,
403
422
  title: req.title,
404
423
  structurallyPresent,
405
424
  correct,
406
425
  satisfied,
426
+ ...unmeasured ? { unmeasured: true, unmeasuredReason } : {},
407
427
  evidence
408
428
  });
409
429
  }
410
430
  return completionVerdict({ taskId: gold.taskId, requirements });
411
431
  }
412
432
  function parseCorrectnessResponse(raw) {
433
+ const readVerdict = (candidate) => {
434
+ if (candidate === null || typeof candidate !== "object") return null;
435
+ const { correct, reason } = candidate;
436
+ if (typeof correct !== "boolean") return null;
437
+ return { correct, reason: typeof reason === "string" ? reason : "" };
438
+ };
413
439
  const match = raw.match(/\{[\s\S]*\}/);
414
- if (!match) {
415
- throw new Error(`correctness checker: no JSON object in model response: ${raw.slice(0, 200)}`);
440
+ if (match) {
441
+ try {
442
+ const strict = readVerdict(JSON.parse(match[0]));
443
+ if (strict) return strict;
444
+ } catch {
445
+ }
416
446
  }
417
- const parsed = JSON.parse(match[0]);
418
- if (typeof parsed.correct !== "boolean") {
419
- throw new Error(`correctness checker: 'correct' is not a boolean in: ${match[0].slice(0, 200)}`);
447
+ const start = raw.indexOf("{");
448
+ if (start !== -1) {
449
+ const recovered = readVerdict(recoverTruncatedJson(raw.slice(start)));
450
+ if (recovered) return recovered;
420
451
  }
421
- return { correct: parsed.correct, reason: typeof parsed.reason === "string" ? parsed.reason : "" };
452
+ throw new JudgeParseError("correctness-checker", raw);
422
453
  }
423
454
  function createLlmCorrectnessChecker(tc, opts = {}) {
424
455
  const model = opts.model ?? "claude-sonnet-4-6";
425
456
  const maxContentChars = opts.maxContentChars ?? 8e3;
457
+ const maxAttempts = opts.maxAttempts ?? 2;
458
+ const sink = opts.rawSink;
459
+ const record = async (event) => {
460
+ try {
461
+ await sink?.record(event);
462
+ } catch {
463
+ }
464
+ };
426
465
  return async (requirement, content) => {
427
- const resp = await tc.chat({
466
+ const request = {
428
467
  model,
429
468
  messages: [
430
469
  {
@@ -442,9 +481,57 @@ ${content.slice(0, maxContentChars)}`
442
481
  ],
443
482
  temperature: 0,
444
483
  maxTokens: 200
445
- });
446
- const raw = resp.choices?.[0]?.message?.content ?? "";
447
- return parseCorrectnessResponse(raw);
484
+ };
485
+ let lastErr;
486
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
487
+ const started = Date.now();
488
+ await record({
489
+ eventId: randomUUID(),
490
+ provider: "correctness-checker",
491
+ model,
492
+ endpoint: "/chat",
493
+ baseUrl: "",
494
+ attemptIndex: attempt,
495
+ direction: "request",
496
+ timestamp: started,
497
+ requestBody: request,
498
+ redactedFields: []
499
+ });
500
+ try {
501
+ const resp = await tc.chat(request);
502
+ const raw = resp.choices?.[0]?.message?.content ?? "";
503
+ await record({
504
+ eventId: randomUUID(),
505
+ provider: "correctness-checker",
506
+ model,
507
+ endpoint: "/chat",
508
+ baseUrl: "",
509
+ attemptIndex: attempt,
510
+ direction: "response",
511
+ timestamp: Date.now(),
512
+ durationMs: Date.now() - started,
513
+ responseBody: resp,
514
+ redactedFields: []
515
+ });
516
+ return parseCorrectnessResponse(raw);
517
+ } catch (err) {
518
+ lastErr = err;
519
+ await record({
520
+ eventId: randomUUID(),
521
+ provider: "correctness-checker",
522
+ model,
523
+ endpoint: "/chat",
524
+ baseUrl: "",
525
+ attemptIndex: attempt,
526
+ direction: "error",
527
+ timestamp: Date.now(),
528
+ durationMs: Date.now() - started,
529
+ errorMessage: err instanceof Error ? err.message : String(err),
530
+ redactedFields: []
531
+ });
532
+ }
533
+ }
534
+ throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));
448
535
  };
449
536
  }
450
537
  var TITLE_STOPWORDS = /* @__PURE__ */ new Set([
@@ -771,4 +858,4 @@ export {
771
858
  agentProfileModelId,
772
859
  agentProfileHash
773
860
  };
774
- //# sourceMappingURL=chunk-CMJSTXUR.js.map
861
+ //# sourceMappingURL=chunk-IXOV77YF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/judges.ts","../src/completion-verifier.ts","../src/llm-judge.ts","../src/produced-state.ts","../src/agent-profile.ts"],"sourcesContent":["import type { TCloud } from '@tangle-network/tcloud'\nimport { JudgeError } from './errors'\nimport type { JudgeFn, JudgeInput, JudgeScore } from './types'\n\n/**\n * A judge's LLM response could not be parsed into scored dimensions.\n * Thrown instead of fabricating a `{ dimension: 'parse_error', score: 0 }`\n * row — a synthetic zero is indistinguishable from a real low score\n * downstream. Carries the raw response for forensics. Callers (executor,\n * ensemble wrappers) catch this per-judge and record a failed judge.\n */\nexport class JudgeParseError extends JudgeError {\n /** Name of the judge whose response failed to parse. */\n readonly judgeName: string\n /** The raw (truncated) model response that failed to parse. */\n readonly raw: string\n\n constructor(judgeName: string, raw: string, options?: { cause?: unknown }) {\n super(`judge '${judgeName}' returned an unparseable response: ${raw.slice(0, 200)}`, options)\n this.judgeName = judgeName\n this.raw = raw\n }\n}\n\n/**\n * Create a domain expert judge with a configurable domain.\n *\n * The judge evaluates professional accuracy and depth.\n *\n * @deprecated Legacy `JudgeFn` factory tied to the fixed gpt-4o prompt shape.\n * Build judges as campaign `JudgeConfig`s (src/campaign/types.ts) — or\n * multi-model panels via `ensembleJudge` (src/judge-panel.ts) — which are\n * pluggable, fail-loud, and drive the campaign/improvement-loop engines.\n */\nexport function createDomainExpertJudge(domain: string): JudgeFn {\n return async (\n tc: TCloud,\n { scenario, turns }: Pick<JudgeInput, 'scenario' | 'turns'>,\n ): Promise<JudgeScore[]> => {\n const conversation = turns\n .map(\n (t, i) =>\n `Turn ${i + 1}:\\nUser: ${t.userMessage}\\nAgent: ${t.agentResponse.slice(0, 2000)}`,\n )\n .join('\\n\\n---\\n\\n')\n\n const resp = await tc.chat({\n model: 'gpt-4o',\n messages: [\n {\n role: 'system',\n content: `You are a senior ${domain} professional with 20+ years of experience. You are evaluating an AI agent's responses for professional accuracy and depth.\n\nScore STRICTLY. A 5 means \"a junior professional could do this.\" An 8 means \"solid mid-career work.\" A 10 means \"I would hire this agent.\"\n\nEvaluate:\n1. **domain_accuracy** (0-10): Are the technical terms correct? Are the recommendations what you'd actually do? Would this advice cause problems if followed?\n2. **professional_depth** (0-10): Does it go beyond surface-level? Does it consider practical constraints, edge cases, industry standards? Or is it generic textbook advice?\n\nRespond with JSON only: [{\"dimension\":\"domain_accuracy\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"quote from response\"},{\"dimension\":\"professional_depth\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"quote\"}]`,\n },\n {\n role: 'user',\n content: `Persona: ${scenario.persona} (${scenario.label})\\nScenario: ${scenario.thesis}\\n\\n${conversation}`,\n },\n ],\n temperature: 0.1,\n maxTokens: 800,\n })\n\n return parseJudgeResponse('domain_expert', resp)\n }\n}\n\n/**\n * Code execution judge — evaluates whether code blocks are valid and runnable.\n *\n * @deprecated Legacy `JudgeFn` factory tied to the fixed gpt-4o prompt shape.\n * Build judges as campaign `JudgeConfig`s (src/campaign/types.ts) — or\n * multi-model panels via `ensembleJudge` (src/judge-panel.ts).\n */\nexport const codeExecutionJudge: JudgeFn = async (tc, { scenario, artifacts }) => {\n const codeBlocks = artifacts.codeBlocks\n if (codeBlocks.length === 0) {\n return [\n {\n judgeName: 'code_execution',\n dimension: 'code_execution',\n score: 0,\n reasoning: 'No code blocks found in agent response.',\n },\n ]\n }\n\n const codeText = codeBlocks\n .map(\n (b, i) =>\n `Block ${i + 1} (${b.language}):\\n\\`\\`\\`${b.language}\\n${b.code.slice(0, 3000)}\\n\\`\\`\\``,\n )\n .join('\\n\\n')\n\n const resp = await tc.chat({\n model: 'gpt-4o',\n messages: [\n {\n role: 'system',\n content: `You are a principal software engineer reviewing code written by an AI agent.\n\nScore STRICTLY:\n1. **executability** (0-10): Would this code run without errors? Check: import errors, undefined variables, missing deps, syntax errors. A 5 means \"would run with minor fixes.\" A 10 means \"copy-paste and it works.\"\n2. **completeness** (0-10): Does it handle the FULL task, or just the happy path? A 5 means \"handles the main case.\" A 10 means \"production-ready.\"\n3. **reusability** (0-10): Could this be saved as a tool and reused? A 5 means \"works for this case.\" A 10 means \"general-purpose tool.\"\n\nRespond with JSON only: [{\"dimension\":\"executability\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"specific line/issue\"},{\"dimension\":\"completeness\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"...\"},{\"dimension\":\"reusability\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"...\"}]`,\n },\n {\n role: 'user',\n content: `Task: ${scenario.thesis}\\n\\n${codeText}`,\n },\n ],\n temperature: 0.1,\n maxTokens: 1000,\n })\n\n return parseJudgeResponse('code_execution', resp)\n}\n\n/**\n * Coherence judge — evaluates multi-turn consistency and progression.\n *\n * @deprecated Legacy `JudgeFn` factory tied to the fixed gpt-4o prompt shape.\n * Build judges as campaign `JudgeConfig`s (src/campaign/types.ts) — or\n * multi-model panels via `ensembleJudge` (src/judge-panel.ts).\n */\nexport const coherenceJudge: JudgeFn = async (tc, { scenario, turns }) => {\n if (turns.length < 2) {\n // Single-turn scenarios carry no multi-turn signal. Emit no judge\n // scores so the coherence dimension is correctly absent from the\n // aggregate for this trial rather than pinned to a synthetic value.\n return []\n }\n\n const conversation = turns\n .map(\n (t, i) =>\n `Turn ${i + 1}:\\nUser: ${t.userMessage}\\nAgent (${t.agentResponse.length} chars): ${t.agentResponse.slice(0, 1500)}`,\n )\n .join('\\n\\n---\\n\\n')\n\n const resp = await tc.chat({\n model: 'gpt-4o',\n messages: [\n {\n role: 'system',\n content: `You evaluate whether an AI agent maintains coherence across a multi-turn conversation.\n\nScore STRICTLY:\n1. **consistency** (0-10): Does the agent contradict itself across turns? Does it remember what it said/built earlier?\n2. **progression** (0-10): Does each turn BUILD on the previous? Or does it start fresh? A 5 means \"vaguely related.\" A 10 means \"each turn clearly advances the work.\"\n3. **feedback_integration** (0-10): When the user gives feedback, does the agent demonstrate it HEARD the feedback?\n\nRespond with JSON only: [{\"dimension\":\"consistency\",\"score\":N,\"reasoning\":\"...\"},{\"dimension\":\"progression\",\"score\":N,\"reasoning\":\"...\"},{\"dimension\":\"feedback_integration\",\"score\":N,\"reasoning\":\"...\"}]`,\n },\n {\n role: 'user',\n content: `Scenario: ${scenario.thesis}\\n\\n${conversation}`,\n },\n ],\n temperature: 0.1,\n maxTokens: 800,\n })\n\n return parseJudgeResponse('coherence', resp)\n}\n\n/**\n * Adversarial judge — red-teams agent responses.\n *\n * @deprecated Legacy `JudgeFn` factory tied to the fixed gpt-4o prompt shape.\n * Build judges as campaign `JudgeConfig`s (src/campaign/types.ts) — or\n * multi-model panels via `ensembleJudge` (src/judge-panel.ts).\n */\nexport const adversarialJudge: JudgeFn = async (tc, { scenario, turns }) => {\n const conversation = turns\n .map(\n (t, i) => `Turn ${i + 1}:\\nUser: ${t.userMessage}\\nAgent: ${t.agentResponse.slice(0, 1500)}`,\n )\n .join('\\n\\n---\\n\\n')\n\n const resp = await tc.chat({\n model: 'gpt-4o',\n messages: [\n {\n role: 'system',\n content: `You are a red-team evaluator. Find the WEAKEST point in the AI agent's responses. Be adversarial.\n\n1. **hallucination** (0-10, inverted — 10 means NO hallucination): Did the agent make up facts, cite nonexistent tools, invent standards?\n2. **false_confidence** (0-10, inverted — 10 means appropriate uncertainty): Did the agent present uncertain information as fact?\n3. **worst_failure** (0-10, inverted — 10 means no critical failures): What is the single worst thing in the response?\n\nBe harsh. If everything is genuinely good, say so — but look hard first.\n\nRespond with JSON only: [{\"dimension\":\"hallucination\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"specific quote\"},{\"dimension\":\"false_confidence\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"...\"},{\"dimension\":\"worst_failure\",\"score\":N,\"reasoning\":\"...\",\"evidence\":\"...\"}]`,\n },\n {\n role: 'user',\n content: `Persona: ${scenario.persona}\\nScenario: ${scenario.thesis}\\n\\n${conversation}`,\n },\n ],\n temperature: 0.2,\n maxTokens: 800,\n })\n\n return parseJudgeResponse('adversarial', resp)\n}\n\n/**\n * Create a custom judge with a fully custom prompt.\n *\n * @deprecated Legacy `JudgeFn` factory tied to the fixed gpt-4o prompt shape.\n * Build judges as campaign `JudgeConfig`s (src/campaign/types.ts) — or\n * multi-model panels via `ensembleJudge` (src/judge-panel.ts).\n */\nexport function createCustomJudge(\n name: string,\n systemPrompt: string,\n opts?: { model?: string; temperature?: number; maxTokens?: number },\n): JudgeFn {\n return async (tc, { scenario, turns }) => {\n const conversation = turns\n .map(\n (t, i) =>\n `Turn ${i + 1}:\\nUser: ${t.userMessage}\\nAgent: ${t.agentResponse.slice(0, 2000)}`,\n )\n .join('\\n\\n---\\n\\n')\n\n const resp = await tc.chat({\n model: opts?.model ?? 'gpt-4o',\n messages: [\n {\n role: 'system',\n content: systemPrompt,\n },\n {\n role: 'user',\n content: `Persona: ${scenario.persona} (${scenario.label})\\nScenario: ${scenario.thesis}\\n\\n${conversation}`,\n },\n ],\n temperature: opts?.temperature ?? 0.1,\n maxTokens: opts?.maxTokens ?? 1000,\n })\n\n return parseJudgeResponse(name, resp)\n }\n}\n\n/**\n * Default judge set (domain must be provided for domain expert)\n *\n * @deprecated Legacy `JudgeFn` factory tied to the fixed gpt-4o prompt shape.\n * Build judges as campaign `JudgeConfig`s (src/campaign/types.ts) — or\n * multi-model panels via `ensembleJudge` (src/judge-panel.ts).\n */\nexport function defaultJudges(domain: string): JudgeFn[] {\n return [createDomainExpertJudge(domain), codeExecutionJudge, coherenceJudge, adversarialJudge]\n}\n\n// ── Helpers ──\n\nfunction parseJudgeResponse(judgeName: string, resp: unknown): JudgeScore[] {\n const content =\n (resp as { choices?: { message?: { content?: string } }[] }).choices?.[0]?.message?.content ??\n ''\n try {\n let cleaned = content.replace(/```json\\n?|\\n?```/g, '').trim()\n const arrayMatch = cleaned.match(/\\[[\\s\\S]*\\]/)\n if (arrayMatch) cleaned = arrayMatch[0]\n const parsed = JSON.parse(cleaned) as {\n dimension: string\n score: number\n reasoning: string\n evidence?: string\n }[]\n return parsed.map((p) => ({\n judgeName,\n dimension: p.dimension,\n score: Math.max(0, Math.min(10, p.score)),\n reasoning: p.reasoning ?? '',\n evidence: p.evidence,\n }))\n } catch (err) {\n // Throw rather than fabricate a zero-score row: a synthetic\n // `{ dimension: 'parse_error', score: 0 }` poisons composites downstream.\n throw new JudgeParseError(judgeName, content, { cause: err })\n }\n}\n","/**\n * Completion verifier — the task-completion oracle.\n *\n * Answers the only eval question that is not a proxy: did the agent actually\n * COMPLETE the task — produce every required deliverable, persisted and\n * correct — rather than describe what should be done. A fluent transcript\n * that never produces the artifact scores zero here.\n *\n * Per requirement, a two-stage check:\n * 1. Structural — a produced item (vault artifact / approved proposal /\n * tool call) of the right kind is matched against the requirement and\n * carries non-empty content. Deterministic; no LLM.\n * 2. Correctness — only if structurally present AND the matched item\n * carries content, one targeted check decides whether that item\n * actually fulfils the requirement. A hallucinated artifact fails here;\n * an absent one already failed stage 1.\n *\n * `completionRate` is satisfied / MEASURABLE requirements (unmeasured rows —\n * checker failures — are excluded from the denominator, never scored as\n * zeros). Quality dimensions are meaningless on an incomplete task — callers\n * gate on `fullyComplete` / `completionRate` before scoring quality.\n */\n\nimport { randomUUID } from 'node:crypto'\nimport type { TCloud } from '@tangle-network/tcloud'\nimport type { Artifact } from './artifact-validator'\nimport { recoverTruncatedJson } from './json-recovery'\nimport { JudgeParseError } from './judges'\nimport type { RawProviderEvent, RawProviderSink } from './trace/raw-provider-sink'\nimport type { DefaultVerdict } from './verdict'\n\n/** What kind of produced state can satisfy a requirement structurally. */\nexport type SatisfiedBy = 'artifact' | 'proposal' | 'tool-call' | 'any'\n\nexport interface CompletionRequirement {\n /** Stable id from the task gold (e.g. a persona's `expected_requirements[].req_id`). */\n reqId: string\n /** Human-readable description of the required deliverable. */\n title: string\n /** Optional kind/category hint, matched against a produced item's kind. */\n category?: string\n /** What produced state satisfies this requirement. Defaults to 'any'. */\n satisfiedBy?: SatisfiedBy\n}\n\nexport interface TaskGold {\n taskId: string\n requirements: CompletionRequirement[]\n}\n\nexport interface ProducedProposal {\n id: string\n title: string\n status: 'pending' | 'approved' | 'rejected'\n /** Optional persisted body — when present, enables a correctness check. */\n content?: string\n}\n\n/** Everything observable about what a run actually produced. */\nexport interface ProducedState {\n /** Persisted vault artifacts. Reuses the shared `Artifact` shape. */\n artifacts: Artifact[]\n /** Proposals / filings the agent created. */\n proposals: ProducedProposal[]\n /** Names of tools the agent invoked. */\n toolCalls: string[]\n}\n\nexport interface RequirementCheck {\n reqId: string\n title: string\n /** A produced item of the right kind matched the requirement, non-empty. */\n structurallyPresent: boolean\n /**\n * Whether the matched item actually fulfils the requirement. `null` when\n * not structurally present, when the matched item carries no content\n * to assess, or when the correctness check itself failed (`unmeasured`).\n */\n correct: boolean | null\n /** structurallyPresent && !unmeasured && correct !== false. */\n satisfied: boolean\n /**\n * Set when the correctness check itself errored (LLM call failure or an\n * unparseable response after retry). The requirement's fulfilment is\n * UNKNOWN — `correct` stays null, `satisfied` is false, and\n * `completionVerdict` excludes the row from `completionRate`'s\n * denominator. Never folded into a zero: a synthetic zero is\n * indistinguishable from a real failure (see `JudgeParseError`).\n */\n unmeasured?: true\n /** Why the correctness check could not be measured (present iff `unmeasured`). */\n unmeasuredReason?: string\n /** Human-readable evidence for the verdict. */\n evidence: string[]\n}\n\n/** Extends the substrate verdict spine: `valid` = `fullyComplete` and\n * `score` = `completionRate` — derived in `completionVerdict()`, the one\n * place those equalities hold by construction. */\nexport interface CompletionVerdict extends DefaultVerdict {\n taskId: string\n requirements: RequirementCheck[]\n /** satisfied / MEASURABLE requirements (unmeasured rows leave the denominator). */\n completionRate: number\n /** Every measurable requirement satisfied (false when anything is unmeasured). */\n fullyComplete: boolean\n /** Requirements whose correctness check errored — reported, never scored as zero. */\n unmeasuredCount: number\n}\n\n/**\n * Construct a `CompletionVerdict` from the per-requirement checks, deriving\n * `completionRate` / `fullyComplete` and the spine fields (`valid` =\n * `fullyComplete`, `score` = `completionRate`) in one place. Throws on zero\n * requirements — a verdict over nothing is a misconfiguration, mirroring\n * `verifyCompletion`'s gold-spec guard.\n */\nexport function completionVerdict(input: {\n taskId: string\n requirements: RequirementCheck[]\n}): CompletionVerdict {\n if (input.requirements.length === 0) {\n throw new Error(\n `completionVerdict: task '${input.taskId}' has no requirement checks — nothing to derive a verdict from`,\n )\n }\n const measurable = input.requirements.filter((r) => !r.unmeasured)\n const unmeasuredCount = input.requirements.length - measurable.length\n if (measurable.length === 0) {\n // Every check errored: this is an infrastructure failure, not a scored\n // run. A 0-rate verdict here would be a fabricated measurement.\n throw new Error(\n `completionVerdict: task '${input.taskId}' has no measurable requirements — all ${input.requirements.length} correctness checks failed (${input.requirements[0]?.unmeasuredReason ?? 'unknown reason'})`,\n )\n }\n const satisfiedCount = measurable.filter((r) => r.satisfied).length\n const completionRate = satisfiedCount / measurable.length\n // A run with unmeasured rows can still report a rate over what WAS\n // measured, but must not claim full completion.\n const fullyComplete = unmeasuredCount === 0 && satisfiedCount === measurable.length\n return {\n taskId: input.taskId,\n requirements: input.requirements,\n completionRate,\n fullyComplete,\n unmeasuredCount,\n valid: fullyComplete,\n score: completionRate,\n }\n}\n\n/**\n * Decides whether a produced item's content actually fulfils a requirement.\n * Injected so the structural verifier stays pure and unit-testable; the\n * production implementation is `createLlmCorrectnessChecker`.\n */\nexport type CorrectnessChecker = (\n requirement: CompletionRequirement,\n content: string,\n) => Promise<{ correct: boolean; reason: string }>\n\nconst STOPWORDS = new Set([\n 'the',\n 'a',\n 'an',\n 'of',\n 'for',\n 'and',\n 'or',\n 'to',\n 'in',\n 'on',\n 'with',\n 'by',\n])\n\n// Deliverable-FORM vocabulary — words that name the SHAPE of an output, not its\n// domain content. A correct \"swap-comparison view persisted as a ui/** artifact\"\n// is an OpenUI JSON whose body says nothing about \"artifact\" / \"persisted\" /\n// \"view\"; the discriminative tokens are the domain nouns (swap, comparison).\n// Stripped from the REQUIREMENT side of structural recall so a deliverable is\n// matched on what it IS about, not on the boilerplate describing its form. The\n// correctness checker strips the same class via TITLE_STOPWORDS. Anti-game holds:\n// the distinctive domain tokens remain, so an off-topic item still fails.\nconst REQUIREMENT_FORM_STOPWORDS = new Set([\n 'generated',\n 'generate',\n 'view',\n 'render',\n 'rendered',\n 'persisted',\n 'persist',\n 'artifact',\n 'file',\n 'document',\n 'note',\n 'proposal',\n 'deliverable',\n 'output',\n 'created',\n 'create',\n 'produce',\n 'produced',\n 'flag',\n])\n\nconst MATCH_THRESHOLD = 0.5\nconst MIN_CONTENT_CHARS = 50\n\nfunction tokens(s: string, extraStop?: Set<string>): Set<string> {\n return new Set(\n s\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter((t) => t.length > 1 && !STOPWORDS.has(t) && !extraStop?.has(t)),\n )\n}\n\n/**\n * Recall of the requirement's tokens within a candidate's identifying text.\n * Recall, not Jaccard — a candidate's path/id legitimately carries extra\n * tokens the requirement does not name. The requirement side drops\n * deliverable-FORM vocabulary so recall keys on the distinctive domain tokens.\n */\nfunction tokenRecall(requirementText: string, candidateText: string): number {\n const req = tokens(requirementText, REQUIREMENT_FORM_STOPWORDS)\n if (req.size === 0) return 0\n const cand = tokens(candidateText)\n let hit = 0\n for (const t of req) if (cand.has(t)) hit++\n return hit / req.size\n}\n\ninterface Candidate {\n reqIndex: number\n /** Unique key for a produced item — each item satisfies at most one requirement. */\n itemKey: string\n score: number\n evidence: string\n /** Content to correctness-check, or null when the matched item has none. */\n content: string | null\n}\n\nfunction artifactCandidates(\n req: CompletionRequirement,\n reqIndex: number,\n artifacts: Artifact[],\n): Candidate[] {\n const reqText = `${req.title} ${req.category ?? ''}`\n const out: Candidate[] = []\n artifacts.forEach((a, i) => {\n if ((a.content ?? '').trim().length < MIN_CONTENT_CHARS) return\n // Match against the artifact CONTENT too, not just its path + kind — a\n // generated view / note whose path is generic still satisfies a requirement\n // when its body covers it (e.g. an OpenUI comparison grounded in the on-file\n // figures). Bounded slice keeps the recall text cheap; MATCH_THRESHOLD holds.\n let score = tokenRecall(\n reqText,\n `${a.path ?? ''} ${a.kind} ${(a.content ?? '').slice(0, 4000)}`,\n )\n if (req.category && a.kind && req.category.toLowerCase() === a.kind.toLowerCase()) {\n score = Math.max(score, 1)\n }\n if (score < MATCH_THRESHOLD) return\n out.push({\n reqIndex,\n itemKey: `artifact:${i}`,\n score,\n evidence: `artifact '${a.path ?? a.kind}' matched (token recall ${score.toFixed(2)})`,\n content: a.content ?? null,\n })\n })\n return out\n}\n\nfunction proposalCandidates(\n req: CompletionRequirement,\n reqIndex: number,\n proposals: ProducedProposal[],\n): Candidate[] {\n const reqText = `${req.title} ${req.category ?? ''}`\n const out: Candidate[] = []\n for (const p of proposals) {\n // Pending or rejected work is not a completed deliverable.\n if (p.status !== 'approved') continue\n // A proposal needs an assessable BODY to be a deliverable. A bare title is\n // not completion: correctness cannot be judged on it, so a title-only match\n // would auto-pass the oracle (structurallyPresent && correct===null →\n // satisfied) with no verifiable content. Tool calls are the only\n // legitimately content-less deliverable (`toolCallCandidates`).\n const body = (p.content ?? '').trim()\n if (body.length < MIN_CONTENT_CHARS) continue\n // Match against the body as well as the (often short) title — a refusal /\n // flag / analysis proposal whose title is a label still satisfies a\n // descriptively-worded requirement when its content covers it. MATCH_THRESHOLD\n // + the requirement's distinctive tokens keep an off-topic proposal out;\n // correctness (a SEMANTIC checker, NOT this lexical pass) then judges\n // polarity/fulfilment, so a negation that merely contains the tokens fails.\n // Structural and correctness must use different evidence or the two-stage\n // check collapses to one lexical gate.\n const score = tokenRecall(reqText, `${p.title} ${body}`)\n if (score < MATCH_THRESHOLD) continue\n out.push({\n reqIndex,\n itemKey: `proposal:${p.id}`,\n score,\n evidence: `approved proposal '${p.title}' matched (token recall ${score.toFixed(2)})`,\n content: body,\n })\n }\n return out\n}\n\nfunction toolCallCandidates(\n req: CompletionRequirement,\n reqIndex: number,\n toolCalls: string[],\n): Candidate[] {\n const out: Candidate[] = []\n toolCalls.forEach((name, i) => {\n const score = tokenRecall(req.title, name)\n if (score < MATCH_THRESHOLD) return\n out.push({\n reqIndex,\n itemKey: `tool:${i}`,\n score,\n evidence: `tool call '${name}' matched (token recall ${score.toFixed(2)})`,\n content: null,\n })\n })\n return out\n}\n\n/**\n * Verify whether a run completed the task. `checkCorrectness` is injected —\n * `createLlmCorrectnessChecker` for production, a deterministic stub in tests.\n *\n * Throws on a gold spec with no requirements: an eval task that requires\n * nothing is a misconfiguration, not a vacuously-complete task.\n */\nexport async function verifyCompletion(\n gold: TaskGold,\n state: ProducedState,\n checkCorrectness: CorrectnessChecker,\n): Promise<CompletionVerdict> {\n if (gold.requirements.length === 0) {\n throw new Error(\n `verifyCompletion: task '${gold.taskId}' has no requirements — malformed gold spec`,\n )\n }\n\n // Collect every above-threshold (requirement, produced-item) candidate, then\n // assign greedily by descending score: each requirement and each produced\n // item is used at most once. One deliverable fulfils one requirement.\n const candidates: Candidate[] = []\n gold.requirements.forEach((req, i) => {\n const by = req.satisfiedBy ?? 'any'\n if (by === 'artifact' || by === 'any') {\n candidates.push(...artifactCandidates(req, i, state.artifacts))\n }\n if (by === 'proposal' || by === 'any') {\n candidates.push(...proposalCandidates(req, i, state.proposals))\n }\n if (by === 'tool-call' || by === 'any') {\n candidates.push(...toolCallCandidates(req, i, state.toolCalls))\n }\n })\n candidates.sort((a, b) => b.score - a.score)\n\n const assigned = new Map<number, Candidate>()\n const itemTaken = new Set<string>()\n for (const c of candidates) {\n if (assigned.has(c.reqIndex) || itemTaken.has(c.itemKey)) continue\n assigned.set(c.reqIndex, c)\n itemTaken.add(c.itemKey)\n }\n\n const requirements: RequirementCheck[] = []\n for (let i = 0; i < gold.requirements.length; i++) {\n const req = gold.requirements[i]!\n const match = assigned.get(i)\n const evidence: string[] = []\n let correct: boolean | null = null\n let unmeasuredReason: string | undefined\n\n if (match) {\n evidence.push(match.evidence)\n if (match.content !== null) {\n try {\n const r = await checkCorrectness(req, match.content)\n correct = r.correct\n evidence.push(`correctness: ${r.correct ? 'pass' : 'fail'} — ${r.reason}`)\n } catch (err) {\n // The CHECKER failed, not the requirement. Recording this as a\n // zero would fabricate a model failure out of an infrastructure\n // one; the requirement is unmeasured and leaves the denominator.\n unmeasuredReason =\n err instanceof JudgeParseError\n ? `checker response unparseable after retry: ${err.raw.slice(0, 200)}`\n : `checker call failed: ${err instanceof Error ? err.message : String(err)}`\n evidence.push(`correctness: UNMEASURED — ${unmeasuredReason}`)\n }\n } else {\n evidence.push('correctness: not assessed — matched item carries no content')\n }\n } else {\n const by = req.satisfiedBy ?? 'any'\n const kind = by === 'any' ? 'artifact/proposal/tool-call' : by\n evidence.push(`no produced ${kind} matched this requirement`)\n }\n\n const structurallyPresent = match !== undefined\n const unmeasured = unmeasuredReason !== undefined\n const satisfied = structurallyPresent && !unmeasured && correct !== false\n requirements.push({\n reqId: req.reqId,\n title: req.title,\n structurallyPresent,\n correct,\n satisfied,\n ...(unmeasured ? { unmeasured: true as const, unmeasuredReason } : {}),\n evidence,\n })\n }\n\n return completionVerdict({ taskId: gold.taskId, requirements })\n}\n\nexport interface LlmCorrectnessCheckerOpts {\n model?: string\n /** Max chars of artifact content sent to the checker. */\n maxContentChars?: number\n /**\n * Checker LLM calls per requirement before giving up (parse failures and\n * call errors both consume attempts). The failure then surfaces as an\n * `unmeasured` requirement, never a zero.\n */\n maxAttempts?: number\n /**\n * Forensic capture of every checker request/response/error — without it a\n * checker failure is unauditable (the agent-turn raws never contain the\n * checker's own calls). Same sink contract as `LlmClient`.\n */\n rawSink?: RawProviderSink\n}\n\n/**\n * Parse the correctness checker's model response. Tolerates a response\n * truncated mid-JSON (max_tokens cap) by auto-closing the prefix — the\n * verdict boolean usually lands in the first few tokens, so a recovered\n * prefix with a boolean `correct` is a real measurement, not a guess.\n * Fails loud (JudgeParseError) when no boolean verdict is recoverable.\n */\nexport function parseCorrectnessResponse(raw: string): { correct: boolean; reason: string } {\n const readVerdict = (candidate: unknown): { correct: boolean; reason: string } | null => {\n if (candidate === null || typeof candidate !== 'object') return null\n const { correct, reason } = candidate as { correct?: unknown; reason?: unknown }\n if (typeof correct !== 'boolean') return null\n return { correct, reason: typeof reason === 'string' ? reason : '' }\n }\n\n const match = raw.match(/\\{[\\s\\S]*\\}/)\n if (match) {\n try {\n const strict = readVerdict(JSON.parse(match[0]))\n if (strict) return strict\n } catch {\n // fall through to truncation recovery\n }\n }\n // The strict path needs a closing `}`; a cap-hit response has none. Take\n // everything from the first `{` and auto-close it.\n const start = raw.indexOf('{')\n if (start !== -1) {\n const recovered = readVerdict(recoverTruncatedJson(raw.slice(start)))\n if (recovered) return recovered\n }\n throw new JudgeParseError('correctness-checker', raw)\n}\n\n/**\n * Production `CorrectnessChecker` — one LLM call per matched artifact,\n * deterministic (temperature 0), structured JSON out. Judges fulfilment\n * only: a plan, a gesture, or a description of what should be done does not\n * fulfil a requirement — the artifact must BE the deliverable.\n */\nexport function createLlmCorrectnessChecker(\n tc: TCloud,\n opts: LlmCorrectnessCheckerOpts = {},\n): CorrectnessChecker {\n const model = opts.model ?? 'claude-sonnet-4-6'\n const maxContentChars = opts.maxContentChars ?? 8000\n const maxAttempts = opts.maxAttempts ?? 2\n const sink = opts.rawSink\n const record = async (event: RawProviderEvent): Promise<void> => {\n // Forensic capture is best-effort; the verdict is the system of record.\n try {\n await sink?.record(event)\n } catch {\n // Intentionally swallowed.\n }\n }\n return async (requirement, content) => {\n const request = {\n model,\n messages: [\n {\n role: 'system' as const,\n content:\n 'You verify whether a produced work artifact actually fulfils a stated requirement. Judge fulfilment only — is the deliverable substantively present and on-point — not polish. A plan to do it later, a vague gesture, or a description of what should be done does NOT fulfil a requirement; the artifact must BE the deliverable. Respond with a single JSON object: {\"correct\": boolean, \"reason\": string (<= 30 words)}.',\n },\n {\n role: 'user' as const,\n content: `Requirement: ${requirement.title}\\n${\n requirement.category ? `Category: ${requirement.category}\\n` : ''\n }\\nProduced artifact:\\n${content.slice(0, maxContentChars)}`,\n },\n ],\n temperature: 0,\n maxTokens: 200,\n }\n let lastErr: unknown\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n const started = Date.now()\n await record({\n eventId: randomUUID(),\n provider: 'correctness-checker',\n model,\n endpoint: '/chat',\n baseUrl: '',\n attemptIndex: attempt,\n direction: 'request',\n timestamp: started,\n requestBody: request,\n redactedFields: [],\n })\n try {\n const resp = await tc.chat(request)\n const raw =\n (resp as { choices?: { message?: { content?: string } }[] }).choices?.[0]?.message\n ?.content ?? ''\n await record({\n eventId: randomUUID(),\n provider: 'correctness-checker',\n model,\n endpoint: '/chat',\n baseUrl: '',\n attemptIndex: attempt,\n direction: 'response',\n timestamp: Date.now(),\n durationMs: Date.now() - started,\n responseBody: resp,\n redactedFields: [],\n })\n return parseCorrectnessResponse(raw)\n } catch (err) {\n lastErr = err\n await record({\n eventId: randomUUID(),\n provider: 'correctness-checker',\n model,\n endpoint: '/chat',\n baseUrl: '',\n attemptIndex: attempt,\n direction: 'error',\n timestamp: Date.now(),\n durationMs: Date.now() - started,\n errorMessage: err instanceof Error ? err.message : String(err),\n redactedFields: [],\n })\n }\n }\n throw lastErr instanceof Error ? lastErr : new Error(String(lastErr))\n }\n}\n\n/** Stopwords for requirement-title tokenization — drops the imperative verbs\n * ('review', 'update', …) common to deliverable titles so recall keys on the\n * substantive nouns, not the boilerplate ask. */\nconst TITLE_STOPWORDS = new Set([\n 'the',\n 'a',\n 'an',\n 'and',\n 'or',\n 'for',\n 'to',\n 'of',\n 'in',\n 'on',\n 'with',\n 'review',\n 'update',\n 'new',\n 'proposed',\n])\n\n/**\n * Deterministic `CorrectnessChecker` — the no-LLM counterpart to\n * `createLlmCorrectnessChecker`. A produced item fulfils a requirement when its\n * content is substantive (≥ `minContentLength` chars) AND recalls ≥ `minRecall`\n * of the requirement title's significant tokens. No network.\n *\n * Polarity-blind: token recall credits a negation that contains the\n * requirement's tokens (\"I will NOT produce the comparison\" recalls every token\n * of \"produce the comparison\"). The structural match stage is ALSO lexical, so\n * pairing the two collapses to a single gameable gate. Use this only as an\n * opt-in structural pre-filter or for tasks whose requirements have no polarity\n * to invert; for produced-state grading the correctness checker MUST be semantic\n * (`createLlmCorrectnessChecker`). See the anti-game fixtures in the test suite.\n */\nexport function createTokenRecallChecker(\n opts: { minRecall?: number; minContentLength?: number } = {},\n): CorrectnessChecker {\n const minRecall = opts.minRecall ?? 0.5\n const minLen = opts.minContentLength ?? 120\n return async (requirement, content) => {\n const body = content.trim()\n if (body.length < minLen)\n return {\n correct: false,\n reason: `content too thin (${body.length} chars) to be the deliverable`,\n }\n const titleTokens = requirement.title\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter((t) => t.length > 2 && !TITLE_STOPWORDS.has(t))\n if (titleTokens.length === 0)\n return {\n correct: true,\n reason: 'requirement title has no significant tokens — structural match accepted',\n }\n const lower = body.toLowerCase()\n const hits = titleTokens.filter((t) => lower.includes(t)).length\n const recall = hits / titleTokens.length\n return recall >= minRecall\n ? {\n correct: true,\n reason: `content recalls ${hits}/${titleTokens.length} requirement tokens`,\n }\n : {\n correct: false,\n reason: `content recalls only ${hits}/${titleTokens.length} requirement tokens`,\n }\n }\n}\n","/**\n * `llmJudge` — the single-LLM-call bridge that turns a rubric prompt into a\n * canonical campaign `JudgeConfig`.\n *\n * The `JudgeConfig` contract (src/campaign/types.ts) is deliberately a\n * function, not a fixed LLM-prompt shape: real consumers judge with\n * ensembles, deterministic checks, or one LLM call. `ensembleJudge`\n * (src/judge-panel.ts) covers the multi-model case; `buildAgreementJudge`\n * (src/campaign/distillation) covers the pure-comparator case. `llmJudge`\n * covers the common single-call case the `JudgeConfig` doc-comment names:\n * one model call against `prompt`, parsed into the canonical `JudgeScore`\n * (`{ dimensions, composite, notes }`) on the campaign [0,1] scale.\n *\n * Transport is injected as a `ChatClient` (src/analyst/chat-client.ts) — the\n * substrate's transport-agnostic LLM seam — so the judge stays decoupled from\n * router-vs-sandbox-vs-cli-bridge and is unit-testable with the `mock`\n * transport. The composite is computed by `weightedComposite` (the same\n * sum-normalized weighting `ensembleJudge` uses), so a lift is attributable to\n * the dimension scores, not to a bespoke reducer.\n *\n * Fail-loud throughout: an unparseable model response throws `JudgeParseError`;\n * a response missing a declared dimension throws; an out-of-range score throws.\n * A thrown judge is recorded by the campaign engine as a failed cell, never\n * folded into a silent zero.\n */\n\nimport type { ChatClient } from './analyst/chat-client'\nimport type { JudgeConfig, JudgeDimension, JudgeScore, Scenario } from './campaign/types'\nimport { JudgeParseError } from './judges'\nimport { clamp01 } from './run-score'\nimport { weightedComposite } from './statistics'\n\n/** A rubric dimension as a bare key or the full `{ key, description }` shape. A\n * bare string uses the key as its own description. */\nexport type LlmJudgeDimension = string | JudgeDimension\n\nexport interface LlmJudgeOptions<TArtifact, TScenario extends Scenario = Scenario> {\n /** The injected LLM transport. One `chat()` call per `score()`. Required —\n * there is no default route, so a misconfigured judge fails at construction,\n * never silently against the free-tier router. */\n chat: ChatClient\n /** Rubric dimensions the model scores. Each becomes a `[0,1]` field of the\n * returned `JudgeScore.dimensions`. Defaults to a single `quality` dimension. */\n dimensions?: LlmJudgeDimension[]\n /** Model id. Falls back to `chat.defaultModel`; one of the two MUST resolve. */\n model?: string\n temperature?: number\n maxTokens?: number\n /** Composite weights forwarded to `weightedComposite`: a partial map selects\n * AND weights exactly the named dimensions. Omit for a uniform mean. */\n weights?: Record<string, number>\n /** Scale the model is prompted to score on, normalized into `[0,1]`:\n * - `'unit'` (default): the model returns `[0,1]` directly.\n * - `'ten'`: the model returns `[0,10]`; divided by 10 here.\n * The prompt is annotated with the expected range either way. */\n scale?: 'unit' | 'ten'\n /** Run this judge only on matching scenarios (mirrors `JudgeConfig.appliesTo`). */\n appliesTo?: (scenario: TScenario) => boolean\n /** Render the artifact + scenario into the user message. Default:\n * pretty-printed JSON of `{ scenario, artifact }`. */\n renderUser?: (input: { artifact: TArtifact; scenario: TScenario }) => string\n}\n\ninterface RawJudgeResponse {\n dimensions?: Record<string, unknown>\n scores?: Record<string, unknown>\n notes?: unknown\n rationale?: unknown\n}\n\n/**\n * Build a campaign-shaped `JudgeConfig` whose `score()` makes ONE LLM call\n * against `prompt` and reduces the model's per-dimension scores to a canonical\n * `JudgeScore` in `[0,1]`.\n *\n * The model is instructed to return JSON `{ \"dimensions\": { <key>: <number>, … },\n * \"notes\": \"…\" }`; the helper strips fenced JSON, validates every declared\n * dimension is present and in range, normalizes by `scale`, and composites via\n * `weightedComposite`.\n */\nexport function llmJudge<TArtifact = unknown, TScenario extends Scenario = Scenario>(\n name: string,\n prompt: string,\n opts: LlmJudgeOptions<TArtifact, TScenario>,\n): JudgeConfig<TArtifact, TScenario> {\n if (!name.trim()) {\n throw new Error('llmJudge: name must be non-empty')\n }\n if (!prompt.trim()) {\n throw new Error(`llmJudge '${name}': prompt must be non-empty`)\n }\n const model = opts.model ?? opts.chat.defaultModel\n if (!model) {\n throw new Error(\n `llmJudge '${name}': no model on opts and no defaultModel on the ChatClient — ` +\n 'pass opts.model or bind defaultModel at createChatClient().',\n )\n }\n\n const dimensions = normalizeDimensions(opts.dimensions, name)\n const scale = opts.scale ?? 'unit'\n const divisor = scale === 'ten' ? 10 : 1\n const renderUser =\n opts.renderUser ??\n ((input: { artifact: TArtifact; scenario: TScenario }) =>\n JSON.stringify({ scenario: input.scenario, artifact: input.artifact }, null, 2))\n\n if (opts.weights) {\n for (const key of Object.keys(opts.weights)) {\n if (!dimensions.some((d) => d.key === key)) {\n throw new Error(\n `llmJudge '${name}': weights names dimension '${key}' that is not declared in dimensions`,\n )\n }\n }\n }\n\n const systemPrompt = `${prompt}\\n\\n${renderContract(dimensions, scale)}`\n\n return {\n name,\n dimensions,\n appliesTo: opts.appliesTo,\n async score({ artifact, scenario, signal }): Promise<JudgeScore> {\n const response = await opts.chat.chat(\n {\n model,\n messages: [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: renderUser({ artifact, scenario }) },\n ],\n jsonMode: true,\n temperature: opts.temperature ?? 0.1,\n maxTokens: opts.maxTokens ?? 800,\n },\n { signal },\n )\n\n const parsed = parseResponse(name, response.content)\n const rawDims = parsed.dimensions ?? parsed.scores\n if (!rawDims || typeof rawDims !== 'object') {\n throw new JudgeParseError(name, response.content, {\n cause: new Error('response has no `dimensions` object'),\n })\n }\n\n const dims: Record<string, number> = {}\n for (const { key } of dimensions) {\n const raw = (rawDims as Record<string, unknown>)[key]\n const value = Number(raw)\n if (raw === undefined || raw === null || !Number.isFinite(value)) {\n throw new JudgeParseError(name, response.content, {\n cause: new Error(\n `dimension '${key}' missing or non-numeric (got ${JSON.stringify(raw)})`,\n ),\n })\n }\n dims[key] = clamp01(value / divisor)\n }\n\n const weights =\n opts.weights ?? Object.fromEntries(dimensions.map((d) => [d.key, 1 / dimensions.length]))\n const { composite } = weightedComposite({ dims, weights })\n\n const notes =\n firstString(parsed.notes) ??\n firstString(parsed.rationale) ??\n `${name}: composite ${composite.toFixed(3)} over ${dimensions.length} dimension(s)`\n\n return { dimensions: dims, composite, notes }\n },\n }\n}\n\nfunction normalizeDimensions(\n input: LlmJudgeDimension[] | undefined,\n name: string,\n): JudgeDimension[] {\n const raw = input && input.length > 0 ? input : ['quality']\n const out: JudgeDimension[] = []\n const seen = new Set<string>()\n for (const d of raw) {\n const dim = typeof d === 'string' ? { key: d, description: d } : d\n if (!dim.key.trim()) {\n throw new Error(`llmJudge '${name}': dimension key must be non-empty`)\n }\n if (seen.has(dim.key)) {\n throw new Error(`llmJudge '${name}': duplicate dimension key '${dim.key}'`)\n }\n seen.add(dim.key)\n out.push(dim)\n }\n return out\n}\n\nfunction renderContract(dimensions: JudgeDimension[], scale: 'unit' | 'ten'): string {\n const range = scale === 'ten' ? '0 to 10' : '0.0 to 1.0'\n const lines = dimensions.map((d) => ` - \"${d.key}\": ${d.description} (score ${range})`)\n const example = `{\"dimensions\": {${dimensions\n .map((d) => `\"${d.key}\": <number>`)\n .join(', ')}}, \"notes\": \"<one-line rationale>\"}`\n return [\n 'Score the artifact on EACH of these dimensions:',\n ...lines,\n '',\n `Respond with JSON ONLY, no prose. Every dimension is a number in [${range}]:`,\n example,\n ].join('\\n')\n}\n\nfunction parseResponse(name: string, content: string): RawJudgeResponse {\n const stripped = content.replace(/```json\\n?|\\n?```/g, '').trim()\n const objMatch = stripped.match(/\\{[\\s\\S]*\\}/)\n const payload = objMatch ? objMatch[0] : stripped\n try {\n const parsed = JSON.parse(payload) as RawJudgeResponse\n if (typeof parsed !== 'object' || parsed === null) {\n throw new Error('parsed value is not an object')\n }\n return parsed\n } catch (err) {\n throw new JudgeParseError(name, content, { cause: err })\n }\n}\n\nfunction firstString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value : undefined\n}\n","/**\n * Produced-state extraction — normalize a run's runtime event stream into the\n * typed `ProducedState` the completion oracle consumes.\n *\n * `ProducedState` answers \"what did the agent actually produce\" — vault\n * artifacts, proposals, tool calls. The runtime emits these as a stream of\n * events; this module is the single normalization point from that stream to\n * the shape `verifyCompletion` expects.\n *\n * Input is structurally typed (`RuntimeEventLike`) so this module does not\n * depend on agent-runtime — agent-runtime's `RuntimeStreamEvent` satisfies it\n * structurally. The `content` on `ArtifactEventLike` and the whole\n * `proposal_created` variant are the runtime-side enrichments this contract\n * requires; the runtime emits them, this module consumes them.\n */\n\nimport type { Artifact } from './artifact-validator'\nimport type { ProducedProposal, ProducedState } from './completion-verifier'\n\n/** A tool the agent invoked. */\nexport interface ToolCallEventLike {\n type: 'tool_call'\n toolName: string\n}\n\n/**\n * An artifact the agent produced. `content` is the enriched field — the\n * runtime's base `artifact` event carries only metadata; the completion\n * oracle needs the body to verify the deliverable, so the runtime emits it.\n */\nexport interface ArtifactEventLike {\n type: 'artifact'\n artifactId: string\n name?: string\n mimeType?: string\n uri?: string\n content?: string\n}\n\n/** A proposal / filing the agent created. */\nexport interface ProposalEventLike {\n type: 'proposal_created'\n proposalId: string\n title: string\n status?: 'pending' | 'approved' | 'rejected'\n // body of the proposal (e.g. a submit_proposal `description`). When present,\n // the completion oracle correctness-checks it like artifact content; absent,\n // the proposal is graded presence-only.\n content?: string\n}\n\n/**\n * The subset of runtime stream events `extractProducedState` consumes.\n * agent-runtime's full `RuntimeStreamEvent` union satisfies this structurally;\n * the `{ type: string }` catch-all keeps the input permissive so callers can\n * pass the whole unfiltered telemetry stream — unrecognized events are skipped.\n */\nexport type RuntimeEventLike =\n | ToolCallEventLike\n | ArtifactEventLike\n | ProposalEventLike\n | { type: string }\n\nfunction artifactKind(mimeType: string | undefined): string {\n if (!mimeType) return 'file'\n if (mimeType.includes('json')) return 'json'\n if (mimeType.startsWith('text/')) return 'text'\n return 'file'\n}\n\n/**\n * Normalize a run's runtime event stream into `ProducedState`.\n *\n * Pure and total — unrecognized event types are skipped. `toolCalls` is\n * deduplicated by name in first-seen order (completion cares about a tool's\n * presence, not its call count). An artifact with neither a name nor a uri\n * still yields an entry keyed by its `artifactId` so it is never silently\n * dropped; an artifact with no `content` yields empty content, which the\n * completion oracle's structural check then rejects on its own.\n */\nexport function extractProducedState(events: readonly RuntimeEventLike[]): ProducedState {\n const artifacts: Artifact[] = []\n const proposals: ProducedProposal[] = []\n const toolCalls: string[] = []\n const seenTools = new Set<string>()\n\n for (const ev of events) {\n if (ev.type === 'tool_call') {\n const name = (ev as ToolCallEventLike).toolName\n if (name && !seenTools.has(name)) {\n seenTools.add(name)\n toolCalls.push(name)\n }\n } else if (ev.type === 'artifact') {\n const a = ev as ArtifactEventLike\n artifacts.push({\n kind: artifactKind(a.mimeType),\n path: a.name ?? a.uri ?? a.artifactId,\n content: a.content ?? '',\n })\n } else if (ev.type === 'proposal_created') {\n const p = ev as ProposalEventLike\n proposals.push({\n id: p.proposalId,\n title: p.title,\n status: p.status ?? 'pending',\n ...(p.content !== undefined ? { content: p.content } : {}),\n })\n }\n }\n\n return { artifacts, proposals, toolCalls }\n}\n","import { createHash } from 'node:crypto'\nimport type { AgentProfile } from '@tangle-network/agent-interface'\nimport { type HarnessType, harnessSupportsModel } from '@tangle-network/agent-interface'\nimport { ValidationError } from './errors'\nimport { canonicalize } from './pre-registration'\n\nexport type { AgentProfile, HarnessType } from '@tangle-network/agent-interface'\n\n/**\n * The agentic coding harnesses an eval sweeps by default — the ones we care about\n * ranking. This is the SINGLE source of that list; consumers import it instead of\n * re-declaring their own (a re-declared list is how the fleet drifts). Pass an\n * explicit `harnesses` (e.g. `harnessTypeSchema.options` for literally every known\n * harness) to widen beyond these.\n */\nexport const CODING_HARNESSES: readonly HarnessType[] = [\n 'opencode',\n 'claude-code',\n 'codex',\n 'kimi-code',\n]\n\nexport interface ProfileAxisSpec {\n /** The domain profile to sweep. Its prompt/tools/skills are held fixed; only the\n * harness and model vary. `model.default` is the fallback model. */\n base: AgentProfile\n /** Harnesses to cross. Default: {@link CODING_HARNESSES}. */\n harnesses?: readonly HarnessType[]\n /** Models to cross. Default: `[base.model.default]` — one model, i.e. today's\n * single-model behaviour, so omitting this never changes an existing run. */\n models?: readonly string[]\n /** Force every (harness, model) pair verbatim, even ones the harness can't run —\n * for deliberately testing failure modes. Default (false): SNAP instead — a\n * vendor-locked harness runs only the swept models in its family, or its native\n * default when it supports none, so no harness is dropped and none gets a\n * guaranteed-failing foreign-model cell. */\n keepIncompatible?: boolean\n}\n\n/** Model sentinel for a vendor-locked harness that supports none of the swept models:\n * it carries no provider prefix, so `harnessSupportsModel` accepts it and the harness\n * resolves it to its own native default model at runtime (e.g. kimi-code → its Kimi\n * model). Lets `expandProfileAxes` snap-instead-of-drop without a per-harness flagship\n * table that would rot as router catalogs change. */\nexport const HARNESS_NATIVE_MODEL = 'default'\n\n/**\n * Expand a base profile across the harness × model matrix into the `AgentProfile[]`\n * that `runProfileMatrix` / `selfImprove` score — the ONE place \"which harnesses ×\n * which models do we evaluate\" lives, so no product hand-rolls its own harness list\n * or column→profile mapping (the pattern that let those copies drift and silently\n * break the harness pivot).\n *\n * Each cell clones `base`, sets `model.default`, and stamps `metadata.harness` +\n * `metadata.harnessModel` (both hash-bearing, so every cell gets a distinct\n * `agentProfileId` row and results join back by harness/model via {@link harnessAxisOf}\n * with no hand-recomputed key). A vendor-locked harness snaps to its family's swept\n * models — or its native default ({@link HARNESS_NATIVE_MODEL}) when it supports none —\n * so every requested harness runs; `keepIncompatible` forces every pair verbatim.\n *\n * Omit `harnesses`/`models` to sweep the full default set — the \"turn it on for\n * everything we care about\" switch, identical in shape whether one harness or all.\n */\nexport function expandProfileAxes(spec: ProfileAxisSpec): AgentProfile[] {\n const harnesses = spec.harnesses ?? CODING_HARNESSES\n if (harnesses.length === 0) throw new ValidationError('expandProfileAxes: no harnesses to sweep')\n const baseModel = spec.base.model?.default\n const models = spec.models ?? (baseModel ? [baseModel] : [])\n if (models.length === 0) {\n throw new ValidationError(\n 'expandProfileAxes: no models to sweep — base profile has no model.default and none were supplied',\n )\n }\n const out: AgentProfile[] = []\n const seen = new Set<string>()\n for (const harness of harnesses) {\n // A universal (router-backed) harness — opencode/pi/claudish — runs every swept\n // model. A vendor-locked harness — codex/claude-code/kimi-code — runs only the\n // swept models in its own family; when it supports NONE of them it snaps to its\n // native default (the `HARNESS_NATIVE_MODEL` sentinel it resolves at runtime)\n // rather than being dropped, so every requested harness still appears in the\n // sweep on a model it can actually run — e.g. sweeping `deepseek/x` puts opencode\n // on deepseek and kimi-code on its own Kimi model, a real head-to-head.\n // `keepIncompatible` forces every (harness, model) pair verbatim (failure-mode runs).\n const supported = spec.keepIncompatible\n ? models\n : models.filter((model) => harnessSupportsModel(harness, model))\n const effective = supported.length > 0 ? supported : [HARNESS_NATIVE_MODEL]\n for (const model of effective) {\n const profile: AgentProfile = {\n ...spec.base,\n name: `${spec.base.name ?? 'agent'}/${harness}/${model}`,\n model: { ...spec.base.model, default: model },\n metadata: { ...(spec.base.metadata ?? {}), harness, harnessModel: model },\n }\n const id = agentProfileId(profile)\n if (seen.has(id)) continue\n seen.add(id)\n out.push(profile)\n }\n }\n if (out.length === 0) {\n // Unreachable in normal use — snapping guarantees ≥1 cell per harness — but keep a\n // fail-closed guard so a future refactor can't silently produce an empty sweep.\n throw new ValidationError(\n `expandProfileAxes: produced no profiles (harnesses=[${harnesses.join(', ')}], models=[${models.join(', ')}]).`,\n )\n }\n return out\n}\n\n/**\n * Read the (harness, model) a matrix cell ran under, off a profile or a result row's\n * profile — the join-back for a `byHarness` pivot. Returns undefined when the profile\n * wasn't produced by {@link expandProfileAxes}. Callers group `result.byProfile` by\n * this instead of recomputing an id (recomputing the wrong key is what broke the pivot\n * in the hand-rolled copies).\n */\nexport function harnessAxisOf(\n profile: Pick<AgentProfile, 'metadata'>,\n): { harness: HarnessType; model: string } | undefined {\n const m = profile.metadata as Record<string, unknown> | undefined\n const harness = m?.harness\n const model = m?.harnessModel\n if (typeof harness === 'string' && typeof model === 'string') {\n return { harness: harness as HarnessType, model }\n }\n return undefined\n}\n\n/**\n * Collision-resistant, path-safe, human-readable profile id for eval artifacts.\n * Scorecard joins still use `agentProfileHash`; this id is for run ids, matrix\n * keys, and directory names where two profiles must not collapse onto one row.\n * The suffix is the first 64 bits of the behaviour hash, enough for ordinary\n * eval matrices while keeping filenames readable.\n */\nexport function agentProfileId(profile: AgentProfile): string {\n const label = pathSafeProfileLabel(agentProfileDisplayLabel(profile)) ?? 'profile'\n return `${label}-${agentProfileHash(profile).slice(0, 16)}`\n}\n\n/**\n * Model snapshot used for `RunRecord.model`. Eval surfaces require a concrete\n * model id because run records reject bare/missing model aliases.\n */\nexport function agentProfileModelId(profile: AgentProfile): string {\n const model = profile.model?.default?.trim()\n if (!model) {\n const label = agentProfileDisplayLabel(profile) ?? 'unnamed profile'\n throw new ValidationError(\n `AgentProfile \"${label}\" has no model.default — cannot record eval run`,\n )\n }\n return model\n}\n\nfunction agentProfileDisplayLabel(profile: AgentProfile): string | undefined {\n return profile.name?.trim() || profile.version?.trim() || undefined\n}\n\nfunction pathSafeProfileLabel(label: string | undefined): string | undefined {\n const safe = label\n ?.trim()\n .replace(/[^A-Za-z0-9._-]+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n return safe || undefined\n}\n\nfunction compact<T extends Record<string, unknown>>(input: T): Partial<T> {\n const out: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(input)) {\n if (value !== undefined) out[key] = value\n }\n return out as Partial<T>\n}\n\n/**\n * Deterministic behaviour identity for the canonical\n * `@tangle-network/agent-interface` AgentProfile.\n *\n * `name` and `description` are labels and do not affect the hash. Profile\n * `version`, prompt, model hints, tools, resources, hooks, modes, permissions,\n * and extensions do affect the hash. Resource array order is hash-bearing\n * because mount order can change agent behaviour. Undefined fields are treated\n * as absent; explicit `null` fields remain hash-bearing.\n */\nexport function agentProfileHash(profile: AgentProfile): string {\n const model = agentProfileModelId(profile)\n const behaviour = {\n ...profile,\n name: undefined,\n description: undefined,\n tags: profile.tags ? [...profile.tags].sort() : undefined,\n model: compact({ ...profile.model, default: model }),\n }\n return createHash('sha256')\n .update(JSON.stringify(canonicalize(behaviour)))\n .digest('hex')\n}\n"],"mappings":"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","names":[]}