orizu 0.5.21 → 0.5.23

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 (87) hide show
  1. package/README.md +46 -15
  2. package/dist/cleanup.d.ts +6 -0
  3. package/dist/cleanup.d.ts.map +1 -0
  4. package/dist/cleanup.js +27 -0
  5. package/dist/gepa-engine-dispatch.d.ts.map +1 -1
  6. package/dist/gepa-engine-dispatch.js +20 -1
  7. package/dist/gepa-python-paths.d.ts.map +1 -1
  8. package/dist/gepa-python-paths.js +25 -6
  9. package/dist/help.d.ts.map +1 -1
  10. package/dist/help.js +37 -15
  11. package/dist/hosted-commands.d.ts +13 -0
  12. package/dist/hosted-commands.d.ts.map +1 -0
  13. package/dist/hosted-commands.js +10 -0
  14. package/dist/hosted-gepa-cli.d.ts +11 -0
  15. package/dist/hosted-gepa-cli.d.ts.map +1 -0
  16. package/dist/hosted-gepa-cli.js +110 -0
  17. package/dist/hosted-gepa-numeric-values.d.ts +3 -0
  18. package/dist/hosted-gepa-numeric-values.d.ts.map +1 -0
  19. package/dist/hosted-gepa-numeric-values.js +49 -0
  20. package/dist/hosted-provider-settings.d.ts +3 -0
  21. package/dist/hosted-provider-settings.d.ts.map +1 -0
  22. package/dist/hosted-provider-settings.js +69 -0
  23. package/dist/hosted-session-cli.d.ts.map +1 -1
  24. package/dist/hosted-session-cli.js +6 -1
  25. package/dist/http.d.ts +1 -0
  26. package/dist/http.d.ts.map +1 -1
  27. package/dist/http.js +7 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +72 -74
  30. package/dist/instruction-set-loader.d.ts.map +1 -1
  31. package/dist/instruction-set-loader.js +57 -5
  32. package/dist/instruction-sets-cli.d.ts +5 -2
  33. package/dist/instruction-sets-cli.d.ts.map +1 -1
  34. package/dist/instruction-sets-cli.js +134 -24
  35. package/dist/optimizations-promote-cli.d.ts +3 -0
  36. package/dist/optimizations-promote-cli.d.ts.map +1 -1
  37. package/dist/optimizations-promote-cli.js +75 -7
  38. package/dist/runner-dir-verify.d.ts.map +1 -1
  39. package/dist/runner-dir-verify.js +4 -7
  40. package/dist/skilled-proposer-bake-report.d.ts +2 -0
  41. package/dist/skilled-proposer-bake-report.d.ts.map +1 -0
  42. package/dist/skilled-proposer-bake-report.js +1 -0
  43. package/dist/skilled-proposer-config.d.ts +2 -0
  44. package/dist/skilled-proposer-config.d.ts.map +1 -0
  45. package/dist/skilled-proposer-config.js +212 -0
  46. package/dist/skilled-proposer-launch.d.ts +26 -0
  47. package/dist/skilled-proposer-launch.d.ts.map +1 -1
  48. package/dist/skilled-proposer-launch.js +103 -6
  49. package/package.json +1 -1
  50. package/scripts/vendor-gepa-python.mjs +81 -12
  51. package/src/cleanup.ts +37 -0
  52. package/src/gepa-engine-dispatch.ts +21 -1
  53. package/src/gepa-python-paths.ts +24 -6
  54. package/src/help.ts +37 -15
  55. package/src/hosted-commands.ts +4 -0
  56. package/src/hosted-gepa-cli.ts +107 -0
  57. package/src/hosted-gepa-numeric-values.ts +60 -0
  58. package/src/hosted-provider-settings.ts +69 -0
  59. package/src/hosted-session-cli.ts +4 -1
  60. package/src/http.ts +8 -0
  61. package/src/index.ts +112 -89
  62. package/src/instruction-set-loader.ts +55 -5
  63. package/src/instruction-sets-cli.ts +173 -19
  64. package/src/optimizations-promote-cli.ts +85 -7
  65. package/src/runner-dir-verify.ts +11 -6
  66. package/src/skilled-proposer-bake-report.ts +1 -0
  67. package/src/skilled-proposer-config.ts +191 -0
  68. package/src/skilled-proposer-launch.ts +96 -7
  69. package/src/skilled-proposer-venv-manager.mjs +44 -27
  70. package/vendor/orizu-gepa/src/orizu_gepa_connector/engine.py +36 -3
  71. package/vendor/orizu-gepa/src/orizu_gepa_connector/instruction_set_loader.py +31 -3
  72. package/vendor/orizu-gepa/src/orizu_gepa_connector/runtime.py +7 -2
  73. package/vendor/orizu-gepa/src/orizu_gepa_connector/skilled_proposer_bridge.py +354 -5
  74. package/vendor/orizu-gepa-python/src/orizu_gepa/cli.py +1 -0
  75. package/vendor/orizu-gepa-python/src/orizu_gepa/client.py +15 -0
  76. package/vendor/skills/orizu-cli/SKILL.md +94 -168
  77. package/vendor/skills/orizu-cli/references/assess-and-plan.md +107 -0
  78. package/vendor/skills/orizu-cli/references/building-judges.md +442 -180
  79. package/vendor/skills/orizu-cli/references/cli-reference.md +69 -39
  80. package/vendor/skills/orizu-cli/references/dataset-design.md +100 -0
  81. package/vendor/skills/orizu-cli/references/eval-strategy.md +64 -0
  82. package/vendor/skills/orizu-cli/references/instructions-after-prompts.md +115 -0
  83. package/vendor/skills/orizu-cli/references/migrate-existing-gepa-setup.md +150 -82
  84. package/vendor/skills/orizu-cli/references/optimization-reports.md +196 -104
  85. package/vendor/skills/orizu-cli/references/optimization-with-gepa.md +57 -37
  86. package/vendor/skills/orizu-cli/references/primer.md +43 -18
  87. package/vendor/skills/orizu-cli/references/prompt-control-plane.md +199 -131
@@ -1,50 +1,122 @@
1
1
  # Building Judges And Scorers
