@mutagent/evaluator 0.1.0-alpha.5 → 0.2.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/.claude/skills/mutagent-evaluator/SKILL.md +28 -30
  2. package/.claude/skills/mutagent-evaluator/assets/agents/dataset-builder.md +6 -5
  3. package/.claude/skills/mutagent-evaluator/assets/agents/evaluator.md +93 -30
  4. package/.claude/skills/mutagent-evaluator/assets/code-quality-criteria.yaml +75 -0
  5. package/.claude/skills/mutagent-evaluator/assets/templates/discover-report.template.html +397 -0
  6. package/.claude/skills/mutagent-evaluator/assets/templates/eval-report.template.html +594 -0
  7. package/.claude/skills/mutagent-evaluator/assets/templates/review-report.template.html +560 -0
  8. package/.claude/skills/mutagent-evaluator/golden/judge-trajectory.prose.md +69 -0
  9. package/.claude/skills/mutagent-evaluator/lenses/methodology-critic-lens.md +1 -1
  10. package/.claude/skills/mutagent-evaluator/references/data-registry.md +43 -0
  11. package/.claude/skills/mutagent-evaluator/references/edd-loop.md +6 -6
  12. package/.claude/skills/mutagent-evaluator/references/eval-layers.md +52 -0
  13. package/.claude/skills/mutagent-evaluator/references/eval-stage.md +37 -4
  14. package/.claude/skills/mutagent-evaluator/references/memory-format.md +1 -1
  15. package/.claude/skills/mutagent-evaluator/schemas/methodology-review.schema.yaml +1 -1
  16. package/.claude/skills/mutagent-evaluator/scripts/agent-dispatch.ts +0 -0
  17. package/.claude/skills/mutagent-evaluator/scripts/aggregate-discover.ts +254 -9
  18. package/.claude/skills/mutagent-evaluator/scripts/audience.ts +84 -0
  19. package/.claude/skills/mutagent-evaluator/scripts/build-review-ui.ts +320 -6
  20. package/.claude/skills/mutagent-evaluator/scripts/cli/prep.ts +32 -2
  21. package/.claude/skills/mutagent-evaluator/scripts/cli/profile-subject.ts +1 -1
  22. package/.claude/skills/mutagent-evaluator/scripts/code-eval-library.ts +201 -0
  23. package/.claude/skills/mutagent-evaluator/scripts/code-quality-verdict.ts +60 -68
  24. package/.claude/skills/mutagent-evaluator/scripts/config/schema.ts +3 -3
  25. package/.claude/skills/mutagent-evaluator/scripts/contracts/agentspec-evals.ts +101 -39
  26. package/.claude/skills/mutagent-evaluator/scripts/contracts/eval-matrix.ts +326 -3
  27. package/.claude/skills/mutagent-evaluator/scripts/contracts/eval-types.ts +30 -4
  28. package/.claude/skills/mutagent-evaluator/scripts/determine-outcome.ts +8 -0
  29. package/.claude/skills/mutagent-evaluator/scripts/edd/change-request.ts +1 -1
  30. package/.claude/skills/mutagent-evaluator/scripts/edd/edd-types.ts +2 -2
  31. package/.claude/skills/mutagent-evaluator/scripts/judge-prompt-template.ts +144 -15
  32. package/.claude/skills/mutagent-evaluator/scripts/materialize-dataset.ts +130 -68
  33. package/.claude/skills/mutagent-evaluator/scripts/matrix-judge.ts +219 -1
  34. package/.claude/skills/mutagent-evaluator/scripts/memory/append.ts +1 -1
  35. package/.claude/skills/mutagent-evaluator/scripts/memory/ratify.ts +165 -0
  36. package/.claude/skills/mutagent-evaluator/scripts/merge-criteria.ts +849 -0
  37. package/.claude/skills/mutagent-evaluator/scripts/prep-tasks.ts +15 -4
  38. package/.claude/skills/mutagent-evaluator/scripts/read-manifest.ts +120 -0
  39. package/.claude/skills/mutagent-evaluator/scripts/read-unitf-traces.ts +34 -2
  40. package/.claude/skills/mutagent-evaluator/scripts/render-build-cards.ts +37 -0
  41. package/.claude/skills/mutagent-evaluator/scripts/render-discover-report-v3.ts +1155 -0
  42. package/.claude/skills/mutagent-evaluator/scripts/render-eval-report-v3.ts +610 -0
  43. package/.claude/skills/mutagent-evaluator/scripts/render-eval-report.ts +11 -92
  44. package/.claude/skills/mutagent-evaluator/scripts/render-review-report-v3.ts +691 -0
  45. package/.claude/skills/mutagent-evaluator/scripts/report-fragments.ts +173 -0
  46. package/.claude/skills/mutagent-evaluator/scripts/route-failures.ts +12 -9
  47. package/.claude/skills/mutagent-evaluator/scripts/run-evaluate.ts +46 -1
  48. package/.claude/skills/mutagent-evaluator/scripts/run-pipeline.ts +39 -4
  49. package/.claude/skills/mutagent-evaluator/scripts/run-review.ts +266 -0
  50. package/.claude/skills/mutagent-evaluator/scripts/subject-profile.ts +82 -0
  51. package/.claude/skills/mutagent-evaluator/scripts/sync-eval-criteria.ts +2 -2
  52. package/.claude/skills/mutagent-evaluator/scripts/unitf-to-evaltrace.ts +64 -21
  53. package/.claude/skills/mutagent-evaluator/scripts/verify-render.ts +728 -0
  54. package/bin/mutagent-cli.mjs +9 -5
  55. package/package.json +2 -2
@@ -1,24 +1,19 @@
1
1
  ---
2
2
  name: mutagent-evaluator
3
3
  description: |
4
- Evaluation-development engine for AI agents and skills. Turns a subject (a skill/agent +
5
- its traces) into a TRUSTWORTHY eval suite: deep-reads traces to determine success/failure
6
- (even when nothing is user-marked), mines emergent BINARY ACTIONABLE criteria from the
7
- ✓/✗ split, builds one critique-before-verdict LLM-judge (or code-check) per criterion,
8
- validates each judge against human labels (TPR/TNR · Rogan-Gladen · bootstrap CI), then
9
- runs the suite against a target per-criterion binary+confidence severity-gated GATE
10
- verdict + agent-variance view. A judge is ONLY a judge: failures are flagged and ROUTED to
11
- diagnostics, never fixed here (EV-051). First invocation auto-detects the subject + the
12
- framework-substrate choice (DEFAULT agent-dispatch host-runtime subagents, no provider ·
13
- in-house AI-SDK judge optional · code-based · user's framework export).
14
- Subsequent invocations dispatch the parent session + MASS-PARALLEL evaluator
15
- sub-agents (one cell, discover / judge modes; host runtime, harness-capped) against the subject's traces.
16
- DEFAULT INTENT: any "evaluate this skill/agent" request runs *evaluate — the JUDGE — which is what an
17
- end user wants. *audit is a SEPARATE, explicit-only 4-tab static-auditor (eval-matrix · data-leak ·
18
- variance · methodology) used mainly for complex agents/skills that emit HTML artifacts; it is NEVER the
19
- fallback for a plain evaluate. Pinned judge model + temp=0
20
- for byte-identical reruns (C-PIN). Usable standalone OR borrowed by mutagent-skill-builder's
21
- SIMULATE phase as the SimVerifier.
4
+ The EVALUATE stage of the agentic development lifecycle (ADL ③). Builds and runs
5
+ trustworthy evaluations for AI agents and skills: from a subject's real traces it
6
+ learns what success and failure look like, turns that into binary eval criteria,
7
+ and scores the subject to a clear gate verdict. It only judges failures are
8
+ flagged and routed to mutagent-diagnostics, never fixed here. Pick it whenever the
9
+ ask is to evaluate, judge, score, or build and validate evals for an agent or
10
+ skill: any plain "evaluate this" runs *evaluate one judge per trajectory walks
11
+ the evidence layers (code checks outcome trajectory tool outputs → context),
12
+ criteria binding evidence across all of them; *evaluate-<layer> scopes the same
13
+ pipeline to one layer; *discover mines new criteria, never re-recommending one it
14
+ already has; *audit is a separate, explicit-only static auditor and never the
15
+ fallback for a plain evaluate. Also serves as the verifier inside
16
+ mutagent-skill-builder's SIMULATE.
22
17
  license: Proprietary. LICENSE.txt has complete terms.
23
18
  compatibility: Designed for Claude Code, Codex, Cursor, OpenCode and similar coding-agent runtimes; works with git, gh CLI, jq, curl, and Bun/pnpm/npm runtimes.
24
19
  metadata:
@@ -102,11 +97,12 @@ reason for the rest. NEVER improvise.
102
97
  |---------|------|-------------------|---------|
103
98
  | `*discover-evals` | hybrid | `references/workflows/orchestrator-protocol.md` + `scripts/prep-tasks.ts` + `scripts/determine-outcome.ts` + `scripts/discover-criteria.ts` + `assets/agents/evaluator.md` (`#mode-discover`) | PREP determiner tasks → fan out `evaluator` (`#mode-discover`, mass-parallel) → AGGREGATE ✓/✗ → mine emergent BINARY ACTIONABLE criteria (EV-041/042/052) **+ T6 failure/uncertain DATASET CANDIDATES** (`collectDatasetCandidates`, reuses the derive-dataset selectors → `*build-dataset`). **GA split** — **code:** sample (broken+healthy) · aggregate · `diff-discriminate` · ground-gate · dataset-candidates; **LLM leaf:** determine + 3 detectors + cite refs + typed assumptions (root-not-symptom). |
104
99
  | `*build-evals` | hybrid | `references/workflows/orchestrator-protocol.md` + `scripts/eval-engine.ts` + `scripts/codegen-evals.ts` + `scripts/prep-tasks.ts` + `scripts/build-evals.ts` + `assets/agents/evaluator.md` (`#mode-judge-criterion`) + `scripts/render-build-cards.ts` | **ENGINE-FORK FIRST (ADL F7/F9/F14).** ASKS the eval implementation mode via `chooseEvalEngineOptions(target)` — Path A `native-matrix` (eval-matrix + LLM-judge SUB-AGENTS; SURFACES the Claude-Code + log-sink dependency up front) vs Path B `code-written` (`codegen-evals.ts` emits a portable bun/TS suite — runs WITHOUT Claude Code, F14). Target-conditional: a code framework offers BOTH, a `harness:*` target is native-only. **Path A** then PREPs judge tasks (criterion × trace-slice) → fan out `evaluator` (`#mode-judge-criterion`, mass-parallel) → one binary+confidence judge per criterion (EV-043). **GA split** — **code:** engine-resolve · spec render · `lint-grounding` · `resolve-ref` (BIND) · codegen; **LLM leaf:** judge + VERIFY (cite refs · note assumptions · abstain). Streams progress + a verbose evals entity card (F13/F16/F22). |
105
- | `*evaluate` | hybrid | `references/workflows/orchestrator-protocol.md` + `scripts/matrix-judge.ts` + `scripts/contracts/eval-matrix.ts` + `assets/agents/evaluator.md` (`#mode-judge-trajectory`) + `scripts/evaluate.ts` | **DEFAULT (headline):** **T1 TIER-0 deterministic pre-pass** (code-method rows run first, zero judge tokens) → PREP one matrix packet per RESIDUAL judge trajectory (**T5 adaptive-K guard, default 1:1**) → fan out `evaluator` (`#mode-judge-trajectory` — one judge/trajectory scoring the WHOLE matrix, emitting the **T2 Judge DAG v2 walk** = `judge_steps[]` + dense na-explicit map + confidence band + early-INCOMPLETE + node-2.5 candidates) → AGGREGATE: fold code+judge verdicts → **T3 independent verifier** refutes GATING fails (downgrade-only) → **T4 consolidate-by-locus + walk-derived health** → GATE verdict + variance view (EV-048). **GA split** — **code:** tier-0 · prep · `lint-grounding` · `resolve-ref` · `assemble-scorecard` (gate `fail ▸ incomplete ▸ pass`) · consolidate-by-locus · route-failures; **LLM leaf:** trajectory judge (DAG v2 walk: BIND · GROUND[absence-split] · cite · abstain) + independent VERIFY. **MAY now return `incomplete`** (indeterminate → calibrate). **ADL F20:** the rollup ALSO renders a SCORECARD DASHBOARD wireframe (`renderScorecardDashboard` — per-criterion pass/fail bar + variance + samples), not a flat terminal dump. Under a **Path B** engine, `*evaluate` instead runs the portable `codegen-evals.ts` suite (no Claude Code) and reads back its scorecard JSON from the discoverable sink. |
106
- | `*improve` | hybrid | `references/edd-loop.md` + `scripts/edd/variance-gate.ts` + `scripts/edd/change-request.ts` + `scripts/edd/edd-types.ts` + `schemas/edd-change-request.schema.yaml` + `assets/agents/evaluator.md` (`#mode-improve`) | **ADL IMPROVE / EDD loop (F18+F19).** **F19 VARIANCE-FIRST:** repeat-N (default 5) the SAME cases `evaluateVarianceGate` accuracy is entered ONLY when the variance gate passes (`assertVarianceStableBeforeAccuracy` THROWS otherwise "accuracy over big samples is wasted on a flapping verdict"). **F18 CLOSURE:** still JUDGE-ONLY (EV-051), the evaluator emits a grounded `EddChangeRequest` (failing cases + `ref{obs,path,value}` + remedy target `agentspec`\|`impl`) to the `mutagent-builder ai-engineer` over **SendMessage**, consumes the `ChangeRequestResponse`, and re-evals on `amended`. **Bounded terminator** (`decideEddLoop`, afkloop-legal): `full-green` ▸ DONE \| `max-swings`\|`max-wallclock`\|`no-improvement-streak` STOPPED + convergence delta. **GA split** **code:** variance gate · request/response validate · loop terminator (all PURE, injected wall-clock); **LLM leaf:** localize the flap/fail to its root + author the grounded request + decide remedy target. |
100
+ | `*evaluate` | hybrid | `references/workflows/orchestrator-protocol.md` + `scripts/matrix-judge.ts` + `scripts/contracts/eval-matrix.ts` + `assets/agents/evaluator.md` (`#mode-judge-trajectory`) + `scripts/evaluate.ts` | **DEFAULT (headline):** **T1 TIER-0 deterministic pre-pass** (code-method rows run first, zero judge tokens) → PREP one matrix packet per RESIDUAL judge trajectory (**T5 adaptive-K guard, default 1:1**) → fan out `evaluator` (`#mode-judge-trajectory` — one judge/trajectory scoring the WHOLE matrix, emitting the **T2 Judge DAG v2 walk** = `judge_steps[]` + dense na-explicit map + confidence band + early-INCOMPLETE + node-2.5 candidates) → AGGREGATE: fold code+judge verdicts → **T3 independent verifier** refutes GATING fails (downgrade-only) → **T4 consolidate-by-locus + walk-derived health** → GATE verdict + variance view (EV-048). **GA split** — **code:** tier-0 · prep · `lint-grounding` · `resolve-ref` · `assemble-scorecard` (gate `fail ▸ incomplete ▸ pass`) · consolidate-by-locus · route-failures; **LLM leaf:** trajectory judge (DAG v2 walk: BIND · GROUND[absence-split] · cite · abstain) + independent VERIFY. **MAY now return `incomplete`** (indeterminate → calibrate). **ADL F20:** the rollup ALSO renders a SCORECARD DASHBOARD wireframe (`renderScorecardDashboard` — per-criterion pass/fail bar + variance + samples), not a flat terminal dump. Under a **Path B** engine, `*evaluate` instead runs the portable `codegen-evals.ts` suite (no Claude Code) and reads back its scorecard JSON from the discoverable sink. **v3 LAYERED WALK (D1=B+):** the trajectory judge performs the whole evidence-layer sequence INSIDE its one dispatch — L0 code checks → L1 outcome (scenario + expectedExit, cheap, first) → per stopping rules L2 trajectory → L3 tool outputs → L4 context — emitting `layerVerdicts[]` + `earlyExit` + `codeEvalHits[]` + an emissions self-manifest (E-NEW contract, `contracts/eval-matrix.ts`); AGGREGATE folds layers (`foldLayerVerdicts`), DETECTS cross-layer conflicts (`detectLayerConflicts` — surfaced for the human calibration queue, NEVER auto-resolved, D2-A/OT-1), enforces the COMPLETENESS LAW (`assertNoUnverdictedCriterion` THROWS on a silent skip), and folds MR-5 data-completeness (`foldEmissionsScorecard`). |
101
+ | `*evaluate-outcome` · `*evaluate-trajectory` · `*evaluate-outputs` · `*evaluate-context` · `*evaluate-code` · `*evaluate-criteria` | hybrid | the SAME binds as `*evaluate` | **v3 PIPEABLE LAYER FILTERS (D3=A):** each runs the identical `*evaluate` pipeline with `layerScope` set in every packet (`outcome`→`[L1]` · `trajectory`→`[L2]` · `outputs`→`[L3]` · `context`→`[L4]` · `code`→`[L0]`); the judge runs ONLY those walk phases **criteria are the SUPER-LAYER and are still verdicted over whatever those phases gather (never left unverdicted the completeness law holds per scope)**. `*evaluate-criteria` = the criterion-axis pass (`#mode-judge-criterion`, single criterion × slicethe suite-build/validation path). Standalone-testable AND composable: a standalone layer verdict must equal the same layer's verdict inside the full walk (V9). |
102
+ | `*optimize` | hybrid | `references/edd-loop.md` + `scripts/edd/variance-gate.ts` + `scripts/edd/change-request.ts` + `scripts/edd/edd-types.ts` + `schemas/edd-change-request.schema.yaml` + `assets/agents/evaluator.md` (`#mode-optimize`) | **ADL ③ OPTIMIZE / EDD loop (F18+F19).** **F19 VARIANCE-FIRST:** repeat-N (default 5) the SAME cases → `evaluateVarianceGate` → accuracy is entered ONLY when the variance gate passes (`assertVarianceStableBeforeAccuracy` THROWS otherwise — "accuracy over big samples is wasted on a flapping verdict"). **F18 CLOSURE:** still JUDGE-ONLY (EV-051), the evaluator emits a grounded `EddChangeRequest` (failing cases + `ref{obs,path,value}` + remedy target `agentspec`\|`impl`) to the `mutagent-builder ai-engineer` over **SendMessage**, consumes the `ChangeRequestResponse`, and re-evals on `amended`. **Bounded terminator** (`decideEddLoop`, afkloop-legal): `full-green` ▸ DONE \| `max-swings`\|`max-wallclock`\|`no-improvement-streak` ▸ STOPPED + convergence delta. **GA split** — **code:** variance gate · request/response validate · loop terminator (all PURE, injected wall-clock); **LLM leaf:** localize the flap/fail to its root + author the grounded request + decide remedy target. |
107
103
  | `*validate` | hybrid | `scripts/validate-judge.ts` + `references/validate-evaluator.md` + `assets/agents/evaluator.md` (`#mode-judge-criterion`) | **ENGINED (EV-044)** — calibrate a judge vs `*review` labels: confusion matrix → TPR/TNR · split-disjointness + test-once · Rogan-Gladen θ · deterministic bootstrap CI; `<MIN_LABELS` stays `unvalidated`+bias-corrected. **GA split** — **code:** entire path is deterministic (filter EXCLUDES indeterminate · confusion · RG · assumption-agreement). |
108
- | `*review` | hybrid | `scripts/build-review-ui.ts` + `references/build-review-interface.md` | **ENGINED (EV-045)** — CODE renders a browser annotation UI (one trace/screen · Pass/Fail/Defer · keyboard · auto-save · labels export); **HITL**: a human labels `mergeLabels` persists feeds `*validate`. |
109
- | `*eval` | agent-chain | `references/eval-stage.md` + `scripts/eval-engine.ts` + `scripts/materialize-dataset.ts` + `scripts/render-build-cards.ts` | **THE ADL EVAL-STAGE ENTRY (F15).** Called after `*build` hands a freshly-built agent + its agentspec. INTERACTIVELY offers `*build-dataset` / `*build-evals` derived from `agentspec.definition.evals`, and lets the user PICK THE EVAL ENGINE (mutagent native eval-matrix [Path A] vs code-written-in-target-lang [Path B]) via the target-conditional menu (`chooseEvalEngineOptions`). Surfaces Path A's Claude-Code + log-sink dependency UP FRONT (F7/F9). Streams wireframe progress + entity cards (F13/F16/F22). Parent-session only (AskUserQuestion). |
104
+ | `*review` | hybrid | `scripts/run-review.ts` (run composer) + `scripts/render-review-report-v3.ts` (surface) + `scripts/build-review-ui.ts` (v2 fallback) + `references/build-review-interface.md` | **ENGINED (EV-045)** — CODE renders a browser review surface; **HITL**: a human labels → `mergeLabels` persists → feeds `*validate`. **Entry point:** `bun scripts/run-review.ts <runId> [--cwd <repoRoot>]` — reads an EXISTING `*evaluate` run dir (`run-input.full.json` + `verdicts/*.verdict.json`; joins on the parsed `trajectoryId`, never the packet filename) and writes `review-report.html` beside `evaluation-report.html`, plus `review-report.v2.html` from the previous annotation UI (module untouched). Dispatches NO judge — it costs nothing and invents no artifacts. **Surface:** navigator matrix (criteria rows × trace columns) → single-trace drill, right-rail verdict cards with Agree/Revise/Refute + why-note, keys `1`/`2`/`D`, >48 traces → window-cluster, submit **calibration handoff markdown** (diagnostics remedy-bundle shape) server-generated from the run's own artifacts. Ingested-but-unjudged trajectories are NAMED in a scope note, never dropped. **Does NOT do W4:** no feedback store, no ruling persistence, no propagation into `*validate` — producing the artifact is the scope; consuming a reviewer's answer is task #9. |
105
+ | `*eval` | agent-chain | `references/eval-stage.md` + `scripts/eval-engine.ts` + `scripts/materialize-dataset.ts` + `scripts/render-build-cards.ts` | **THE ADL EVAL-STAGE ENTRY (F15).** Called after `*build` hands a freshly-built agent + its agentspec. INTERACTIVELY offers `*build-dataset` / `*build-evals` derived from `agentspec.spec.evaluation`, and lets the user PICK THE EVAL ENGINE (mutagent native eval-matrix [Path A] vs code-written-in-target-lang [Path B]) via the target-conditional menu (`chooseEvalEngineOptions`). Surfaces Path A's Claude-Code + log-sink dependency UP FRONT (F7/F9). Streams wireframe progress + entity cards (F13/F16/F22). Parent-session only (AskUserQuestion). |
110
106
  | `*build-dataset` | hybrid | `scripts/materialize-dataset.ts` + `scripts/build-dataset.ts` + `assets/agents/dataset-builder.md` + `schemas/dataset.schema.yaml` + `references/generate-synthetic-data.md` + `scripts/render-build-cards.ts` | **ENGINED (EV-046) + ADL F8.** Now MATERIALIZES real items first: `materializeFromAgentspec` seeds ≥1 REAL DatasetCase per `dataset_category` + one per `edge_case` (seed → actual items, not definitions) → then the 3-way: HITL seed interview (~10) → `dataset-builder` agent (tuples → NL queries → realism filter) → CODE cartesian-expand + near-dup drop + monotonic merge. Streams wireframe progress cards (F13/F16) + a verbose dataset entity card (F22). |
111
107
  | `*discover-dataset` | script | `scripts/derive-dataset.ts` | **ENGINED (EV-047) · re-fronts the old `*derive-dataset`** — distill a living regression set from labeled ✓/✗ traces (reuses `sample-traces.ts` EV-052 selectors + `build-dataset.ts` merge). Code-only. **P-B:** consumes the `discovery` agent's curated `SelectionManifest` handoff — **scenario-balanced** (`ext.classification.scenario`), **edge-cases first** (`ext.classification.edgeCase.is`), worthiness-prioritized (`ext.signals.worthinessScore`). |
112
108
  | `*audit` | agent-chain | `assets/agents/audit-executor.md` + `workflows/{audit,data-leak,variance}.workflow.js` + `scripts/{flow-graph,ui-slots}.ts` + `lenses/context-flow-lens.md` | SURFACES the v1 4-tab static-auditor (EV-001..027, KEEP) **+ now the agent context-flow audit**: tool-result threading + sub-agent handoff completeness (EV-028/029, over the `flow-graph` EV-032 + expected-flow EV-037) and the first-class **HTML-artifact missing-data** dimension (computed-but-not-rendered / orphan / faithfulness, EV-039/040, subject-agnostic). |
@@ -138,7 +134,7 @@ When you encounter a *<name> token:
138
134
  Invoke me with:
139
135
  - `evaluate skill <name>` / `evaluate agent <name>` / `/mutagent-evaluator` → **`*evaluate`** (default)
140
136
  - `*discover-evals` (mine criteria) · `build evals for <x>` · `validate judge <x>` · `*audit <subject>` (explicit only)
141
- - `*improve` (the ADL ③ EDD loop — variance-first then request-amend-reeval to full green, bounded)
137
+ - `*optimize` (the ADL ③ EDD loop — variance-first then request-amend-reeval to full green, bounded)
142
138
  - `*self-audit` (the eval-of-the-eval — audit my OWN eval-dev; on-demand only)
143
139
  - borrowed by `mutagent-skill-builder` SIMULATE (SimVerifier role)
144
140
  - `--reconfigure` to re-enter onboarding (subject + substrate)
@@ -151,7 +147,7 @@ Minimal eval-dev spine (build order — do NOT reorder):
151
147
  *discover-evals → deep-read traces, determine ✓/✗, mine 5-10 binary actionable criteria
152
148
  *build-evals → one critique-before-verdict judge (or code-check) per criterion
153
149
  *evaluate → run vs target → per-criterion binary+confidence → GATE verdict + variance
154
- *improve → ADL ③ EDD loop: F19 variance-first (stabilize per-case spread, repeat-N)
150
+ *optimize → ADL ③ EDD loop: F19 variance-first (stabilize per-case spread, repeat-N)
155
151
  BEFORE accuracy, then F18 closure (judge-only REQUESTS the ai-engineer to
156
152
  amend agentspec|impl over SendMessage → re-eval) → full green OR bounded STOP
157
153
  ```
@@ -159,13 +155,13 @@ Minimal eval-dev spine (build order — do NOT reorder):
159
155
  `*validate` (calibrate the judge) layers on top. `*audit` (the v1 4-tab master-audit) is an
160
156
  **explicit-only** specialized surface (complex / HTML-artifact subjects) — NOT part of the default
161
157
  evaluate spine and never an automatic fallback.
162
- `*improve` is the IMPROVE stage — it runs AFTER an initial `*build` + `*evaluate` and is **bounded**
158
+ `*optimize` is the OPTIMIZE stage — it runs AFTER an initial `*build` + `*evaluate` and is **bounded**
163
159
  (never infinite): full-green ⇒ DONE; else max-swings / max-wallclock / no-improvement ⇒ STOP + delta.
164
160
 
165
161
  **ADL EVAL-stage entry (`*eval`).** When `*build` hands over a freshly-built agent +
166
162
  its agentspec, `*eval` is the entry: it interactively offers `*build-dataset` /
167
- `*build-evals` derived from `agentspec.definition.evals` (F15), MATERIALIZES real
168
- dataset items per category + edge-case (F8), lets the user PICK THE EVAL ENGINE
163
+ `*build-evals` derived from `agentspec.spec.evaluation` (F15), MATERIALIZES real
164
+ dataset cases by projecting the 0.3.0 `datasets[].items[]` (F8), lets the user PICK THE EVAL ENGINE
169
165
  (Path A native eval-matrix vs Path B code-written — surfacing Path A's Claude-Code +
170
166
  log-sink dependency up front, F7/F9/F14), streams wireframe progress + entity cards
171
167
  (F13/F16/F22), and renders the scorecard as a dashboard (F20). See
@@ -276,7 +272,7 @@ applies, EV-053/EQ5):
276
272
  | `scripts/aggregate-discover.ts` | P2 (§5a) + §9.4 (T6) | code | The real `*discover-evals` AGGREGATE half: parse the leaf's per-trace verdict files + per-batch mining report → `TraceAnnotation[]` (FAIL-LOUD via `missingVerdictKeys`; THROW on an undispatched-trace category ref) → `deriveMinedCriteria` (§5b metadata + §5c DR-2) → `growLivingSuite` (append-only, monotonic, saturation-stop). **T6:** `collectDatasetCandidates` (failure/uncertain → `DatasetCase[]` via the derive-dataset selectors) + `unmatchedDetectionCandidates` (the `*evaluate` judge's node-2.5 handoff) → consumable by `*build-dataset`. `DiscoverMiningReport` contract. No hand-rolled annotations. |
277
273
  | `scripts/code-eval.ts` | P3 (EX-2) | code | The v2 CODE-track primitive library — generic PURE `(trace) → {result, detail}` checks: presence · string-equality · format-validity · schema-conformance · ref-integrity (cross-stage). SV-1 dotted-path read incl. `obs:<name>.<path>`. Exhaustive `runCodeEval` (unknown primitive → THROW). NO LLM, byte-identical. Disjoint from the v1 `run-deterministic.ts` audit world. |
278
274
  | `scripts/check-method-router.ts` | P3 (EX-2) | hybrid | THE load-bearing §5b `check_method` router: `deterministic`→CODE-EXEC (judge NEVER called) · `llm-judge`→JUDGE seam · `hybrid`→code pre-filter that GATES the judge. Unknown → THROW (exhaustive). `RoutedCriterionVerdict` = `CriterionVerdict` + provenance `{producedBy, codeResult, judgeReached}` (structural superset → `evaluate.ts` rollup unchanged). `extractCodeEval(registry)` fail-loud (a code-class criterion with no spec THROWS — never silently judge). "Code before judge" lives INSIDE the agent. |
279
- | `scripts/code-quality-verdict.ts` | W2I1 (⑤ IMPROVE) | hybrid | The **code-quality JUDGE mode** (`#mode-judge-code-quality`) — the (b) half of the ⑤ IMPROVE code-target BOTH-gate. Scores a `code` subject's QUALITY (spec-faithfulness · addresses-diagnosis · no-regression · error-handling · maintainability) BEYOND tests-green → severity-gated binary PASS/FAIL. `buildCodeQualityPrompt` (pure renderer, critique-before-verdict) + `codeQualityGatePass` (pure aggregate) + `runCodeQualityJudge` (C-PIN run wrapper on the injected JudgeInvoke seam). Judge-only (EV-051), host-runtime, pinned model + temp 0. **DISTINCT from `code-eval.ts`** (deterministic primitives — no LLM). `DEFAULT_CODE_QUALITY_CRITERIA` + its aggregation rule are FLAGGED-for-operator-sign-off. |
275
+ | `scripts/code-quality-verdict.ts` | W2I1 (⑤ OPTIMIZE) | hybrid | The **code-quality JUDGE mode** (`#mode-judge-code-quality`) — the (b) half of the ⑤ OPTIMIZE code-target BOTH-gate. Scores a `code` subject's QUALITY (spec-faithfulness · addresses-diagnosis · no-regression · error-handling · maintainability) BEYOND tests-green → severity-gated binary PASS/FAIL. `buildCodeQualityPrompt` (pure renderer, critique-before-verdict) + `codeQualityGatePass` (pure aggregate) + `runCodeQualityJudge` (C-PIN run wrapper on the injected JudgeInvoke seam). Judge-only (EV-051), host-runtime, pinned model + temp 0. **DISTINCT from `code-eval.ts`** (deterministic primitives — no LLM). `DEFAULT_CODE_QUALITY_CRITERIA` + its aggregation rule are FLAGGED-for-operator-sign-off. |
280
276
  | `scripts/run-evaluate.ts` | P5 + §9.4 (T1·T3·T4·T5) | hybrid | The real-engine `*evaluate` end-to-end COMPOSER: `tier0Plan` (T1 — code rows decided in the pre-pass, residual judge rows only in packets) → `prepMatrixPackets` (residual-only) → `adaptivePacketPlan` (T5 overload guard, default 1:1) → [dispatch #mode-judge-trajectory] → `aggregateEvaluate` (FAIL-LOUD readiness gate over DISPATCHED ids → `aggregateMatrixScorecard` folding code+judge + T3 `independentVerify` downgrade-only on gating fails → GATE + variance → T4 `consolidateByLocus` lociClusters → EV-051 `routeFailures`→validated HandoverBundle). `maskedScorecard` = the C-PIN byte-identity artifact. |
281
277
  | `scripts/render-eval-report.ts` | P4 (D-1/2/3) | code | The v2 reporting (v1 `render-report.ts` untouched): `renderEvalCards` (D-1 terminal per-criterion cards) + `buildEvalReportInput` (derives the rich tabs from real run data — ledger · coverage · cohorts · gating rolls · top-findings · judge-health) + `renderEvalReport` (the operator-APPROVED 5 tabs: ① Overview KPIs+coverage+gating-table+top-findings · ② Trajectory‖Judge ledger + click-row Target-Agent‖Judge side-by-side · ③ Eval Scorecard cohort heatmap + nested subcards + inline calibration · ④ Findings verbatim-evidence + judge chain + agree/revise/refute · ⑤ Self-Eval [INTERNAL, strip-marked]). Consumes the §9.4 judge-walk (`judge_steps[]` + dense map) when present, degrades to the per-trajectory scorecard otherwise. Tabs are `<button>` (no `<s>` strikethrough). Unified design-system tokens (`assets/brand/theme.css`). byte-identical after the `generatedAt` mask. `autoOpenCommand` cross-platform helper (orchestrator fires it). |
282
278
  | `scripts/contracts/eval-types.ts` *(extended)* | P2/P2b | code | + `MinedCriterion` (additive subtype of `DiscoveredCriterion`) carrying the §5b `MetricMetadata` (generality·dimension·level·check_method [3-value SF-2 router]·substrate·applies_to·severity·judge_inputs·flag) + the §5c `DiscoveryRationale` (DR-2: targets·why·evidence{grounding observed\|inferred·prevalence k/n·refs}·assumptions·expected_impact). `parseMinedCriterion` enforces the evidence-first gate (OBSERVED ⇒ refs + k>0). |
@@ -287,7 +283,7 @@ applies, EV-053/EQ5):
287
283
  |--------|---------|------|---------|
288
284
  | `scripts/contracts/eval-engine.ts` | F7/F9/F14 | code | The ENGINE FORK contract — `EvalEngine` (`native-matrix` Path A · `code-written` Path B) + `EngineTargetInput` (the minimal agentspec.build slice) + `EvalEngineOption` (the menu, with `requiresClaudeCode`/`requiresLogSink`/`portable` SURFACED) + `EvalEnginePlan` (the resolved choice incl. discoverable `outputSink`). |
289
285
  | `scripts/eval-engine.ts` | F7/F9/F14 | code | The target-conditional resolver — `isFrameworkTarget` · `chooseEvalEngineOptions` (framework→BOTH · harness→native-only) · `resolveEvalEngine` (surfaces CC + log-sink deps) · `assertEngineMatchesTarget` (code-written⊥harness, fail-loud) · `defaultOutputSink`. PURE. |
290
- | `scripts/contracts/agentspec-evals.ts` | F8 | code | The MINIMAL `agentspec.definition.evals` slice (`success_criteria[]` · `scenarios[]` · `dataset_categories[]`) — local re-declaration (standalone: NEVER imports the agentspec skill). `parseAgentspecEvals` guarded. |
286
+ | `scripts/contracts/agentspec-evals.ts` | F8 | code | The MINIMAL `agentspec.spec.evaluation` slice (0.3.0 D18/D19 — `criteria[]` · `scenarios[]` · `datasets[]` with dataset-local `categories[]` + `caseDimensions` + real `items[]`) — local re-declaration (standalone: NEVER imports the agentspec skill). `parseSpecEvaluation` guarded. |
291
287
  | `scripts/materialize-dataset.ts` | F8 | code | MATERIALIZE real dataset items from the agentspec — `materializeFromAgentspec` (≥1 real item/category + one/edge_case, seed→actual) · `dimensionsFromAgentspec` · `materializeToDataset` (monotonic). Reuses `build-dataset.ts` ids/dedup/merge. PURE. |
292
288
  | `scripts/codegen-evals.ts` | F14 (Path B) | code | Emit a PORTABLE code-written eval suite source (bun/TS) — `codegenEvalSuite` (code-checks + SDK judge + criteria → gate-bearing scorecard to a discoverable sink). NO CC dispatch. Fail-loud, deterministic. PURE. |
293
289
  | `scripts/render-build-cards.ts` | F13/F16/F20/F22 | code | The wireframe terminal surface — progress cards (`renderBuildDatasetProgressCard`/`renderBuildEvalsProgressCard`, F13/F16) · entity cards (`renderDatasetEntityCard`/`renderEvalsEntityCard`, F22) · the scorecard DASHBOARD (`renderScorecardDashboard` — pass/fail bar + variance + samples, F20, not a flat dump). PURE. |
@@ -296,7 +292,9 @@ applies, EV-053/EQ5):
296
292
 