2
2
 
3
- How to turn human-labeled annotations into automated evaluators. Use this reference for authoring and validating the evaluator logic; use `prompt-control-plane.md` to push versioned prompt artifacts, runner artifacts, scorer definitions, and score runs into Orizu.
4
-
5
- ## Inputs
6
-
7
- You should arrive here with:
8
- - A labeled task export: `orizu tasks export --task <taskId> --format jsonl --out labels.jsonl`
9
- - One or more **specific binary failure modes** the labels measure (e.g. `correctly_identified_issue`, `escalated_when_required`).
10
- - The original dataset row each label refers to (the export includes `dataset_row_id` and the row payload).
11
-
12
- If you have Likert or "overall quality" labels, stop and re-annotate. Judges built on Likert data are unreliable. See `primer.md` Step 2.
13
-
14
- Terminology:
15
- - A **judge** is the evaluator itself, often an LLM prompt plus runner.
16
- - A **scorer** is the metric contract stored in Orizu. It names the score, directionality, mode (`row` or `set`), display format, and backing implementation.
17
- - Row scorers return per-row scores and feedback. Set scorers compute aggregate metrics such as Cohen's kappa, accuracy, precision, recall, F1, or a custom reducer over row-level outputs.
18
- - Use `orizu scorers exec` for scorer-level evaluation. Builtin set scorers consume subject results or dependency row-scorer results and submit one aggregate score run by default. `runners exec --scorer-version` is a low-level row-runner compatibility command.
19
-
20
- ## Choosing the judge type
21
-
22
- | Failure mode looks like | Use |
23
- |-------------------------|-------------------------------------------|
24
- | Rule-shaped (keyword present, tool called, format valid, length within bounds) | **Code assertion** |
25
- | Subjective / nuanced (offered the right resolution, tone matches policy, escalation was warranted) | **LLM-as-a-judge** |
26
- | Path-of-life (block before user sees the response — toxicity, PII leak) | **Guardrail** (small classifier or code, runs synchronously; not covered here) |
27
-
28
- Default to code. LLM judges cost money, time, and trust budget — earn them.
29
-
30
- ## Code assertions
31
-
32
- A code assertion is a pure function:
33
-
34
- ```python
35
- def passes(input: dict, output: dict) -> bool:
36
- # Returns True if the output is acceptable for this failure mode.
37
- ...
38
- ```
39
-
40
- **Patterns that work well:**
41
- - Keyword/regex match on output text
42
- - Structural check on JSON output
43
- - Tool-call verification (did the agent call the expected tool with valid args?)
44
- - Length/format bounds (response is within N tokens, ends with a question mark, etc.)
45
- - Numeric tolerance for known answers
46
-
47
- **Example — case reference number present in support response:**
3
+ Turn human-labeled decisions into automated evaluators whose alignment is good
4
+ enough for the decision they power. Use this reference for authoring, alignment,
5
+ and judge optimization. Use `prompt-control-plane.md` for artifact manifests,
6
+ versioning, and score-submission contracts.
7
+
8
+ ## Inputs and terms
9
+
10
+ Arrive with one of these accepted label inputs:
11
+
12
+ - a labeled task export: `orizu tasks export --task <taskId> --format jsonl --out labels.jsonl`;
13
+ - a versioned golden dataset plus its human-label field mapping; or
14
+ - for a mixed dataset, the union of golden field-mapping rows and task-export
15
+ rows, keyed by the primary dataset's `dataset_row_id`.
16
+
17
+ The downstream judge-building steps are identical for all three forms. Also
18
+ arrive with:
19
+
20
+ - one or more specific binary **failure modes**, such as
21
+ `correctly_identified_issue` or `escalated_when_required`;
22
+ - the original dataset row for every label; and
23
+ - multiply labeled rows for measuring human–human agreement.
24
+
25
+ If the labels are Likert scores or an “overall quality” bundle, return to the
26
+ **J4 — Ground truth via annotation (conditional)** and rewrite the rubric as one binary question
27
+ per failure mode before building a judge.
28
+
29
+ - A **judge** is the evaluator, often an LLM instruction set plus a runner.
30
+ - A **scorer** is the metric contract stored in Orizu. It names the score,
31
+ directionality, mode (`row` or `set`), display format, and implementation.
32
+ - Row scorers return per-row scores and feedback. Set scorers compute batch
33
+ metrics such as agreement, precision, recall, F1, or a custom reduction.
34
+
35
+ ## Start with alignment, not a universal threshold
36
+
37
+ Raw percent agreement is the share of identical decisions, and it can look high
38
+ when one label dominates even if the judge learned nothing. **Cohen's kappa** is
39
+ chance-corrected agreement, so zero means chance-level agreement. **TPR (true
40
+ positive rate)** is the fraction of human-labeled failures the judge catches.
41
+ **TNR (true negative rate)** is the fraction of human-labeled passes the judge
42
+ correctly leaves unflagged.
43
+
44
+ Measure kappa, TPR, and TNR separately for every failure mode on judge-test rows.
45
+ Always show the confusion matrix, sample count, class balance, and scenario-class
46
+ breakdown beside them. A judge that flags everything can have perfect TPR and
47
+ useless TNR; a judge that passes everything has the inverse failure. If a
48
+ judge-test set contains no positives or no negatives, the corresponding rate is
49
+ undefined: collect enough examples of that class before setting or clearing a
50
+ bar.
51
+
52
+ ### Measure the human ceiling first
53
+
54
+ Use only rows with two or more independent labels on the same example. For each
55
+ failure mode, compute human–human kappa and inspect the annotator confusion
56
+ matrix and directional disagreement. Do not infer the ceiling from single-label
57
+ rows or overall agreement. Judge–human kappa should normally land within about
58
+ 0.05–0.10 of human–human kappa.
59
+
60
+ When human–human kappa is itself low (below ~0.6), the rubric or labels are the
61
+ bottleneck. Return to **J4 — Ground truth via annotation (conditional)**: clarify the
62
+ failure-mode definition, add boundary examples, repair the labeler workflow, and
63
+ relabel a shared sample. Recompute the human ceiling before changing judge
64
+ instructions. Judge tuning against disputed labels only automates the dispute.
65
+
66
+ ### Teach the framework and agree on each bar
67
+
68
+ The agent presents the observed label balance, human ceiling, confusion costs,
69
+ and the following starting points. These are defaults to reason from, not
70
+ requirements.
71
+
72
+ | Decision class | Starting-point threshold (agent + user adjust together) |
73
+ | -- | -- |
74
+ | **Gatekeeper** — headline metric; informs ship/promote decisions | kappa ≥ 0.75, TPR ≥ 0.90 and TNR ≥ 0.90, and within 0.10 of human–human kappa |
75
+ | **Optimization signal** — GEPA reflection and candidate selection | kappa ≥ 0.6 (roughly the 70–80% agreement zone on balanced data). Row-level noise averages out across a run — but the winning candidate must be confirmed against a gatekeeper-grade judge before shipping, or we Goodhart on judge noise |
76
+ | **Triage / monitoring** — flags suspect traces for human review | TPR ≥ 0.80 with a tolerable false-positive rate; kappa ≥ 0.4–0.5 usable, because a human reviews every flag |
77
+
78
+ To clarify the table's rough parenthetical, on balanced data
79
+ `kappa = 2 * agreement - 1`: kappa 0.6 is about 80% raw agreement, and the
80
+ common 70–80% instinct spans kappa 0.4–0.6, which is why the bar sits at the top
81
+ of that zone.
82
+
83
+ For each judge and failure mode:
84
+
85
+ 1. Choose the decision class: gatekeeper, optimization signal, or triage /
86
+ monitoring.
87
+ 2. Explain the relevant false-negative and false-positive costs, the human
88
+ ceiling, small-sample uncertainty, and scenario-class gaps.
89
+ 3. Ask the user which kappa, TPR, TNR or false-positive-rate bars they accept.
90
+ The agent never selects a bar silently.
91
+ 4. Record the agreed judge trust bar in the judge-validation output before tuning or final
92
+ validation. Include the judge version, failure mode, decision class,
93
+ human–human kappa, each agreed judge trust bar metric, applicable scenario classes, user,
94
+ and decision date.
95
+
96
+ An agreement record can use this shape:
97
+
98
+ | Judge version | Failure mode | Decision class | Human–human kappa | Agreed judge trust bar | Scenario classes | Agreed by |
99
+ | -- | -- | -- | -- | -- | -- | -- |
100
+ | `<version>` | `<mode>` | `<class>` | `<value>` | `kappa …; TPR …; TNR/FPR …` | `<covered classes>` | `<user/date>` |
101
+
102
+ ## Choose and author the evaluator
103
+
104
+ | Failure mode looks like | Use |
105
+ | -- | -- |
106
+ | Rule-shaped: tool called, JSON valid, exact format, numeric bound | **Code assertion** |
107
+ | Nuanced: resolution was appropriate, tone met policy, escalation was warranted | **LLM judge** |
108
+ | Must block before a user sees the response: toxicity or PII leak | **Guardrail** (synchronous code or classifier; not covered here) |
109
+
110
+ Default to code for genuinely deterministic rules. A mechanically equivalent
111
+ assertion, such as schema validation when schema validity is the entire failure
112
+ definition, does not need prompt tuning or model-selection statistics. Record
113
+ why the assertion is identical to the human-approved rule. If it is gating, it
114
+ still needs an agreed judge trust bar and the registered, submitted evidence path from
115
+ **J5 — Build & validate judges**. A regex, keyword, or other heuristic is not
116
+ tautological merely because it is code; validate it against the human labels
117
+ like any other judge.
118
+
119
+ Example deterministic assertion:
48
120
 
49
121
  ```python
50
122
  import re
@@ -55,182 +127,372 @@ def has_case_reference(input: dict, output: dict) -> bool:
55
127
  return bool(CASE_REF_RE.search(output["text"]))
56
128
  ```
57
129
 
58
- Run it over the labeled export and confirm it agrees with the human labels for this failure mode. If it does, you're done — code assertions don't need TPR/TNR validation when they're tautologically correct (the rule *is* the failure definition).
130
+ For a nuanced failure mode, make the LLM judge return one binary decision and a
131
+ short reason. Its instructions should contain:
132
+
133
+ 1. the binary question;
134
+ 2. specific pass and fail criteria;
135
+ 3. four to eight stratified examples from the training split, including boundary
136
+ cases and short rationales; and
137
+ 4. a strict JSON result whose label is exactly `ok` or `flag`, such as
138
+ `{"label": "flag", "reason": "Escalation was required but omitted."}`.
139
+
140
+ For binary gold labels, require that binary verdict rather than a continuous
141
+ score. The runner validates the two allowed labels, stores the parsed object as
142
+ `model_response`, and emits `passed: label === "ok"`. The canonical kappa
143
+ manifest can then read `$dependencies.judge.model_response.label` with `flag` as
144
+ the positive class, while `scores submit` can aggregate the top-level `passed`
145
+ field. The GEPA alignment scorer uses the same `ok`/`flag` domain when comparing
146
+ the candidate verdict with the human label. This strict `label` contract applies
147
+ to the Orizu-native path. The external DSPy example in
148
+ `optimization-with-gepa.md` wraps the judge with its own `pass` shape at
149
+ `return 1.0 if judge_result["pass"] else 0.0`, so its wrapper adapts that shape
150
+ rather than expecting native shape parity.
151
+
152
+ Frame every scorer output so higher means better; for the binary row score,
153
+ `ok` maps to 1 and `flag` to 0. Never name a value as a loss or error while also
154
+ declaring `higher_is_better: true`, because that gives optimization and
155
+ reflection mixed directional signals.
156
+
157
+ ## Split, iterate, and validate
158
+
159
+ Build the labeled judge pool only from the application's train and validation
160
+ rows. Use a stratified split within that pool when labels are imbalanced; the
161
+ allocations below are starting points, and the exact judge-development /
162
+ judge-test split is yours to define:
163
+
164
+ | Set | Starting allocation | Purpose |
165
+ | -- | -- | -- |
166
+ | Judge train (`train`) | ~20% | Few-shot examples or judge-instruction optimization |
167
+ | Judge dev / validation (`validation`) | ~40% | Iterate and compare candidates |
168
+ | Judge test (`judge-test`) | ~40% | One alignment validation after the judge candidate is frozen |
169
+
170
+ Author `judge-split.json` with explicit row membership for all three judge
171
+ partitions. Every `row_ids` entry must come from the application's train or
172
+ validation partition; never include an application final-held-out row. Require
173
+ the three judge partitions to be mutually disjoint:
174
+
175
+ ```json
176
+ {
177
+ "name": "judge-alignment",
178
+ "strategy": "predefined",
179
+ "seed": null,
180
+ "partitions": [
181
+ { "name": "train", "row_ids": ["<judge-train-row-id>"] },
182
+ { "name": "validation", "row_ids": ["<judge-validation-row-id>"] },
183
+ { "name": "judge-test", "row_ids": ["<judge-test-row-id>"] }
184
+ ]
185
+ }
186
+ ```
187
+
188
+ Materialize that judge split set and record the returned `split_set_id` as
189
+ `<judge-split-set-id>`:
59
190
 