297
293
  | Script | Req | Kind | Purpose |
298
294
  |--------|-----|------|---------|
299
- | `scripts/build-review-ui.ts` | EV-045 | code | The `*review` Code half — `renderReviewUi` emits a DETERMINISTIC browser annotation UI (one trace/screen, native render, Pass/Fail/Defer, notes, keyboard, localStorage auto-save, labels export) + `mergeLabels` (dedup by traceId). Holds no judge prompt; the HUMAN decides. |
295
+ | `scripts/build-review-ui.ts` | EV-045 | code | The `*review` Code half — `renderReviewUi` emits a DETERMINISTIC browser annotation UI (one trace/screen, native render, Pass/Fail/Defer, notes, keyboard, localStorage auto-save, labels export) + `mergeLabels` (dedup by traceId). Holds no judge prompt; the HUMAN decides. Retained as the `review-report.v2.html` transition fallback under the W4 surface. |
296
+ | `scripts/run-review.ts` | EV-045 | code | **The `*review` RUN COMPOSER** — the analogue of run-evaluate's `writeRunReport`. Reads an existing run dir (run-input + `verdicts/*.verdict.json`, excluding the `*.verify.json` ledger) and writes `review-report.html` + the v2 fallback. Joins verdicts to traces on the parsed `trajectoryId`, NOT the packet filename; treats the lean run-input's `"<N EvalTraces>"` placeholder as ABSENT rather than data; NAMES ingested-but-unjudged trajectories in a scope note. Fail-loud on a missing run dir / run-input / verdicts / criteria, and a malformed verdict names its FILE. Dispatches no judge. |
297
+ | `scripts/render-review-report-v3.ts` | EV-045 | code | The W4 frozen-contract review surface (navigator + drill · rail verdict cards · rulings · calibration handoff MD) + `REVIEW_REPORT_SPEC`, the surface's verification spec, exported here so the unit test and the composer assert the same shape. |
300
298
  | `scripts/build-dataset.ts` | EV-046 | code | The `*build-dataset` Code half — cartesian dimension×value expand · deterministic token-Jaccard near-dup removal · content-derived id · `mergeCases` MONOTONIC merge. Agent proposes realism; script enforces non-redundancy. |