60
- If your code assertion disagrees with humans on >5% of cases, your rule isn't capturing the failure mode and you probably need an LLM judge instead.
191
+ ```bash
192
+ orizu datasets splits create <datasetVersionId> --from-file <judge-split.json> --json
193
+ ```
61
194
 
62
- ## LLM-as-a-judge
195
+ Keep the local `judge-split.json` and the source application split-membership
196
+ artifact in version control. Before materializing, record that the judge
197
+ partitions are pairwise disjoint, their union is a subset of application train
198
+ plus validation, and their union has zero intersection with application
199
+ final-held-out. That recorded comparison and `judge-split.json` are the
200
+ auditable row-membership evidence proving final-held-out exclusion.
201
+
202
+ On development rows, inspect false negatives when TPR is weak and false positives
203
+ when TNR is weak. Fix the failure-mode criteria and boundary examples, then rerun
204
+ development evaluation. Preserve judge-test until the candidate and agreed judge trust bar
205
+ are frozen. If judge-test alignment falls materially below development, treat
206
+ that as overfitting and return to a new development cycle rather than iterating
207
+ on judge-test rows.
208
+
209
+ The application final-held-out partition reserved for the single
210
+ seed-versus-selected comparison in the dataset-design reference (J3) never
211
+ appears in judge train, judge dev, judge test, or any other judge-alignment
212
+ material. A judge selected for agreement on those rows would bias the final
213
+ comparison through the judge itself. Those rows need no human labels. At the
214
+ **J6 — Optimize & promote**, the accepted judge scores the application
215
+ final-held-out rows exactly once for that comparison; this application scoring
216
+ is not judge-alignment measurement or tuning.
217
+
218
+ A 100% pass rate is a saturation warning, not evidence of alignment. Sample
219
+ fresh production traces and add harder scenario classes when an evaluator stops
220
+ finding meaningful failures.
221
+
222
+ ## Register and submit the validation evidence
223
+
224
+ Store evaluator code, instructions, manifests, validation records, and the labels
225
+ used to validate them in version control. Use `prompt-control-plane.md` for the
226
+ manifest bodies and artifact boundaries. A typical local layout is:
227
+
228
+ ```text
229
+ evals/<project>/
230
+ judge-split.json
231
+ judge-optimizer/
232
+ judges/<failure-mode>/
233
+ judge/
234
+ runner/
235
+ alignment-runner/
236
+ orizu.instruction-set.json
237
+ row-scorer.manifest.json
238
+ kappa-scorer.manifest.json
239
+ alignment-row-scorer.manifest.json
240
+ judge-validation.md
241
+ ```
63
242
 
64
- For nuanced failures, build a judge that takes `(input, output)` and returns `pass | fail`.
243
+ In a local workflow under the user's token, push the executable artifacts and
244
+ register both the row scorer used for per-example feedback and the set scorer
245
+ used for kappa plus confusion diagnostics. Hosted sessions follow the artifact
246
+ authority and commit rules in `SKILL.md`. Substitute IDs returned by each
247
+ command in subsequent commands:
65
248
 
66
- ### Step 1: Split the labels
249
+ For a custom deterministic code assertion that must complete the submitted J5
250
+ evidence path, use the executable `prompt_runner` control-plane shape. The
251
+ runner implements the assertion without calling an LLM; the judge artifact is
252
+ its versioned execution contract and output-schema identity. A `runner_only`
253
+ scorer can be registered, but the current CLI cannot execute it through either
254
+ `runners exec --scorer-version` or `scorers exec`, so it cannot satisfy this
255
+ recipe.
67
256
 
68
- Split your labeled export 20 / 40 / 40:
257
+ Set the row-scorer manifest's `implementation_kind: prompt_runner`, set the
258
+ dependent set-scorer manifest's `implementation_kind: builtin_metric`, and use
259
+ the IDs returned by each command in the next command:
69
260
 
70
- | Set | Size | Purpose |
71
- |--------|------|----------------------------------------------------|
72
- | Train | ~20% | Few-shot examples in the judge prompt |
73
- | Dev | ~40% | Iterate on the judge prompt; measure TPR / TNR |
74
- | Test | ~40% | Final validation; touch only when you think you're done |
261
+ ```bash
262
+ orizu runners push ./evals/<project>/judges/<failure-mode>/runner --project <team/project> --name <code-assertion-runner-name> --json
75
263
 
76
- Random split is fine for stationary data. If labels skew (e.g. 80% pass, 20% fail), stratify so each split preserves the ratio.
264
+ orizu judges push ./evals/<project>/judges/<failure-mode>/judge --project <team/project> --runner-version <code-assertion-runner-version-id> --json
77
265
 
78
- ### Step 2: Write the judge prompt
266
+ orizu scorers register --project <team/project> --name <code-assertion-row-scorer-name> --manifest ./evals/<project>/judges/<failure-mode>/row-scorer.manifest.json --prompt-version <code-assertion-judge-version-id> --runner-version <code-assertion-runner-version-id> --json
79
267
 
80
- Structure:
81
- 1. **Task framing.** What's being judged. State it as a binary question.
82
- 2. **Failure-mode definition.** Be specific. Include positive and negative criteria.
83
- 3. **Few-shot examples.** Draw 4–8 from the train set. Half pass, half fail. Include short rationales.
84
- 4. **Output format.** Force structured output: `{"pass": true|false, "reason": "..."}`. Reason is for debugging, not scoring.
268
+ # Set the dependency whose `alias` is `judge` in `kappa-scorer.manifest.json`: its `dependencies[].scorer_version_id` must be `<code-assertion-row-scorer-version-id>` before registering the dependent set scorer.
269
+ orizu scorers register --project <team/project> --name <code-assertion-kappa-scorer-name> --manifest ./evals/<project>/judges/<failure-mode>/kappa-scorer.manifest.json --json
85
270
 
86
- **Example skeleton:**
271
+ orizu runners exec --scorer-version <code-assertion-row-scorer-version-id> --dataset-version <dataset-version-id> --split-set <judge-split-set-id> --split judge-test --runner-dir ./evals/<project>/judges/<failure-mode>/runner --out ./code-assertion-judge-test-results.jsonl
87
272
 
88
- ```python
89
- JUDGE_PROMPT = """You are evaluating a customer support agent response.
273
+ orizu scores submit ./code-assertion-judge-test-results.jsonl --project <team/project> --scorer-version <code-assertion-row-scorer-version-id> --subject-version <code-assertion-judge-version-id> --dataset-version <dataset-version-id> --split-set <judge-split-set-id> --split judge-test --json
90
274
 
91
- The failure mode under evaluation: **escalated_when_required**.
92
- - PASS: When the customer's situation requires human escalation (refund > $500, account compromise, legal threat, distressed user), the agent escalated.
93
- - FAIL: The situation required escalation and the agent did not, OR the agent escalated unnecessarily.
275
+ orizu scorers exec --project <team/project> --scorer-version <code-assertion-kappa-scorer-version-id> --subject-version <code-assertion-judge-version-id> --dataset-version <dataset-version-id> --split-set <judge-split-set-id> --split judge-test --dependency-score-run judge=<code-assertion-row-score-run-id> --out ./code-assertion-judge-test-alignment.json --json
276
+ ```
94
277
 
95
- Respond with JSON only: {"pass": <true|false>, "reason": "<one sentence>"}.
278
+ For an LLM judge, register the prompt-backed row scorer and its dependent set
279
+ scorer:
96
280
 
97
- Examples:
98
- <input>{{example_1_input}}</input>
99
- <output>{{example_1_output}}</output>
100
- <judgment>{"pass": true, "reason": "Distressed user, agent handed off."}</judgment>
281
+ ```bash
282
+ orizu runners push ./evals/<project>/judges/<failure-mode>/runner --project <team/project> --name <judge-runner-name> --json
101
283
 
102
- <input>{{example_2_input}}</input>
103
- <output>{{example_2_output}}</output>
104
- <judgment>{"pass": false, "reason": "Refund $1200, agent processed without escalation."}</judgment>
284
+ orizu judges push ./evals/<project>/judges/<failure-mode>/judge --project <team/project> --runner-version <judge-runner-version-id> --json
105
285
 
106
- ... 4–8 examples total ...
286
+ orizu scorers register --project <team/project> --name <row-scorer-name> --manifest ./evals/<project>/judges/<failure-mode>/row-scorer.manifest.json --prompt-version <judge-version-id> --runner-version <judge-runner-version-id> --json
107
287
 
108
- Now evaluate:
109
- <input>{input}</input>
110
- <output>{output}</output>
111
- <judgment>"""
288
+ orizu scorers register --project <team/project> --name <kappa-scorer-name> --manifest ./evals/<project>/judges/<failure-mode>/kappa-scorer.manifest.json --json
112
289
  ```
113
290
 
114
- ### Step 3: Validate on dev set
291
+ For the LLM judge-test split, execute the row scorer, submit its row results,
292
+ and then execute the dependent set scorer. `scorers exec` submits the aggregate
293
+ score run by default, so omit `--no-submit` at the J5 — Build & validate judges
294
+ boundary. See `prompt-control-plane.md` for the canonical submission behavior:
115
295
 
116
- Run the judge over the dev set and compare against human labels. Compute:
296
+ ```bash
297
+ orizu runners exec --scorer-version <row-scorer-version-id> --dataset-version <dataset-version-id> --split-set <judge-split-set-id> --split judge-test --runner-dir ./evals/<project>/judges/<failure-mode>/runner --out ./judge-test-results.jsonl
117
298
 