301
299
  | `scripts/derive-dataset.ts` | EV-047 | code | `*discover-dataset` — distill a living regression set from past ✓/✗ (reuses `sample-traces.ts` selectors + `build-dataset.ts` merge); trace→`DatasetCase`. Append-only, no new decision. |
302
300
  | `scripts/living-suite.ts` | EV-053 | code | Generic append-only writer (`appendOnly` + `assertMonotonicGrowth`) shared by datasets + criteria — a living artifact NEVER shrinks. Pure-counter provenance (no clock → C-PIN byte-identity). |
@@ -131,11 +131,12 @@ not run the subject and does not decide pass/fail.
131
131
  1. **Pre-read** `references/generate-synthetic-data.md` — the dimension → tuple → query → filter
132
132
  process is the lens. Read the passed `dimensions` + `seed_tuples`.
133
133
  - **ADL F8 — agentspec-materialized seeds.** In the ADL EVAL stage the parent ALSO PREPs real
134
- items MATERIALIZED from `agentspec.definition.evals` (`scripts/materialize-dataset.ts`): ≥1 real
135
- `DatasetCase` per `dataset_category` + one per `edge_case`. When present, treat these
136
- materialized cases as ADDITIONAL realism anchors (alongside the HITL `seed_tuples`) they are
137
- real queries from the spec, NOT definitions. EXPAND around them; do not re-derive them. The
138
- deterministic dedup/merge (`build-dataset.ts`) drops any overlap.
134
+ items PROJECTED from `agentspec.spec.evaluation` (0.3.0, `scripts/materialize-dataset.ts`): one
135
+ real `DatasetCase` per `datasets[].items[]` entry tuple = the item's `category` + `case` axis
136
+ assignment, query = the item's opaque `input` payload. When present, treat these materialized
137
+ cases as ADDITIONAL realism anchors (alongside the HITL `seed_tuples`) they are real queries
138
+ from the spec, NOT definitions. EXPAND around them; do not re-derive them. The deterministic
139
+ dedup/merge (`build-dataset.ts`) drops any overlap.
139
140
  2. **Generate more tuples (Step 3).** Produce `target_count` new `(dim1, dim2, dim3, …)` combinations
140
141
  for the subject. Avoid duplicates of the seed + each other; vary values across dimensions. This is
141
142
  ONE step — tuples only, no queries yet.
@@ -20,9 +20,9 @@ ACTIVATION-NOTICE: This file contains your full agent operating guidelines. Read
20
20
  class: pure_subagent_executor
21
21
  isolation: none
22
22
 
23
- modes: [discover, judge, verify, improve] # discover · judge · verify (GA-5) · improve (EDD ③ — F18/F19)
23
+ modes: [discover, judge, verify, optimize] # discover · judge · verify (GA-5) · optimize (EDD ③ — F18/F19)
24
24
  judge_axes: [trajectory, criterion] # judge-mode fan-out axes
25
- # `improve` is the ADL ③ IMPROVE / Eval-Driven-Development (EDD) LOOP mode (F18+F19). It is a MODE of
25
+ # `optimize` is the ADL ③ OPTIMIZE / Eval-Driven-Development (EDD) LOOP mode (F18+F19). It is a MODE of
26
26
  # this ONE agent (the roster stays 3) — it drives the variance-first gate (F19) then, while still
27
27
  # JUDGE-ONLY (EV-051), REQUESTS the mutagent-builder ai-engineer to amend the Agent/AgentSpec (F18) over
28
28
  # SendMessage and re-evals, bounded by an afkloop-legal terminator. It NEVER fixes the subject itself.
@@ -224,11 +224,15 @@ optional_verdict_fields:
224
224
  # structured refs + typed assumptions). A LIGHTWEIGHT / FLATTENED emit that drops discovery.evidence.refs
225
225
  # or discovery.assumptions is a DEFECT — the gate (lint-grounding) + diff-discriminate operate on those
226
226
  # fields; stripping them silently downgrades every criterion to inferred.
227
- required_label_fields: [traceId, verdict, rootCause, refs, evidencePointer] # discover — `rootCause` REPLACES firstThingWrong (root-not-symptom); `refs` = structured grounding
227
+ required_label_fields: [traceId, verdict, firstThingWrong, evidencePointer, refs] # discover — the EXACT keys DiscoverLabelSchema accepts (closed object); `firstThingWrong` HOLDS THE ROOT, not the first visible symptom (root_not_symptom); `refs` = structured grounding
228
228
  required_category_fields: [name, definition, class, fixOrEval, exampleTraceIds] # discover
229
229
  # optional_category_fields (P2/P2b, ADDITIVE — the leaf MAY emit these §5b metric-metadata
230
- # PROPOSALS; AGGREGATE (scripts/aggregate-discover.ts) applies GENERIC defaults when absent,
231
- # so emitting them is OPTIONAL and backward-compatible): [dimension, level, generality, severity, judgeInputs, codeEval]
230
+ # PROPOSALS; AGGREGATE (scripts/aggregate-discover.ts) HONORS what is present and applies GENERIC
231
+ # defaults ONLY where absent, so emitting them is OPTIONAL and backward-compatible):
232
+ # [dimension, level, generality, severity, judgeInputs, codeEval]
233
+ # Each is a CLOSED union (below) — a value outside it fails LOUD at parse time rather than being
234
+ # silently ignored. (Until the P2 passthrough fix the JOIN dropped all four, so the defaults applied
235
+ # unconditionally and every mined criterion read `level: output` no matter what the leaf proposed.)
232
236
  # dimension ∈ operation-correctness | data-correctness | operational-deviation
233
237
  # level ∈ context | output | cross-stage
234
238
  # generality ∈ general-structural | specific-semantic (else derived from class: code→general-structural)
@@ -310,6 +314,7 @@ commands:
310
314
  - "references/grounded-adjudication.md" # GA doctrine: bind · gather refs · typed assumptions · abstain
311
315
  - "subjects/<name>/" # the auto-generated subject profile / event taxonomy
312
316
  - "references/workflows/orchestrator-protocol.md" # Step 1 dispatch FSM
317
+ - "<run_dir>/existing-criteria.json" # SUITE-AWARENESS — the criteria that ALREADY exist (see suite_awareness)
313
318
  workflow:
314
319
  - "Pre-read references/error-analysis.md + references/grounded-adjudication.md + the subjects/<name>/ profile + your assigned <key>.task.json determiner specs"
315
320
  - "Determine outcome per trace (EV-042) — event→intended goal, trajectory→what happened, terminal→verdict; a guard-hold is a PASS"
@@ -319,14 +324,35 @@ commands:
319
324
  - "Trace each Fail to its ROOT (root-not-symptom): one criterion per root; multiple INDEPENDENT roots ⇒ multiple criteria; a causal edge must be GROUNDED (cite it) or surfaced as a typed assumption; deep recursive-why → route to diagnostics"
320
325
  - "Surface TYPED assumptions (factual-intent · normative · scope) for any premise the trace did not establish"
321
326
  - "Cluster notes into 5-10 emergent categories; tag class (objective→code/subjective→judge/hybrid) + fixOrEval"
327
+ - "NAME each cluster suite-aware (AFTER clustering, never before — see suite_awareness): if an EXISTING criterion in existing-criteria.json already states this behaviour, REUSE its exact id as the category name and attach your traces as REINFORCING evidence instead of minting a restatement under a new name"
328
+ - "Emit the §5b PROPOSALS you actually judged — level · severity · dimension · generality. AGGREGATE now HONORS them (they are no longer silently replaced by generic defaults), so an omitted field means 'derive it', not 'it does not matter'"
322
329
  - "Flag fixable-vs-eval-worthy (EV-051) — route fixable + infra-class to diagnostics; keep behavioral criteria"
323
330
  - "Write <key>.verdict.json (critique-before-verdict) + discover/<batch_id>.json (labels + FULL MinedCriterion per category, incl. discovery.evidence.refs + discovery.assumptions)"
331
+ # suite_awareness — the leaf SEES the criteria that already exist, so a behaviour
332
+ # already covered gains EVIDENCE instead of a second name for the same check.
333
+ # The parent writes `existing-criteria.json` (scripts/aggregate-discover.ts
334
+ # writeExistingSuiteBrief) into the run dir before dispatch: {id, statement,
335
+ # severity, level, checkedBy} per existing criterion — NO evidence, deliberately —
336
+ # PLUS `openQuestions[]`: pairs already awaiting a ruling on whether they are one
337
+ # check, each with the guard reason. Those carry only the pair + reason; both
338
+ # sides' statements are already in `criteria[]`, which is what keeps the whole
339
+ # brief evidence-free by construction.
340
+ suite_awareness:
341
+ - "WHEN: consult it AFTER you have clustered, to NAME a cluster. NEVER before."
342
+ - "WHY THAT ORDER IS LOAD-BEARING: reading the existing suite BEFORE the traces would seed a pre-defined failure list and re-introduce exactly the confirmation bias `emergent_categories_only` forbids — you would go hunting for the criteria you were shown. Clustering FIRST keeps the categories emergent; the suite is consulted only to decide what an already-emerged cluster should be CALLED. Emergence is preserved because the brief cannot influence what you found, only what you name it."
343
+ - "IT CARRIES NO EVIDENCE ON PURPOSE: the brief ships statements, not the traces or refs behind them, so it cannot tempt you into re-citing a failure you did not read this batch."
344
+ - "REINFORCE: if an existing criterion already states the behaviour your cluster found, emit the cluster under THAT criterion's exact id. Seeing the behaviour again is legitimate REINFORCING evidence — the parent unions your traces onto the existing criterion and the report marks it REINFORCED."
345
+ - "OPEN QUESTIONS: the brief's `openQuestions[]` lists pairs of EXISTING criteria already awaiting a human ruling on whether they are one check, each with the reason they were kept apart (e.g. `marker parity: [BEFORE] vs [AFTER]`). BOTH sides are live criteria and both statements are in `criteria[]`. If your cluster matches one side, emit it under THAT side's id — do NOT mint a third name for a behaviour that is already an open question, and do NOT try to settle the question yourself (you are not the ruling authority; that is the calibration loop's). If your cluster genuinely matches NEITHER side, mint it as new."
346
+ - "INFORMS, NEVER BLOCKS: a full-looking suite is not a reason to suppress a real finding. If the traces show a behaviour no existing criterion states, MINT IT — a genuinely new criterion is always correct, and the parent's deterministic merge is the safety net for a restatement you mint anyway."
347
+ - "NEVER FABRICATE: do not carry an existing criterion into your mining report because it is in the brief. You may only emit clusters backed by traces YOU actually read this batch — an id reused with no trace of your own behind it is an invented finding."
348
+ - "ABSENT/EMPTY brief ⇒ proceed exactly as before (a first run has no suite; that is normal, not a gap)."
324
349
  compresses:
325
350
  - "deep-read trace → goal-attainment Pass/Fail"
326
351
  - "DETECT across 3 lenses (drift · tool-output-failure · missing-context)"
327
352
  - "GATHER structured refs (claim + absence) · BIND criterion terms"
328
353
  - "root-not-symptom localization + typed-assumption surfacing"
329
354
  - "emergent category clustering"
355
+ - "suite-aware NAMING (reuse an existing id ⇒ REINFORCE, never restate)"
330
356
  - "fixable-vs-eval-worthy flag"
331
357
  - "emit FULL-MinedCriterion verdict + mining files"
332
358
  preserves: "the error-analyst discipline — folded INLINE as 'Mode: discover' (below); the standalone assets/agents/error-analyst.md was RETIRED in the 5→3 consolidation (Phase 3a, df6a6e8c8). This file is its canonical home."