299
+ orizu scores submit ./judge-test-results.jsonl --project <team/project> --scorer-version <row-scorer-version-id> --subject-version <judge-version-id> --dataset-version <dataset-version-id> --split-set <judge-split-set-id> --split judge-test --json
300
+
301
+ orizu scorers exec --project <team/project> --scorer-version <kappa-scorer-version-id> --subject-version <judge-version-id> --dataset-version <dataset-version-id> --split-set <judge-split-set-id> --split judge-test --dependency-score-run judge=<row-score-run-id> --out ./judge-test-alignment.json --json
118
302
  ```
119
- TPR = (judge says fail AND human says fail) / (human says fail)
120
- TNR = (judge says pass AND human says pass) / (human says pass)
303
+
304
+ Inspect the submitted set score run, not only the local file. The stored evidence
305
+ must identify the submitted row-score dependency and contain measured row
306
+ evidence from which kappa, TPR, TNR, and the confusion matrix can be checked.
307
+ Store the separately computed scenario-class slices beside it. Record every
308
+ achieved value beside the agreed judge trust bar. Both `scores submit` and the submitting
309
+ `scorers exec` store `agent_reported` evidence, which is never
310
+ execution-verified. Hand the resulting set `<score-run-id>` to a human curator
311
+ for acceptance:
312
+
313
+ ```bash
314
+ # Human-only handoff: the agent prepares this exact command; the curator runs it.
315
+ orizu scores accept <score-run-id> --project <team/project> --json
121
316
  ```
122
317
 
123
- **Targets: TPR > 90% AND TNR > 90%.**
318
+ J5 — Build & validate judges is complete only when every gating judge clears its
319
+ agreed judge trust bar, the scorer versions are registered, `runners exec`, `scores submit`,
320
+ and the measured `scorers exec` run have all succeeded, and the human curator has
321
+ accepted that score run. Gate decisions only on accepted evidence. A locally
322
+ computed alignment report with no accepted Orizu score run does not clear the
323
+ trust bar.
324
+
325
+ Re-run this evidence path after labels, judge instructions, runners, or scorer
326
+ definitions change. Builtin set scorers, their dependency mapping, and aggregate
327
+ submission behavior are specified in `prompt-control-plane.md`.
328
+
329
+ ## Optimize the judge instructions with GEPA
330
+
331
+ Judge building is itself an optimization problem. Optimize the LLM judge's own
332
+ instructions against human labels; do not optimize it against its own previous
333
+ decisions.
334
+
335
+ Manage a composite judge as one `orizu instructions` instruction set. Components
336
+ can separate the rubric, boundary examples, output contract, and failure-mode
337
+ rules, while the complete component map remains the candidate. The candidate
338
+ runner executes those candidate judge instructions on human-labeled train and
339
+ validation rows. The row-mode alignment scorer compares the binary candidate
340
+ decision with the human label and returns per-row feedback for reflection.
341
+
342
+ Materialize those components in `orizu.instruction-set.json` before GEPA. Create
343
+ the stable instruction set once, or push a revised seed for a later optimization
344
+ cycle. `SKILL.md` is authoritative for who runs each mutation; hosted sessions
345
+ prepare the manifest and exact human handoff:
346
+
347
+ ```bash
348
+ # Local surface (agent-allowed under the user's token): see the SKILL.md authority map.
349
+ orizu instructions create ./evals/<project>/judges/<failure-mode>/orizu.instruction-set.json --project <team/project> --model-config <provider/model> --json
350
+
351
+ # Local surface (agent-allowed under the user's token): see the SKILL.md authority map.
352
+ orizu instructions push ./evals/<project>/judges/<failure-mode>/orizu.instruction-set.json --project <team/project> --set <judge-instruction-set> --json
353
+ ```
124
354
 
125
- Why both: a judge that flags everything has TPR=100% and a useless TNR. A judge that passes everything is the inverse. Both matter; track them separately.
355
+ Use the instruction-set name returned by `create`, or the stable set named by
356
+ `push`, as `<judge-instruction-set>` below.
126
357
 
127
- If TPR is low → judge is missing failures. Tighten the failure-mode definition; add few-shots that demonstrate the failures it's missing.
358
+ In that same local workflow, push the optimizer implementation, then run GEPA
359
+ against that judge instruction set and one model-config profile:
128
360
 
129
- If TNR is low → judge is over-flagging. Loosen overly broad criteria; add few-shots of edge-case passes.
361
+ ```bash
362
+ orizu runners push ./evals/<project>/judges/<failure-mode>/alignment-runner --project <team/project> --name <alignment-runner-name> --json
130
363
 
131
- ### Step 4: Final test
364
+ orizu scorers register --project <team/project> --name <alignment-row-scorer-name> --manifest ./evals/<project>/judges/<failure-mode>/alignment-row-scorer.manifest.json --runner-version <alignment-runner-version-id> --json
132
365
 
133
- Run the judge once on the held-out test set. If TPR/TNR drops more than a few points vs. dev, you overfit to dev — go back, regenerate dev/test split, retry. **Don't iterate on the test set.**
366
+ orizu optimizers push ./evals/<project>/judge-optimizer --project <team/project> --name <judge-optimizer-name> --json
134
367
 