@@ -403,13 +429,15 @@ commands:
403
429
  - "Pre-read references/write-judge-prompt.md (the 4-component judging contract — your lens) + references/grounded-adjudication.md"
404
430
  - "Read your assigned <trajectory_key>.packet.json (MatrixPacket: subject · trajectoryId · WHOLE matrix · trajectory · transcript · pinned envelope) — judge exactly this, never re-derive the data"
405
431
  - "Frame the trajectory in its ROUTE/intended-outcome (CONTEXT) before scoring"
406
- - "Score EVERY criterion in the matrix for THIS trajectory: read only what the row needs (judgeInputs); compare against statement + passCondition"
432
+ - "v3 LAYERED WALK (D1=B+, operator-frozen): the walk IS a fixed layer sequence you run INSIDE this one dispatch. Honor `packet.layerScope` when present (absent/empty = FULL walk). The phases: (L0 code checks) if the code-eval library is present at scripts/code-eval-library.ts, RUN it yourself via Bash over the packet's trajectory JSON and record each hit as codeEvalHits[{pattern,anchor,detail}] — a fired pattern is evidence, not a verdict; (L1 outcome) classify the SCENARIO from the inbound intent + tool inventory, derive its expectedExit[] terminal actions, glance ONLY at end-state evidence and emit layerVerdicts[{layer:'L1',verdict,scenario,expectedExit,refs,note}]; (STOPPING RULES) if L1 passes AND every criterion is answerable from evidence gathered so far → you may set earlyExit:'L1' and mark L2-L4 as {verdict:'skipped'} — but a criterion may NEVER go unverdicted because the agent did the right thing; if ANY criterion is unanswerable OR L1 fails/undecidable → descend; (L2 trajectory) actual-vs-expected decision path, read from the END, emit layerVerdicts L2 (+ divergence in localize); (L3 tool outputs) per-observation structural validity + completeness — external-data correctness is UNVERIFIABLE (fence), a failed tool makes everything downstream suspect; emit layerVerdicts L3 (+firstProblemOrigin); (L4 context) for each critical operational send: was required context retrieved AND present in history AT THAT TIME (chronology-sorted!) — distinguish gapKind retrieval (never fetched) vs attention (present, ignored); emit layerVerdicts L4. Record layersEngaged. CONFLICT DISCIPLINE (OT-1): when your own layers disagree (e.g. L1 pass vs L2 fail) emit BOTH verdicts honestly with a note — NEVER reconcile them yourself; the aggregate surfaces the conflict for a human."
433
+ - "Score EVERY criterion in the matrix for THIS trajectory: read only what the row needs (judgeInputs); compare against statement + passCondition — criteria are the SUPER-LAYER: they may bind evidence from ANY walk phase"
407
434
  - "BIND (L1) per row: each criterion TERM must resolve in THIS trajectory; an unbound term ⇒ uncertain + blockedBy:{kind:factual-intent} (INDETERMINATE), ABSTAIN — never fail"
408
- - "GATHER: cite a structured ref {obs,path,value} for the claim AND any absence; surface TYPED assumptions for any ungroundable premise → uncertain(blockedBy)"
435
+ - "GATHER: cite a structured ref {obs,path,value} for the claim AND any absence (ref.obs = the packet's trajectoryId, NEVER an observation name; ref.path = packet-shaped trajectory.N/transcript.N OR trace-shaped observations.N — dot form canonical, brackets tolerated); surface TYPED assumptions for any ungroundable premise → uncertain(blockedBy)"
409
436
  - "Critique BEFORE verdict; commit to result ∈ {pass,fail} (uncertain when the INPUTS can't decide — abstain-on-silence); binary, severity is the row's"
410
437
  - "Inaction-can-be-success: a correct HOLD (no send during a non-critical outbound_guard) is a PASS even with zero tool calls"
411
438
  - "Write <trajectory_key>.verdict.json (a MatrixVerdictFile {trajectoryId, judgeModel, temperature:0, verdicts[]} — each verdict may carry refs?/assumptions?/blockedBy?)"
412
439
  - "EMIT-CONTRACT (HARD, WS-1): on every COMPLETE-fidelity trajectory you MUST also persist the §9.4 walk — `understanding` (M2), `expectedTrajectory` (M3), `agentSteps` (the target step lane), and `judgeSteps` (your anchored reasoning). These are NOT optional: the parent runs a machine `assessEmitCompleteness` gate (scripts/emit-completeness.ts) that LOUDLY flags any wholly-dropped field, and a verdict missing them STARVES the report's Trajectory (§2) + Self-Eval (§5) tabs. `agentSteps` is factual trace data (reconstruct it from the ordered tool steps you were given — order by startTime, the observations array is reverse-chronological); M2/M3/judgeSteps are YOUR reasoning. Only an INCOMPLETE (node-1) trajectory is exempt (it emits verdicts:[] and no walk)."
440
+ - "v3 EMIT-CONTRACT ADDITIONS (E-NEW): alongside the §9.4 walk, persist layerVerdicts[] (one per engaged layer, skipped ones marked), earlyExit?, layersEngaged, codeEvalHits[] (when the library ran), and the emissions SELF-MANIFEST {emitted[], missing[{key,reason}]} — list honestly what you gathered vs what this contract expects; a missing emission with a stated reason is a NAMED degrade, a silent drop is a defect (MR-5 catches it same-run)."
413
441
  - "Verdicts are independently VERIFIED (#mode-verify · ≠ judge · downgrade-only); a CRIT/HIGH uncertain rolls the run up to INCOMPLETE at the gate (no false-green)"
414
442
  compresses:
415
443
  - "read MatrixPacket DATA; frame in ROUTE (CONTEXT)"
@@ -456,9 +484,9 @@ commands:
456
484
  - "emit verified verdict (never flip, never fix)"
457
485
  preserves: "the GA-5 result-verifier contract (scripts/result-verify.ts verifyVerdict / verifyVerdicts) — see '## Mode: verify' below. A MODE of evaluator, not a 4th registered agent (grounded-adjudication.md sign-off c4)."
458
486
 
459
- # F18+F19: the ADL ③ IMPROVE / Eval-Driven-Development loop. A MODE of evaluator (roster stays 3),
487
+ # F18+F19: the ADL ③ OPTIMIZE / Eval-Driven-Development loop. A MODE of evaluator (roster stays 3),
460
488
  # not a new subagent. JUDGE-ONLY held: this mode REQUESTS the engineer to fix; it never patches.
461
- - improve:
489
+ - optimize:
462
490
  meta:
463
491
  what: "Drive the EDD loop: variance-first (F19) → REQUEST the builder ai-engineer to amend (F18) → re-eval → bounded terminate."
464
492
  does: "After the initial *build, FIRST stabilizes per-case VARIANCE (repeat-N the SAME cases, default 5; gate the spread) BEFORE measuring accuracy. While JUDGE-ONLY (EV-051), emits a structured EddChangeRequest (failing cases + grounded refs + remedy target agentspec|impl) to the mutagent-builder ai-engineer over SendMessage; consumes the ChangeRequestResponse; re-evals; loops to full green OR a bounded STOP."
@@ -466,7 +494,7 @@ commands:
466
494
  how: "scripts/edd/variance-gate.ts gates variance (evaluateVarianceGate · nextPhaseAfterVariance · assertVarianceStableBeforeAccuracy); scripts/edd/change-request.ts is the seam + the bounded terminator (buildChangeRequest · validate{Change,Response} · reEvalWarranted · decideEddLoop). The eval-runner (sibling) is consumed via the clean interface (references/edd-loop.md §Assumed eval-runner interface) — this mode REBUILDS no runner."
467
495
  display: "The EDD loop — variance-first, then request-amend-reeval to full green (bounded)"
468
496
  description: |
469
- PURPOSE: the ADL ③ IMPROVE stage. Drive the subject to full green via the
497
+ PURPOSE: the ADL ③ OPTIMIZE stage. Drive the subject to full green via the
470
498
  Eval-Driven-Development loop — F19 VARIANCE-FIRST (stabilize per-case spread
471
499
  BEFORE accuracy) then F18 EDD CLOSURE (REQUEST the builder ai-engineer to amend the
472
500
  Agent/AgentSpec, re-eval, repeat) — bounded by an afkloop-legal terminator.
@@ -475,11 +503,11 @@ commands:
475
503
  JUDGE-ONLY (EV-051): this mode NEVER edits the subject — it emits a grounded
476
504
  EddChangeRequest over SendMessage and re-evals what the engineer amends.
477
505
  NEVER self-dispatches the engineer's fix; NEVER skips re-eval on an amend.
478
- dispatch: { mode: improve }
506
+ dispatch: { mode: optimize }
479
507
  pre_gate.loads:
480
508
  - "references/edd-loop.md" # the F18/F19 loop doctrine + assumed eval-runner interface
481
509
  - "references/grounded-adjudication.md" # GA doctrine: every failing-case ask is grounded (≥1 ref)
482
- - "references/workflows/orchestrator-protocol.md" # the improve dispatch step
510
+ - "references/workflows/orchestrator-protocol.md" # the optimize dispatch step
483
511
  workflow:
484
512
  - "Pre-read references/edd-loop.md (the EDD doctrine + the assumed eval-runner interface) + references/grounded-adjudication.md"
485
513
  - "PHASE = variance (F19): for each case run repeat-N (default 5) via the eval-runner; collect per-case CaseVarianceObservation {verdicts[], trajectories?}"
@@ -496,7 +524,7 @@ commands:
496
524
  - "build GROUNDED change-request (failing cases + remedy target) — judge-only, request-not-patch"
497
525
  - "SendMessage to ai-engineer · consume response · re-eval on amend"
498
526
  - "bounded terminator (decideEddLoop): full-green ▸ DONE | swings/wallclock/no-improve ▸ STOPPED+delta"
499
- preserves: "JUDGE-ONLY (EV-051) — the improve mode REQUESTS a fix and re-evals; it never edits the subject. The amend is the mutagent-builder ai-engineer's job (the ONE agent allowed to touch the Agent/AgentSpec). See '## Mode: improve' below."
527
+ preserves: "JUDGE-ONLY (EV-051) — the optimize mode REQUESTS a fix and re-evals; it never edits the subject. The amend is the mutagent-builder ai-engineer's job (the ONE agent allowed to touch the Agent/AgentSpec). See '## Mode: optimize' below."
500
528
 