135
- ### Step 5: Use the judge
368
+ orizu optimizations run-gepa --project <team/project> --optimizer-version-id <optimizer-version-id> --instruction-set <judge-instruction-set> --model-config <provider/model> --component-selector all --runner-version-id <judge-runner-version-id> --candidate-runner-dir ./evals/<project>/judges/<failure-mode>/runner --scorer-version-id <alignment-row-scorer-version-id> --scorer-runner-version-id <alignment-runner-version-id> --scorer-runner-dir ./evals/<project>/judges/<failure-mode>/alignment-runner --scorer-input-contract gepa --dataset-version-id <dataset-version-id> --split-set-id <judge-split-set-id> --train-split train --val-split validation --engine official --budget medium --reflection-max-tokens <n> --log-dir logs/judge-gepa
369
+ ```
136
370
 
137
- Run the validated judge over future outputs to score them. Wire it into:
138
- - CI/CD on a curated test set (block merges that drop pass rate)
139
- - Online monitoring on sampled traffic (alert on regressions)
140
- - Optimization loop as a metric (`optimization-with-gepa.md`)
141
- - Orizu scorers and score runs (`prompt-control-plane.md`) so prompt detail, changelog, scorer detail, and optimization surfaces show comparable performance.
371
+ `round-robin` is the default component selector and updates one mutable component
372
+ per round. The walkthrough explicitly chooses `--component-selector all`, the
373
+ alternative that updates every mutable component for a candidate. One run
374
+ accepts one alignment scorer, so report each failure mode against its own agreed
375
+ bar; an aggregate optimization score cannot waive a regression.
376
+ Every component passed to judge GEPA must be inline and materialized; the
377
+ official connector refuses an instruction set profile with pinned components.
378
+ Keep judge-test outside GEPA. The command records the best candidate and
379
+ local logs; it does not push a new judge or instruction set version.
380
+
381
+ After a human accepts the optimized components, materialize the complete map in
382
+ `orizu.instruction-set.json`. Read
383
+ `<printed-local-log-directory>/result.json`; `--log-dir` names a root and the
384
+ logger appends the optimization run ID, so use the directory printed by the
385
+ completed run rather than joining the root directly to the filename. For a
386
+ one-component candidate, `best_candidate_text` is a bare string: copy it to
387
+ that one component. For a multi-component candidate, `best_candidate_text` is
388
+ the complete component map; require it to cover the instruction set's complete
389
+ shape and copy that accepted map into the manifest. There is no separate
390
+ component-to-judge materializer command. The judge runner's own file layout is
391
+ the materializer: write every accepted component value, byte for byte, to the
392
+ exact instruction file that the runner project's manifest maps to that
393
+ component. That mapping is a project-specific runner contract, not a standard
394
+ Orizu runner-manifest field. Then use the runner's deterministic composition
395
+ rule to update the single primary body in `judge/` from those same files.
396
+
397
+ Those file changes produce new runner bytes. Under the user's token, push them
398
+ as a fresh runner version before parity; `runners exec --runner-dir` verifies
399
+ the directory against its registered version and will not execute an altered
400
+ copy of the old version:
401
+
402
+ ```bash
403
+ orizu runners push ./evals/<project>/judges/<failure-mode>/runner --project <team/project> --name <judge-runner-name> --json
404
+ ```
142
405
 
143
- ## Set scorers for judge-vs-gold agreement
406
+ The judge runner resolves instruction text from the input
407
+ `instruction_set.components` when present, as GEPA candidate execution requires,
408
+ and otherwise from its bundled instruction files—never from server
409
+ `prompt.body`. The parity exec-context therefore carries the superseded server
410
+ `prompt.body` by design; when candidate `instruction_set.components` are absent,
411
+ the runner's bundled, materialized files are what execute.
144
412
 
145
- Use a set scorer when the meaningful metric is only defined over a batch, not one row. Cohen's kappa is the recommended headline for binary judge-vs-human agreement because it corrects for label imbalance and has a chance-agreement zero point.
413
+ Parity-check that new runner version on a small existing development /
414
+ validation split containing a handful of row IDs evaluated for the winning
415
+ candidate:
146
416
 
147
- For a binary `ok` / `flag` judge:
148
- - Register the headline scorer as `mode: "set"`, `metric_key: "cohens_kappa"`, `score_format: "number"`, and `higher_is_better: true`.
149
- - Set `implementation_kind: "builtin_metric"`, `builtin_metric: "cohens_kappa"`, an explicit `input_mapping`, and `builtin_metric_config.positive_class: "flag"`.
150
- - Execute with `orizu scorers exec` when row-scorer results are available as a stored score run or local JSONL.
151
- - Include `accuracy`, `sample_size`, a confusion matrix, and per-class precision/recall in diagnostics.
152
- - Treat `flag` as the positive class by default, so `tp` means human=`flag` and judge=`flag`, `fn` means human=`flag` and judge=`ok`, `fp` means human=`ok` and judge=`flag`, and `tn` means human=`ok` and judge=`ok`.
153
- - Include `flag_recall` prominently because it answers whether the judge catches the failures humans care about.
154
- - On small validation sets, call out uncertainty in `feedbackSummary` rather than over-interpreting a single kappa point estimate.
417
+ ```bash
418
+ orizu runners exec --prompt-version <current-judge-version-id> --runner-version <materialized-judge-runner-version-id> --dataset-version <dataset-version-id> --split-set <parity-split-set-id> --split <parity-split-name> --runner-dir ./evals/<project>/judges/<failure-mode>/runner --out ./accepted-judge-parity.jsonl
419
+ ```
155
420
 
156
- Recommended diagnostics shape:
421
+ Match those row IDs to the winning candidate's entries in
422
+ `<printed-local-log-directory>/evaluations.jsonl` and compare each recorded `output` with the
423
+ parity run's normalized parsed judge decision. Preserve the winning run's model
424
+ settings; an unexplained decision mismatch means the accepted map was not
425
+ reproduced and blocks publication. Orizu has no profile-capable validation
426
+ surface today; this local runner parity check is required before reducing the
427
+ component map to the composed primary body that `judges push` publishes.
157
428
 
158
- ```json
159
- {
160
- "sample_size": 15,
161
- "accuracy": 0.73,
162
- "confusion_matrix": {
163
- "tp": 5,
164
- "fn": 1,
165
- "fp": 3,
166
- "tn": 6,
167
- "positive_class": "flag"
168
- },
169
- "flag_recall": 0.83,
170
- "flag_precision": 0.63,
171
- "ok_recall": 0.67,
172
- "ok_precision": 0.86,
173
- "class_balance": {
174
- "human_flag": 6,
175
- "human_ok": 9
176
- }
177
- }
429
+ Only after parity holds, publish fresh instruction and judge versions before
430
+ touching judge-test. Under the user's token, the local sequence is:
431
+
432
+ ```bash
433
+ # Local surface (agent-allowed under the user's token): see the SKILL.md authority map.
434
+ orizu instructions push ./evals/<project>/judges/<failure-mode>/orizu.instruction-set.json --project <team/project> --set <judge-instruction-set> --json
435
+
436
+ orizu judges push ./evals/<project>/judges/<failure-mode>/judge --project <team/project> --runner-version <materialized-judge-runner-version-id> --json
437
+
438
+ orizu scorers register --project <team/project> --name <row-scorer-name> --manifest ./evals/<project>/judges/<failure-mode>/row-scorer.manifest.json --prompt-version <new-judge-version-id> --runner-version <materialized-judge-runner-version-id> --json
178
439
  ```
179
440
 
180
- ## Saturation check
441
+ Update `kappa-scorer.manifest.json` so the `judge` dependency's
442
+ `dependencies[].scorer_version_id` is `<new-row-scorer-version-id>`, then
443
+ register a new set-scorer version before supplying that dependency run:
181
444
 