501
529
  resolution_contract: |
502
530
  When you encounter a *<name> token:
@@ -507,8 +535,8 @@ resolution_contract: |
507
535
  mode: judge, axis: trajectory => run #mode-judge-trajectory (preserves eval-matrix-judge); input is a .packet.json.
508
536
  mode: judge, axis: criterion => run #mode-judge-criterion (preserves eval-judge); input is a .task.json.
509
537
  mode: verify => run #mode-verify (GA-5 result-verifier; reviewer≠judge, downgrade-only); input is a decided verdict + its situation.
510
- mode: improve => run #mode-improve (EDD ③ loop — F19 variance-first then F18 request-amend-reeval, bounded). JUDGE-ONLY: REQUEST, never patch.
511
- mode: judge, axis: code-quality => run #mode-judge-code-quality (Wave-2 W2I1 — score a CODE subject's QUALITY for the ⑤ IMPROVE code-target BOTH-gate). JUDGE-ONLY; binary quality PASS/FAIL. Rubric mirrored in scripts/code-quality-verdict.ts.
538
+ mode: optimize => run #mode-optimize (EDD ③ loop — F19 variance-first then F18 request-amend-reeval, bounded). JUDGE-ONLY: REQUEST, never patch.
539
+ mode: judge, axis: code-quality => run #mode-judge-code-quality (Wave-2 W2I1 — score a CODE subject's QUALITY for the ⑤ OPTIMIZE code-target BOTH-gate). JUDGE-ONLY; binary quality PASS/FAIL. Rubric mirrored in scripts/code-quality-verdict.ts.
512
540
  4. DISPATCH-INPUT DISAMBIGUATION — the parent hands you files:
513
541
  a *.packet.json (MatrixPacket) => judge/trajectory, ALWAYS (matrix-judge path; no unit field).
514
542
  a *.task.json (JudgeTaskSpec) => unit.kind: "discover" => discover; else unit.axis: "criterion" => judge/criterion.
@@ -615,8 +643,13 @@ a new eval mid-judging. Your focus is judging what IS, not pondering what could
615
643
  - Compare the trajectory/transcript against the row's `statement` + `passCondition`.
616
644
  - **GROUND (node 4 — ABSENCE-SPLIT) — REFS ARE MANDATORY, NOT DECORATIVE:** every **decided**
617
645
  verdict (`result ∈ {pass, fail}`) MUST carry **≥1 structured `ref {obs, path, value}`** that
618
- grounds it — `obs` = the trace/observation id you read, `path` = the field path within it
619
- (e.g. `output.response`, `observations[3].output.success`), `value` = the EXACT cited string
646
+ grounds it — **`obs` = the packet's `trajectoryId` (the trace id), NEVER an observation
647
+ name** (in a multi-trajectory batch an observation-name `obs` can locate the WRONG
648
+ trajectory — the resolver takes the FIRST match in batch order), `path` = the field path
649
+ within the situation you were handed — packet-shaped (`trajectory.0.name`,
650
+ `transcript.0.content`) and trace-shaped (`observations.3.output.success`) BOTH re-resolve
651
+ (the verifier reconstructs the packet views deterministically); dot form is canonical,
652
+ bracket indices (`observations[3]`) are tolerated — `value` = the EXACT cited string
620
653
  (re-resolved by whitespace-normalized exact match by `#mode-verify`). **The string your prose
621
654
  critique already quotes IS the ref's `value`** — you are not inventing evidence, you are making
622
655
  the evidence the critique cites MACHINE-CHECKABLE. A decided verdict with a critique that cites
@@ -690,10 +723,12 @@ a new eval mid-judging. Your focus is judging what IS, not pondering what could
690
723
  "refs": [
691
724
  { "obs": "ef30a271", "path": "input.prompt", "value": "<outbound_guard consecutive_outbound=\"7\">" },
692
725
  { "obs": "ef30a271", "path": "output.response", "value": "held" },
693
- { "obs": "ef30a271", "path": "observations[0].name", "value": "ai.generateText" }
726
+ { "obs": "ef30a271", "path": "observations.0.name", "value": "ai.generateText" }
694
727
  ]
695
728
  }
696
729
  ```
730
+ (`"ef30a271"` is the packet's `trajectoryId`. Note the dot-form index `observations.0.name` —
731
+ canonical; `observations[0].name` also resolves.)
697
732
  Each `ref.value` is a VERBATIM string from the trace the critique quotes — `#mode-verify`
698
733
  re-resolves it by exact match; a value the trace doesn't contain is a dead ref → downgrade.
699
734
  **Counter-example (DEFECT — do NOT emit):** the same verdict with `"refs": []` (or `refs`
@@ -860,6 +895,29 @@ this inline section is now its canonical home.
860
895
  pick a primitive + field/params); else keep `class: judge` and emit NO codeEval. A code/hybrid
861
896
  category WITHOUT a `codeEval` is a HARD error (tier-0 inert). The `statement` stays the human
862
897
  "Pass = …"; the `codeEval` is its runnable twin (run by the tier-0 pre-pass, zero judge tokens).
898
+ **§5b PROPOSALS ARE NOW HONORED:** the `level` / `severity` / `dimension` / `generality` you emit
899
+ are carried onto the mined criterion and the generic heuristics are the FALLBACK, not the
900
+ override (they used to be dropped in the JOIN, which pinned every criterion to `level: output`).
901
+ Emit what you actually judged; omit a field only when you want it derived.
902
+ 4b. **NAME the cluster suite-aware — `reinforce_not_restate`.** Only now (AFTER clustering, never
903
+ before) open `existing-criteria.json`: the criteria the suite ALREADY holds, as
904
+ `{id, statement, severity, level, checkedBy}`. If one of them already states the behaviour your
905
+ cluster found, emit your cluster under **that criterion's exact id** — your traces then attach to
906
+ it as REINFORCING evidence rather than standing up a second name for one check. The ORDER is
907
+ load-bearing: consulting the suite before reading would hand you a pre-defined failure list and
908
+ re-create the confirmation bias `emergent_categories_only` exists to prevent. Clustering first
909
+ keeps what you FIND emergent; the brief only informs what you CALL it. It ships no evidence, so
910
+ it cannot tempt you into re-citing a failure you did not read. It **informs, it never blocks** —
911
+ if the traces show something no existing criterion states, MINT IT; and never emit an existing id
912
+ with no trace of your own behind it (that is an invented finding). An absent or empty brief is
913
+ normal on a first run — proceed unchanged.
914
+ The brief also lists **`openQuestions[]`** — pairs of EXISTING criteria already awaiting a human
915
+ ruling on whether they are really one check, each with the reason they were kept apart (e.g.
916
+ `marker parity: [BEFORE] vs [AFTER]`). Both sides are live and both statements appear in
917
+ `criteria[]`. If your cluster matches one side, emit it under **that side's id**: minting a third
918
+ name for a behaviour that is already an open question makes the question harder to answer, not
919
+ easier. Do **not** attempt to settle the question yourself — you are not the ruling authority.
920
+ If your cluster genuinely matches neither side, it is new; mint it.
863
921
  5. **Flag fixable-vs-eval-worthy (S4 / EV-051).** Route the fixable + infra-class (e.g. sample C4
864
922
  dead-channel `account_number_unavailable`) to diagnostics; keep the genuinely behavioral criteria
865
923
  for `*build-evals`. NEVER fix.
@@ -871,14 +929,18 @@ this inline section is now its canonical home.
871
929
  the FAILURE + UNCERTAIN traces into DATASET CANDIDATES (`collectDatasetCandidates`, reusing the
872
930
  derive-dataset selectors) and folds in the `*evaluate` judge's node-2.5 unmatched-detection
873
931
  handoff — both consumable by `*build-dataset`. You mine + flag; the parent emits the candidates.
874
- 7. **Render the discover `discovery-report.html` via the SHIPPED `writeDiscoverRunReport` composer**
875
- (`render-discover-report.ts`) — pass the run dir; it builds `triage-summary.json` from
876
- `triage.json` + wires every companion (verdicts Proof-of-work, dataset-candidates Dataset,
877
- triage census coverage funnel, profile entity hero) so the report is COMPLETE BY DEFAULT.
932
+ 7. **Render the discover `discovery-report.html` via the SHIPPED `writeDiscoverRunReportV3` composer**
933
+ (`render-discover-report-v3.ts`) — pass the run dir PLUS the AGGREGATE result you already hold in
934
+ memory (`criteria` · `annotations` · the leaf `miningReport` · the ingested `traces` ·
935
+ `datasetCandidates` · the grown `suite` provenance). It writes BOTH surfaces: the PRODUCTION
936
+ W3 frozen-contract report at `discovery-report.html` and the previous renderer's output at
937
+ `discovery-report.v2.html` (transition fallback) — mirroring eval's `writeRunReport`. Anything you
938
+ do not pass is read from the run dir; a genuinely absent companion renders as a **NAMED absence**
939
+ (e.g. "sampling strategy census: not recorded by this run"), NEVER a fabricated number.
878
940
  **Do NOT render via bare `writeDiscoverReport(criteria, grounding)`** — without companions it