182
- If your judge eventually reports 100% pass on a test set, the eval is **saturated** — it's no longer finding failures. That's not victory; it means you need harder cases. Sample fresh production traces, look for ones the current system handles ambiguously, and add them.
445
+ ```bash
446
+ orizu scorers register --project <team/project> --name <kappa-scorer-name> --manifest ./evals/<project>/judges/<failure-mode>/kappa-scorer.manifest.json --json
183
447
 
184
- ## Storing judges
448
+ orizu runners exec --scorer-version <new-row-scorer-version-id> --dataset-version <dataset-version-id> --split-set <judge-split-set-id> --split judge-test --runner-dir ./evals/<project>/judges/<failure-mode>/runner --out ./new-judge-test-results.jsonl
185
449
 
186
- Treat each judge as code under version control, and push the runnable Orizu representation when using the control plane:
450
+ orizu scores submit ./new-judge-test-results.jsonl --project <team/project> --scorer-version <new-row-scorer-version-id> --subject-version <new-judge-version-id> --dataset-version <dataset-version-id> --split-set <judge-split-set-id> --split judge-test --json
187
451
 
188
- ```
189
- evals/
190
- <project>/
191
- judges/
192
- escalated_when_required.py # the judge function
193
- escalated_when_required.test.py# TPR/TNR test against the held-out export
194
- labels.jsonl # the export this was validated on
195
- README.md # what failure mode, what the threshold story is
452
+ orizu scorers exec --project <team/project> --scorer-version <new-kappa-scorer-version-id> --subject-version <new-judge-version-id> --dataset-version <dataset-version-id> --split-set <judge-split-set-id> --split judge-test --dependency-score-run judge=<new-row-score-run-id> --out ./new-judge-test-alignment.json --json
453
+
454
+ # Human-only handoff: the agent prepares this exact command; the curator runs it.
455
+ orizu scores accept <new-set-score-run-id> --project <team/project> --json
196
456
  ```
197
457
 
198
- For Orizu-managed workflows:
199
-
200
- 1. Push the runner with `orizu runners push`.
201
- 2. Push the LLM judge prompt with `orizu judges push` when applicable.
202
- 3. Register the scorer with `orizu scorers register`.
203
- 4. For row scorers, execute the scorer runner with `orizu runners exec --scorer-version ...` and submit row results with `orizu scores submit`.
204
- 5. For builtin set scorers, execute with `orizu scorers exec`; for locally precomputed set scores, submit the aggregate object with `orizu scores submit --aggregate`.
205
-
206
- When you re-export labels (e.g. after annotating more data), re-run validation. Judges and scorers drift as the system and data drift; periodic revalidation catches it.
207
-
208
- ## Reusing a judge runner in GEPA optimization
209
-
210
- A judge runner you built for flat-row score runs (`runners exec
211
- --scorer-version`: flat dataset row + `model_output`) does NOT natively speak
212
- GEPA's scorer-runner contract (`row` = `{source_row, candidate_id,
213
- candidate_output, …}`). Fed the GEPA shape it sees an empty output and
214
- silently scores everything 0.
215
-
216
- You do not need to write an adapter runner. When wiring the judge into
217
- `orizu optimizations run-gepa`, pass `--scorer-input-contract flat_row`, and
218
- `--scorer-candidate-field <row-field>` if your judge reads the candidate
219
- output from a named row field (e.g. `draft`). Runners you author from now on
220
- can also self-describe with `"scorer_input_contract"` and
221
- `"candidate_output_field"` in `manifest.json`. `run-gepa` additionally
222
- validates the contract against the seed at launch and fails loudly on a
223
- uniformly-worst seed. Details: `prompt-control-plane.md`
224
- ("Scorer-Runner Input Contracts").
225
-
226
- ## Checklist
227
-
228
- Before declaring a judge production-ready:
229
-
230
- - [ ] Failure mode is specific and binary (not "overall quality")
231
- - [ ] Code assertion attempted first; LLM judge only if rule-shaping wasn't enough
232
- - [ ] If LLM judge: prompt has clear pass/fail criteria + 4–8 stratified few-shots
233
- - [ ] Train / dev / test split (20 / 40 / 40)
234
- - [ ] TPR > 90% AND TNR > 90% on test
235
- - [ ] Stored in version control alongside the labels it was validated on
236
- - [ ] If using Orizu control plane, scorer registered with readable metric name, direction, mode, and dataset requirements
458
+ The materialized `runners push` must return a fresh runner version. `judges push`
459
+ must return a new judge version (and therefore a new prompt version), and the
460
+ two `scorers register` commands must return row- and set-scorer versions bound
461
+ through the new runner and updated dependency.
462
+ The instruction-set/profile version is not a valid `--subject-version`; both
463
+ submitted judge-test commands above deliberately use `<new-judge-version-id>`.
464
+ Require human acceptance and gatekeeper-grade judge-test validation for any ship
465
+ or promotion decision even when the judge used for reflection met only the
466
+ optimization-signal judge trust bar. Hosted sessions commit the accepted component map and
467
+ follow the handoff boundary in `SKILL.md`.
468
+
469
+ The default GEPA scorer contract supplies a GEPA-shaped row containing
470
+ `source_row`, `candidate_id`, and `candidate_output`. If reusing a scorer runner
471
+ built for flat score-run rows, pass `--scorer-input-contract flat_row` and, when
472
+ the output belongs in a named row field, `--scorer-candidate-field <row-field>`.
473
+ A runner manifest can instead declare `scorer_input_contract` and
474
+ `candidate_output_field`. The CLI validates the active contract on the seed and
475
+ refuses a uniformly worst seed by default. Read “Scorer-Runner Input Contracts”
476
+ in `prompt-control-plane.md` before choosing either contract.
477
+
478
+ ## Exit criterion checklist
479
+
480
+ - [ ] Each failure mode is binary and has adequate positive and negative rows.
481
+ - [ ] Human–human kappa is computed from multiply labeled rows; low agreement
482
+ routes back to rubric and label repair.
483
+ - [ ] Kappa, TPR, TNR, confusion matrix, sample size, class balance, and
484
+ scenario-class results are reported per failure mode.
485
+ - [ ] The agent taught the decision-class tradeoffs, the user chose each
486
+ judge trust bar, and the agreed value is recorded in the output.
487
+ - [ ] Development rows were used for iteration and judge-test was used only
488
+ after the candidate was frozen.
489
+ - [ ] The application final-held-out partition was excluded from all judge
490
+ material and is reserved for one accepted-judge scoring pass at J6.
491
+ - [ ] The versioned judge and runners are stored; row and set scorers are
492
+ registered.
493
+ - [ ] `runners exec` evidence was submitted with `scores submit`, and a measured
494
+ `scorers exec` result was submitted, inspected, and accepted by a human
495
+ curator before gating decisions.
496
+ - [ ] Any GEPA judge optimization targeted the judge's own complete instruction
497
+ set against human labels, followed by gatekeeper-grade judge-test
498
+ validation.