879
941
  degrades the funnel to em-dash and leaves Proof-of-work + Dataset empty (the A4 thin-report gap;
880
- the data exists, it just isn't forwarded). Eval's `writeRunReport` is already complete-by-default;
881
- discover MUST use its composer to match.
942
+ the data exists, it just isn't forwarded). The v2 composer `writeDiscoverRunReport`
943
+ (`render-discover-report.ts`) stays available unchanged for the legacy surface.
882
944
 
883
945
  ### Governing invariants (verbatim — must survive the merge)
884
946
 
@@ -890,6 +952,7 @@ this inline section is now its canonical home.
890
952
  - `gather_structured_refs`: "Every observed claim AND every absence claim cites a structured ref {obs,path,value} (ground-absence = a positive field check, never inferred from silence)."
891
953
  - `typed_assumptions`: "Every surfaced assumption is TYPED — factual-intent · normative · scope — so its lifecycle/blocking routes correctly (GA-3)."
892
954
  - `emergent_categories_only`: "Categories EMERGE from what the traces show. Never start from a pre-defined failure list (confirmation bias). No generic scores as categories."
955
+ - `reinforce_not_restate`: "The existing suite (existing-criteria.json) is consulted AFTER clustering, to NAME an already-emerged cluster — never before, which would seed a pre-defined list and violate emergent_categories_only. A cluster whose behaviour an existing criterion already states is emitted under THAT id (reinforcing evidence), not as a second name for one check. INFORMS, never blocks: a genuinely new behaviour is always minted. An existing id emitted with no trace of your own behind it is a fabricated finding."
893
956
  - `judge_only_never_fix`: "EV-051 — FLAGS fixable-vs-eval-worthy and routes the fixable + infra-class to diagnostics. NEVER fixes the subject."
894
957
  - `binary_actionable`: "Each emergent category is one binary criterion whose verdict points at a concrete fix locus."
895
958
  - `full_mined_criterion_emit`: "Emit the FULL MinedCriterion (base + §5b metadata + §5c discovery incl. structured refs + typed assumptions). A lightweight/flattened emit that drops refs/assumptions is a DEFECT."
@@ -949,9 +1012,9 @@ registered subagent** (the roster stays evaluator · dataset-builder · audit-ex
949
1012
  - **Feeds the gate:** a downgraded CRIT/HIGH verdict makes the run **INCOMPLETE** (the ternary gate
950
1013
  `fail ▸ incomplete ▸ pass`) — the latent false-green killer.
951
1014
 
952
- ## Mode: improve ← EDD ③ IMPROVE loop (F18 closure + F19 variance-first)
1015
+ ## Mode: optimize ← EDD ③ OPTIMIZE loop (F18 closure + F19 variance-first)
953
1016
 
954
- THE **Eval-Driven-Development loop** — the ADL ③ IMPROVE stage. After the initial `*build` +
1017
+ THE **Eval-Driven-Development loop** — the ADL ③ OPTIMIZE stage. After the initial `*build` +
955
1018
  `*evaluate`, this mode drives the subject to **full green**. It is a **MODE of `evaluator`, not a new
956
1019
  registered subagent** (the roster stays evaluator · dataset-builder · audit-executor). It backs
957
1020
  `scripts/edd/variance-gate.ts` (F19) + `scripts/edd/change-request.ts` (F18). It stays **JUDGE-ONLY
@@ -1013,7 +1076,7 @@ never re-implements, the runner. The interface this mode ASSUMES (documented ver
1013
1076
  ### Governing invariants (must survive any merge)
1014
1077
 
1015
1078
  - `variance_before_accuracy` (F19): "Stabilize per-case variance (repeat-N, default 5) BEFORE measuring accuracy. The accuracy phase is entered ONLY when the variance gate passes (`assertVarianceStableBeforeAccuracy` THROWS otherwise). Accuracy over big samples is wasted on a flapping verdict."
1016
- - `judge_only_requests_never_patches` (F18 · EV-051): "The improve mode REQUESTS the builder ai-engineer to amend (over SendMessage) and re-evals what is amended. It NEVER edits the subject/spec/source itself — the mutagent-builder ai-engineer is the ONE agent allowed to touch the Agent/AgentSpec."
1079
+ - `judge_only_requests_never_patches` (F18 · EV-051): "The optimize mode REQUESTS the builder ai-engineer to amend (over SendMessage) and re-evals what is amended. It NEVER edits the subject/spec/source itself — the mutagent-builder ai-engineer is the ONE agent allowed to touch the Agent/AgentSpec."
1017
1080
  - `grounded_change_request` (F18 · GA-1): "Every failing case in a change-request carries the verbatim critique + ≥1 structured ref{obs,path,value}. An ungrounded ask fails loud (`validateChangeRequest`)."
1018
1081
  - `remedy_target_def_vs_impl` (F18): "The evaluator PROPOSES where the fix belongs — `agentspec` (the DEFINITION is wrong → def→impl cascade via *build) vs `impl` (a wiring/faithfulness defect). It proposes; the engineer decides + may reject with a reason."
1019
1082
  - `reeval_always_follows_amend` (F18): "An `amended` response ALWAYS triggers a fresh evaluation swing (from the variance phase). There is no 'fixed it, trust me, skip re-eval' path. A `rejected` response never re-evals an unchanged subject."
@@ -1030,9 +1093,9 @@ never re-implements, the runner. The interface this mode ASSUMES (documented ver
1030
1093
  C-PIN (pinned model + temperature 0).
1031
1094
  - **Additive to the runner:** consumes the assumed eval-runner interface; rebuilds nothing.
1032
1095
 
1033
- ## Mode: judge — axis code-quality ← the ⑤ IMPROVE code-target quality verdict (Wave-2 W2I1)
1096
+ ## Mode: judge — axis code-quality ← the ⑤ OPTIMIZE code-target quality verdict (Wave-2 W2I1)
1034
1097
 
1035
- The **(b) half of the ⑤ IMPROVE loop's code-target BOTH-gate.** For a `code`-kind subject, "converged"
1098
+ The **(b) half of the ⑤ OPTIMIZE loop's code-target BOTH-gate.** For a `code`-kind subject, "converged"
1036
1099
  requires BOTH (a) the subject's OWN test suite green — a hard DETERMINISTIC gate the ai-engineer
1037
1100
  reports and the optimize oracle records as `testsGreen` — AND (b) THIS code-quality verdict passing.
1038
1101
  This mode is (b): score the QUALITY of the applied code change, BEYOND tests-green (a deterministic
@@ -1064,7 +1127,7 @@ mirroring how the other judge prompts mirror their agent modes).
1064
1127
  ## Eval-leg reconcile — criteria MAINTENANCE, not judging (Wave-2 W2I5 · KP-003)
1065
1128
 
1066
1129
  The evaluator owns the **eval leg** of the def → impl → eval triad — the third leg of `#sync-spec`. When
1067
- an impl amends (the ⑤ IMPROVE loop's ai-engineer, or brownfield drift), the eval criteria that ground the
1130
+ an impl amends (the ⑤ OPTIMIZE loop's ai-engineer, or brownfield drift), the eval criteria that ground the
1068
1131
  subject's evaluation can go stale. The reconcile REASONING — which criteria a changed impl makes stale,
1069
1132
  what new criterion it needs — is the **ai-architect's** (`#sync-spec`, session-dispatched, Model-B). The
1070
1133
  evaluator exposes only the deterministic CONTRACT the reconcile reads/writes, in
@@ -0,0 +1,75 @@
1
+ # code-quality-criteria.yaml — the CODE-QUALITY rubric (⑤ OPTIMIZE code-target BOTH-gate, W2I1)
2
+ # ═══════════════════════════════════════════════════════════════════════════════
3
+ # THIS FILE IS THE RUBRIC. Edit it to tune what "code quality-pass" means — no code
4
+ # change, no release. `scripts/code-quality-verdict.ts` loads it at import time and
5
+ # exports it as DEFAULT_CODE_QUALITY_CRITERIA.
6
+ #
7
+ # WHAT IT GATES: for a subject whose medium is `code`, "converged" = the subject's OWN
8
+ # test suite green (deterministic) AND this rubric PASSes. Neither alone converges.
9
+ # Prompt/markdown subjects never touch this file — they converge on evals alone.
10
+ #
11
+ # AGGREGATION (severity-gated): a `fail` OR `uncertain` on any `critical`/`high`
12
+ # criterion BLOCKS the quality-pass. `medium` is advisory (recorded, never blocking).
13
+ #
14
+ # EDITING RULES:
15
+ # - `id` is a byte-identity key + report anchor. Changing an id breaks historical
16
+ # comparison — add a new criterion instead of renaming an old one.
17
+ # - Every criterion must be BINARY (decidable pass/fail), never a Likert score.
18
+ # - `severity` must be exactly one of: critical | high | medium.
19
+ # - Keep passDefinition/failDefinition CONCRETE — the judge must not have to guess.
20
+ # - Bump `version` on any change to this file.
21
+ #
22
+ # STATUS: the picks below are the conservative, subject-agnostic starting set
23
+ # (FLAGGED-for-operator-sign-off, Wave-2 W2I1) — a default, not a final contract.
24
+
25
+ version: 1
26
+
27
+ criteria:
28
+ - id: Q1-spec-faithful
29
+ statement: The implementation realizes the agentspec definition the amend targeted.
30
+ passDefinition: >-
31
+ PASS: every spec-declared tool / job-to-be-done is present and the operative
32
+ system_prompt is unchanged except where the amend intended; the def→impl cascade held.
33
+ failDefinition: >-
34
+ FAIL: a spec-declared tool or JTBD is missing, or the system_prompt was altered
35
+ beyond the amend intent (the impl forked from the SSoT).
36
+ severity: critical
37
+
38
+ - id: Q2-addresses-diagnosis
39
+ statement: The change targets the diagnosed root-cause locus, not an adjacent symptom.
40
+ passDefinition: >-
41
+ PASS: the edit is at (or directly causes a fix at) the RCA-named locus / the
42
+ failing-case root.
43
+ failDefinition: >-
44
+ FAIL: the change edits an unrelated place or patches a symptom while the root
45
+ cause remains.
46
+ severity: high
47
+
48
+ - id: Q3-no-regression
49
+ statement: The change introduces no unrelated regression and stays in scope.
50
+ passDefinition: >-
51
+ PASS: only the remedy-named surface changed; no unrelated behavior was removed
52
+ or broken.
53
+ failDefinition: >-
54
+ FAIL: unrelated code was changed/removed, or a previously-working path was broken.
55
+ severity: high
56
+
57
+ - id: Q4-error-handling
58
+ statement: Failure paths are handled, not silently dropped.
59
+ passDefinition: >-
60
+ PASS: error/failure branches surface, recover, or log per the subject's contract;
61
+ no new silent drop.
62
+ failDefinition: >-
63
+ FAIL: a failure is swallowed with no recovery/notify/observability (a silent-drop
64
+ regression).
65
+ severity: high
66
+
67
+ - id: Q5-maintainable
68
+ statement: The code is readable, framework-idiomatic, and free of obvious footguns.
69
+ passDefinition: >-
70
+ PASS: clear structure, idiomatic to the target framework, no dead code /
71
+ copy-paste / obvious footgun introduced.
72
+ failDefinition: >-
73
+ FAIL: unreadable/duplicated/dead code or an obvious maintainability footgun was
74
+ introduced.
75
+ severity: medium