@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.
- package/.claude/skills/mutagent-evaluator/SKILL.md +28 -30
- package/.claude/skills/mutagent-evaluator/assets/agents/dataset-builder.md +6 -5
- package/.claude/skills/mutagent-evaluator/assets/agents/evaluator.md +93 -30
- package/.claude/skills/mutagent-evaluator/assets/code-quality-criteria.yaml +75 -0
- package/.claude/skills/mutagent-evaluator/assets/templates/discover-report.template.html +397 -0
- package/.claude/skills/mutagent-evaluator/assets/templates/eval-report.template.html +594 -0
- package/.claude/skills/mutagent-evaluator/assets/templates/review-report.template.html +560 -0
- package/.claude/skills/mutagent-evaluator/golden/judge-trajectory.prose.md +69 -0
- package/.claude/skills/mutagent-evaluator/lenses/methodology-critic-lens.md +1 -1
- package/.claude/skills/mutagent-evaluator/references/data-registry.md +43 -0
- package/.claude/skills/mutagent-evaluator/references/edd-loop.md +6 -6
- package/.claude/skills/mutagent-evaluator/references/eval-layers.md +52 -0
- package/.claude/skills/mutagent-evaluator/references/eval-stage.md +37 -4
- package/.claude/skills/mutagent-evaluator/references/memory-format.md +1 -1
- package/.claude/skills/mutagent-evaluator/schemas/methodology-review.schema.yaml +1 -1
- package/.claude/skills/mutagent-evaluator/scripts/agent-dispatch.ts +0 -0
- package/.claude/skills/mutagent-evaluator/scripts/aggregate-discover.ts +254 -9
- package/.claude/skills/mutagent-evaluator/scripts/audience.ts +84 -0
- package/.claude/skills/mutagent-evaluator/scripts/build-review-ui.ts +320 -6
- package/.claude/skills/mutagent-evaluator/scripts/cli/prep.ts +32 -2
- package/.claude/skills/mutagent-evaluator/scripts/cli/profile-subject.ts +1 -1
- package/.claude/skills/mutagent-evaluator/scripts/code-eval-library.ts +201 -0
- package/.claude/skills/mutagent-evaluator/scripts/code-quality-verdict.ts +60 -68
- package/.claude/skills/mutagent-evaluator/scripts/config/schema.ts +3 -3
- package/.claude/skills/mutagent-evaluator/scripts/contracts/agentspec-evals.ts +101 -39
- package/.claude/skills/mutagent-evaluator/scripts/contracts/eval-matrix.ts +326 -3
- package/.claude/skills/mutagent-evaluator/scripts/contracts/eval-types.ts +30 -4
- package/.claude/skills/mutagent-evaluator/scripts/determine-outcome.ts +8 -0
- package/.claude/skills/mutagent-evaluator/scripts/edd/change-request.ts +1 -1
- package/.claude/skills/mutagent-evaluator/scripts/edd/edd-types.ts +2 -2
- package/.claude/skills/mutagent-evaluator/scripts/judge-prompt-template.ts +144 -15
- package/.claude/skills/mutagent-evaluator/scripts/materialize-dataset.ts +130 -68
- package/.claude/skills/mutagent-evaluator/scripts/matrix-judge.ts +219 -1
- package/.claude/skills/mutagent-evaluator/scripts/memory/append.ts +1 -1
- package/.claude/skills/mutagent-evaluator/scripts/memory/ratify.ts +165 -0
- package/.claude/skills/mutagent-evaluator/scripts/merge-criteria.ts +849 -0
- package/.claude/skills/mutagent-evaluator/scripts/prep-tasks.ts +15 -4
- package/.claude/skills/mutagent-evaluator/scripts/read-manifest.ts +120 -0
- package/.claude/skills/mutagent-evaluator/scripts/read-unitf-traces.ts +34 -2
- package/.claude/skills/mutagent-evaluator/scripts/render-build-cards.ts +37 -0
- package/.claude/skills/mutagent-evaluator/scripts/render-discover-report-v3.ts +1155 -0
- package/.claude/skills/mutagent-evaluator/scripts/render-eval-report-v3.ts +610 -0
- package/.claude/skills/mutagent-evaluator/scripts/render-eval-report.ts +11 -92
- package/.claude/skills/mutagent-evaluator/scripts/render-review-report-v3.ts +691 -0
- package/.claude/skills/mutagent-evaluator/scripts/report-fragments.ts +173 -0
- package/.claude/skills/mutagent-evaluator/scripts/route-failures.ts +12 -9
- package/.claude/skills/mutagent-evaluator/scripts/run-evaluate.ts +46 -1
- package/.claude/skills/mutagent-evaluator/scripts/run-pipeline.ts +39 -4
- package/.claude/skills/mutagent-evaluator/scripts/run-review.ts +266 -0
- package/.claude/skills/mutagent-evaluator/scripts/subject-profile.ts +82 -0
- package/.claude/skills/mutagent-evaluator/scripts/sync-eval-criteria.ts +2 -2
- package/.claude/skills/mutagent-evaluator/scripts/unitf-to-evaltrace.ts +64 -21
- package/.claude/skills/mutagent-evaluator/scripts/verify-render.ts +728 -0
- package/bin/mutagent-cli.mjs +9 -5
- package/package.json +2 -2
|
@@ -91,6 +91,15 @@ export const MatrixCriterionSchema = Type.Object(
|
|
|
91
91
|
]),
|
|
92
92
|
/** the 3-dimension MECE coverage tag (optional context for the judge). */
|
|
93
93
|
dimension: Type.Optional(Type.String()),
|
|
94
|
+
/**
|
|
95
|
+
* WHICH evidence layer this criterion binds to (the v3 layered walk's own
|
|
96
|
+
* taxonomy): a judge-walk layer id (`"L0".."L4"`), a discover-proposed
|
|
97
|
+
* MetricLevel (`"output" | "context" | "cross-stage"`), or the criteria
|
|
98
|
+
* super-layer (`"criteria"`) for a cross-cutting check. ADDITIVE/OPTIONAL —
|
|
99
|
+
* absent ⇒ renderers default to `"criteria"` (byte-stable pre-v3 rows).
|
|
100
|
+
* Tolerant free string for forward-compat; consumers map to LAYER_NAMES.
|
|
101
|
+
*/
|
|
102
|
+
layer: Type.Optional(Type.String()),
|
|
94
103
|
/** what the judge should read for this row (write-judge-prompt "choose what to pass"). */
|
|
95
104
|
judgeInputs: Type.Optional(Type.Array(Type.String({ minLength: 1 }))),
|
|
96
105
|
// ── T1 (B-U3) tier-0 router (ADDITIVE, OPTIONAL — grandfather) ──────────────
|
|
@@ -138,6 +147,7 @@ export function minedToMatrixCriterion(c: MinedCriterion): MatrixCriterion {
|
|
|
138
147
|
passCondition: c.statement,
|
|
139
148
|
severity: c.metadata.severity,
|
|
140
149
|
dimension: c.metadata.dimension,
|
|
150
|
+
layer: c.metadata.level,
|
|
141
151
|
checkMethod: c.metadata.check_method,
|
|
142
152
|
...(judgeInputs.length > 0 ? { judgeInputs } : {}),
|
|
143
153
|
...(c.codeEval !== undefined ? { codeEval: c.codeEval } : {}),
|
|
@@ -184,6 +194,41 @@ export type SubjectProfileProvenanceValue =
|
|
|
184
194
|
* harness/skill marked UNKNOWN, never confabulated). */
|
|
185
195
|
export const PROFILE_UNKNOWN = "unknown" as const;
|
|
186
196
|
|
|
197
|
+
// ── EV-5 — tool reversibility (does a tool take an IRREVERSIBLE EXTERNAL action?) ─
|
|
198
|
+
//
|
|
199
|
+
// A routing failure that only READS is materially less severe than one that also
|
|
200
|
+
// sends an email or mutates a live system — but nothing surfaced "this session could
|
|
201
|
+
// take irreversible external actions." This classifies each subject tool so the judge
|
|
202
|
+
// preamble can flag it. HONEST: `unknown` when the tool's effect can't be established
|
|
203
|
+
// (never confabulated), never coerced to a false "reversible".
|
|
204
|
+
export const ToolReversibility = {
|
|
205
|
+
/** a pure/no-op tool (no external effect). */
|
|
206
|
+
None: "none",
|
|
207
|
+
/** an external action that can be undone / re-run safely (a read, an idempotent write). */
|
|
208
|
+
Reversible: "reversible",
|
|
209
|
+
/** an external action that CANNOT be undone (send/email/charge/delete/deploy/post). */
|
|
210
|
+
IrreversibleExternal: "irreversible-external",
|
|
211
|
+
/** the tool's effect can't be established from the inputs — flagged, never guessed. */
|
|
212
|
+
Unknown: "unknown",
|
|
213
|
+
} as const;
|
|
214
|
+
export type ToolReversibilityValue =
|
|
215
|
+
(typeof ToolReversibility)[keyof typeof ToolReversibility];
|
|
216
|
+
|
|
217
|
+
/** One tool's reversibility classification (EV-5). */
|
|
218
|
+
export const ToolReversibilitySchema = Type.Object(
|
|
219
|
+
{
|
|
220
|
+
name: Type.String({ minLength: 1 }),
|
|
221
|
+
reversibility: Type.Union([
|
|
222
|
+
Type.Literal(ToolReversibility.None),
|
|
223
|
+
Type.Literal(ToolReversibility.Reversible),
|
|
224
|
+
Type.Literal(ToolReversibility.IrreversibleExternal),
|
|
225
|
+
Type.Literal(ToolReversibility.Unknown),
|
|
226
|
+
]),
|
|
227
|
+
},
|
|
228
|
+
{ additionalProperties: false },
|
|
229
|
+
);
|
|
230
|
+
export type ToolReversibilityEntry = Static<typeof ToolReversibilitySchema>;
|
|
231
|
+
|
|
187
232
|
export const SubjectProfileSchema = Type.Object(
|
|
188
233
|
{
|
|
189
234
|
/** what the agent IS (name / role identity). */
|
|
@@ -195,6 +240,10 @@ export const SubjectProfileSchema = Type.Object(
|
|
|
195
240
|
purpose: Type.String({ minLength: 1 }),
|
|
196
241
|
/** the tools the agent wields (GIVEN inventory or reconstructed from the trace batch). */
|
|
197
242
|
tools: Type.Array(Type.String({ minLength: 1 })),
|
|
243
|
+
/** EV-5 — per-tool reversibility (none · reversible · irreversible-external · unknown)
|
|
244
|
+
* so the judge sees which tools take IRREVERSIBLE EXTERNAL actions BEFORE it weighs a
|
|
245
|
+
* failure. ADDITIVE/OPTIONAL: absent ⇒ the judge reads the bare tool list. */
|
|
246
|
+
toolReversibility: Type.Optional(Type.Array(ToolReversibilitySchema)),
|
|
198
247
|
/** the skill the agent runs under, when known (`unknown` ≠ confabulated). */
|
|
199
248
|
skill: Type.Optional(Type.String()),
|
|
200
249
|
/** the agent's responsibility boundary / scope. */
|
|
@@ -242,6 +291,14 @@ export const MatrixPacketSchema = Type.Object(
|
|
|
242
291
|
{ model: Type.String({ minLength: 1 }), temperature: Type.Literal(0) },
|
|
243
292
|
{ additionalProperties: false },
|
|
244
293
|
),
|
|
294
|
+
/**
|
|
295
|
+
* v3 LAYERED WALK (D1=B+) — layer-scope filter for the pipeable
|
|
296
|
+
* `*evaluate-<layer>` commands: absent/empty = the FULL walk (L0→L4 +
|
|
297
|
+
* criteria); a subset = the judge runs ONLY those layer phases (criteria
|
|
298
|
+
* still verdicted over whatever those phases gather — never left
|
|
299
|
+
* unverdicted). ADDITIVE/OPTIONAL: legacy packets still validate.
|
|
300
|
+
*/
|
|
301
|
+
layerScope: Type.Optional(Type.Array(Type.String({ minLength: 1 }))),
|
|
245
302
|
},
|
|
246
303
|
{ additionalProperties: false },
|
|
247
304
|
);
|
|
@@ -353,7 +410,9 @@ export type ExpectedStep = Static<typeof ExpectedStepSchema>;
|
|
|
353
410
|
export const AgentStepSchema = Type.Object(
|
|
354
411
|
{
|
|
355
412
|
n: Type.Number(),
|
|
356
|
-
|
|
413
|
+
/** TOLERANT: explicit `null` = an honest "no tool call this step" (live-judge shape
|
|
414
|
+
* on a zero-tool trajectory) — distinct from an omitted field. */
|
|
415
|
+
tool: Type.Optional(Type.Union([Type.String(), Type.Null()])),
|
|
357
416
|
/** ok | error | warn | false-success */
|
|
358
417
|
status: Type.Optional(Type.String()),
|
|
359
418
|
detail: Type.Optional(Type.String()),
|
|
@@ -409,6 +468,139 @@ export const CandidateItemSchema = Type.Object(
|
|
|
409
468
|
);
|
|
410
469
|
export type CandidateItem = Static<typeof CandidateItemSchema>;
|
|
411
470
|
|
|
471
|
+
// ── v3 LAYERED WALK (E-NEW-1..6,9 — ADDITIVE, OPTIONAL) ──────────────────────
|
|
472
|
+
// Evaluator-v3 contract (operator-frozen 2026-07-24): ONE judge per trajectory
|
|
473
|
+
// performs the whole evidence-layer walk internally — L0 code checks → L1
|
|
474
|
+
// outcome → (descend per stopping rules) L2 trajectory → L3 tool outputs → L4
|
|
475
|
+
// context — and EMITS one LayerVerdict per engaged layer alongside the
|
|
476
|
+
// (unchanged) per-criterion verdicts. Cross-layer disagreement is SIGNAL:
|
|
477
|
+
// aggregate DETECTS conflicts, never resolves them (D2-A / OT-1). All fields
|
|
478
|
+
// OPTIONAL (grandfather): pre-v3 verdict files still validate; renderers show
|
|
479
|
+
// NAMED degrade badges, never silent blanks.
|
|
480
|
+
|
|
481
|
+
/** The five evidence layers of the walk. */
|
|
482
|
+
export const LayerId = {
|
|
483
|
+
Code: "L0",
|
|
484
|
+
Outcome: "L1",
|
|
485
|
+
Trajectory: "L2",
|
|
486
|
+
ToolOutputs: "L3",
|
|
487
|
+
Context: "L4",
|
|
488
|
+
} as const;
|
|
489
|
+
export type LayerIdValue = (typeof LayerId)[keyof typeof LayerId];
|
|
490
|
+
export const LAYER_IDS: readonly string[] = Object.values(LayerId);
|
|
491
|
+
|
|
492
|
+
/** Human names — the vocabulary reports print beside the L-codes. */
|
|
493
|
+
export const LAYER_NAMES: Record<string, string> = {
|
|
494
|
+
L0: "code checks",
|
|
495
|
+
L1: "outcome",
|
|
496
|
+
L2: "trajectory",
|
|
497
|
+
L3: "tool outputs",
|
|
498
|
+
L4: "context",
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
/** One per-layer verdict from the walk (E-NEW-1). `skipped` marks layers the
|
|
502
|
+
* stopping rules never engaged (early-exit) — skipped ≠ undecidable. */
|
|
503
|
+
export const LayerVerdictSchema = Type.Object(
|
|
504
|
+
{
|
|
505
|
+
/** L0 | L1 | L2 | L3 | L4 (tolerant free string for forward-compat). */
|
|
506
|
+
layer: Type.String({ minLength: 1 }),
|
|
507
|
+
verdict: Type.Union([
|
|
508
|
+
Type.Literal("pass"),
|
|
509
|
+
Type.Literal("fail"),
|
|
510
|
+
Type.Literal("undecidable"),
|
|
511
|
+
Type.Literal("skipped"),
|
|
512
|
+
/** L0 EVIDENCE-STATE (live-judge shape): patterns fired, evidence recorded —
|
|
513
|
+
* honoring the meta-judge fence a pass/fail on L0 would violate (a fired
|
|
514
|
+
* pattern is a candidate, not a verdict). L0-specific. */
|
|
515
|
+
Type.Literal("fired"),
|
|
516
|
+
/** L0 CLEAN-STATE (live-judge shape): the library RAN and NO pattern fired.
|
|
517
|
+
* Distinct from `pass` (a pass would assert L0 proved the layer correct) and
|
|
518
|
+
* from `skipped` (the library did run). "no code-detectable candidate" — an
|
|
519
|
+
* honest clean, never a verdict on the deeper layers. */
|
|
520
|
+
Type.Literal("no-fires"),
|
|
521
|
+
]),
|
|
522
|
+
/** annotation-only — may NEVER flip the verdict. */
|
|
523
|
+
confidence: Type.Optional(Type.Number()),
|
|
524
|
+
/** grounding citations (same tolerant shape as judge-step refs). */
|
|
525
|
+
refs: Type.Optional(Type.Array(Type.Union([Type.String(), GaRefSchema]))),
|
|
526
|
+
/** one-breath reasoning for THIS layer's verdict. */
|
|
527
|
+
note: Type.Optional(Type.String()),
|
|
528
|
+
/** L1: the classified scenario (STRUCTURED, not prose — E-NEW-2). */
|
|
529
|
+
scenario: Type.Optional(Type.String()),
|
|
530
|
+
/** L1: the expected terminal actions for that scenario (E-NEW-2). */
|
|
531
|
+
expectedExit: Type.Optional(Type.Array(Type.String())),
|
|
532
|
+
/** L3: the first problematic observation — everything downstream suspect. */
|
|
533
|
+
/** TOLERANT: explicit `null` = an honest "no problem origin exists" (live-judge
|
|
534
|
+
* shape — naming one would invent it), distinct from an omitted field. */
|
|
535
|
+
firstProblemOrigin: Type.Optional(Type.Union([Type.String(), Type.Null()])),
|
|
536
|
+
/**
|
|
537
|
+
* L4: retrieval (never fetched) vs attention (present but ignored).
|
|
538
|
+
*
|
|
539
|
+
* TOLERANT-BUT-STILL-CLASSIFIED. A live judge emitted the required distinction
|
|
540
|
+
* and then QUALIFIED it — "attention (transient, non-terminal — self-corrected
|
|
541
|
+
* before send); no retrieval gap" — which the bare 2-literal union rejected.
|
|
542
|
+
* Both forms are now accepted, but deliberately NOT by loosening to a free
|
|
543
|
+
* string: the qualified form must still BEGIN with one of the two kinds, so
|
|
544
|
+
* the classification stays machine-extractable (read the leading token) and a
|
|
545
|
+
* value that classifies nothing (`"unclear"`) is still refused. Loosening to
|
|
546
|
+
* `Type.String()` would have kept this file parsing while silently forfeiting
|
|
547
|
+
* the fail-loud property the field exists for.
|
|
548
|
+
*/
|
|
549
|
+
gapKind: Type.Optional(
|
|
550
|
+
Type.Union([
|
|
551
|
+
Type.Literal("retrieval"),
|
|
552
|
+
Type.Literal("attention"),
|
|
553
|
+
Type.String({ pattern: "^(retrieval|attention)\\b" }),
|
|
554
|
+
]),
|
|
555
|
+
),
|
|
556
|
+
/**
|
|
557
|
+
* L2: the ONE-LINE statement of where the actual path left the expected path
|
|
558
|
+
* — the headline of a trajectory-layer failure, distilled out of the much
|
|
559
|
+
* longer `note`. A live judge emitted it alongside a `note` that walks the
|
|
560
|
+
* full chronological path, i.e. it is the summary a reader needs, not a
|
|
561
|
+
* duplicate: "mandatory reviewWithManager step omitted between draft
|
|
562
|
+
* generation and the terminal sendMessage".
|
|
563
|
+
*/
|
|
564
|
+
divergence: Type.Optional(Type.String()),
|
|
565
|
+
},
|
|
566
|
+
{ additionalProperties: false },
|
|
567
|
+
);
|
|
568
|
+
export type LayerVerdict = Static<typeof LayerVerdictSchema>;
|
|
569
|
+
|
|
570
|
+
/** E-NEW-6 — one L0 code-eval library hit (the judge runs the library itself). */
|
|
571
|
+
export const CodeEvalHitSchema = Type.Object(
|
|
572
|
+
{
|
|
573
|
+
/** the library pattern id (e.g. CE-P1 fault-passthrough). */
|
|
574
|
+
pattern: Type.String({ minLength: 1 }),
|
|
575
|
+
/** where it fired (obs id / step anchor). */
|
|
576
|
+
anchor: Type.Optional(Type.Union([Type.Number(), Type.String()])),
|
|
577
|
+
detail: Type.Optional(Type.String()),
|
|
578
|
+
},
|
|
579
|
+
{ additionalProperties: false },
|
|
580
|
+
);
|
|
581
|
+
export type CodeEvalHit = Static<typeof CodeEvalHitSchema>;
|
|
582
|
+
|
|
583
|
+
/** E-NEW-9b — the walk's SELF-MANIFEST of emitted vs missing emissions; AGGREGATE
|
|
584
|
+
* folds these into the MR-5 data-completeness scorecard so a skipped expected
|
|
585
|
+
* emission is caught the same run, not at render time. */
|
|
586
|
+
export const WalkEmissionsSchema = Type.Object(
|
|
587
|
+
{
|
|
588
|
+
/** emission keys the judge DID produce. */
|
|
589
|
+
emitted: Type.Array(Type.String()),
|
|
590
|
+
/** expected-but-missing keys, each with the judge's own reason. */
|
|
591
|
+
missing: Type.Optional(
|
|
592
|
+
Type.Array(
|
|
593
|
+
Type.Object(
|
|
594
|
+
{ key: Type.String({ minLength: 1 }), reason: Type.String({ minLength: 1 }) },
|
|
595
|
+
{ additionalProperties: false },
|
|
596
|
+
),
|
|
597
|
+
),
|
|
598
|
+
),
|
|
599
|
+
},
|
|
600
|
+
{ additionalProperties: false },
|
|
601
|
+
);
|
|
602
|
+
export type WalkEmissions = Static<typeof WalkEmissionsSchema>;
|
|
603
|
+
|
|
412
604
|
// ── MatrixVerdictFile — the Judge Agent OUTPUT (one per trajectory) ──────────
|
|
413
605
|
export const MatrixVerdictFileSchema = Type.Object(
|
|
414
606
|
{
|
|
@@ -469,10 +661,91 @@ export const MatrixVerdictFileSchema = Type.Object(
|
|
|
469
661
|
Type.String(),
|
|
470
662
|
Type.Object(
|
|
471
663
|
{
|
|
472
|
-
root
|
|
664
|
+
/** The primary root (root-not-symptom). REQUIRED on a structured localize —
|
|
665
|
+
* a rootless walk emits `null` (an honest "no failure to localize"), and a
|
|
666
|
+
* judge that has only a `summary` has its root FILLED from it at parse time
|
|
667
|
+
* (see the coercion below) so the invariant holds without rejecting honest
|
|
668
|
+
* output. */
|
|
669
|
+
root: Type.Union([Type.String({ minLength: 1 }), Type.Null()]),
|
|
670
|
+
/**
|
|
671
|
+
* A short SUMMARY a judge emits when there is NO failure to localize to a
|
|
672
|
+
* single root (a clean/hold trajectory with independent non-criterion
|
|
673
|
+
* deviations). Live-judge shape: instead of `root`, it summarises the whole
|
|
674
|
+
* trajectory and routes the deviations to `candidates`. Consumers coerce
|
|
675
|
+
* either to a readable band (`root` preferred, `summary` fallback).
|
|
676
|
+
*/
|
|
677
|
+
summary: Type.Optional(Type.String()),
|
|
473
678
|
symptom: Type.Optional(Type.String()),
|
|
679
|
+
/** grounding prose for the root claim (first emitted by a live D1 judge). */
|
|
680
|
+
evidence: Type.Optional(Type.String()),
|
|
681
|
+
/** the criterionIds this root OWNS (judge-emitted consolidate-by-locus hint). */
|
|
682
|
+
criteria: Type.Optional(Type.Array(Type.String())),
|
|
683
|
+
note: Type.Optional(Type.String()),
|
|
474
684
|
ref: Type.Optional(Type.Union([Type.String(), GaRefSchema])),
|
|
475
685
|
routeTo: Type.Optional(Type.String()),
|
|
686
|
+
/**
|
|
687
|
+
* FURTHER roots that are INDEPENDENT of `root` — not steps in one causal
|
|
688
|
+
* chain, but separate failures that happen to appear in the same
|
|
689
|
+
* trajectory. Emitted by a live judge following `root_not_symptom`'s
|
|
690
|
+
* "multiple INDEPENDENT roots ⇒ multiple criteria": it kept the primary
|
|
691
|
+
* root in `root` and listed the rest here rather than silently collapsing
|
|
692
|
+
* them into one locus. Consolidate-by-locus clusters on `root`; these are
|
|
693
|
+
* additional loci, so a consumer that reads only `root` UNDER-REPORTS.
|
|
694
|
+
*/
|
|
695
|
+
independentRoots: Type.Optional(Type.Array(Type.String())),
|
|
696
|
+
/**
|
|
697
|
+
* The L2 actual-vs-expected divergence. Accepted HERE as well as on the
|
|
698
|
+
* layer verdict because the OPERATOR-FROZEN judge prose explicitly says
|
|
699
|
+
* "(L2 trajectory) … emit layerVerdicts L2 (+ divergence in localize)" —
|
|
700
|
+
* so a judge obeying the contract literally puts it in this object, and
|
|
701
|
+
* the closed schema rejected exactly that. (The live D1 judge happened to
|
|
702
|
+
* put it on `layerVerdicts[L2]` instead, which is why this never fired.)
|
|
703
|
+
* Same class as the `rootCause`/`firstThingWrong` drift: contract prose
|
|
704
|
+
* naming a field the schema refuses. The prose is C-PIN golden, so the
|
|
705
|
+
* SCHEMA accepts both placements rather than churning a frozen prompt.
|
|
706
|
+
*/
|
|
707
|
+
divergence: Type.Optional(Type.String()),
|
|
708
|
+
/**
|
|
709
|
+
* An OT-1 conflict the judge surfaced UNRECONCILED (e.g. the outcome layer
|
|
710
|
+
* passes while the trajectory layer fails). Doctrine is to expose the
|
|
711
|
+
* disagreement for a human rather than have the judge resolve it, so this
|
|
712
|
+
* is prose stating both sides and explicitly declining to reconcile —
|
|
713
|
+
* frequently the single most decision-relevant field on the file.
|
|
714
|
+
*/
|
|
715
|
+
/**
|
|
716
|
+
* An OT-1 conflict the judge surfaced UNRECONCILED (e.g. the outcome layer
|
|
717
|
+
* passes while the trajectory layer fails). Doctrine is to expose the
|
|
718
|
+
* disagreement for a human rather than have the judge resolve it. TOLERANT:
|
|
719
|
+
* free prose, OR a structured {sideA, sideB, note?} pair (a live judge
|
|
720
|
+
* emitted the structured form; both carry the same meaning — two sides,
|
|
721
|
+
* explicitly not reconciled). Frequently the single most decision-relevant
|
|
722
|
+
* field on the file.
|
|
723
|
+
*/
|
|
724
|
+
conflict: Type.Optional(
|
|
725
|
+
Type.Union([
|
|
726
|
+
Type.String(),
|
|
727
|
+
Type.Object(
|
|
728
|
+
{
|
|
729
|
+
sideA: Type.String(),
|
|
730
|
+
sideB: Type.String(),
|
|
731
|
+
note: Type.Optional(Type.String()),
|
|
732
|
+
},
|
|
733
|
+
{ additionalProperties: false },
|
|
734
|
+
),
|
|
735
|
+
/** `null` = an honest "no conflict — the layers agree" (live-judge shape). */
|
|
736
|
+
Type.Null(),
|
|
737
|
+
]),
|
|
738
|
+
),
|
|
739
|
+
/**
|
|
740
|
+
* EV-051 routing prose. NOTE: this is the SAME CONCEPT as `routeTo` above,
|
|
741
|
+
* emitted under a second name by a real judge. Both are accepted because
|
|
742
|
+
* rejecting the file over a synonym is the worse failure — but do NOT add
|
|
743
|
+
* a third spelling: a closed schema carrying synonyms is how the
|
|
744
|
+
* `rootCause`/`firstThingWrong` drift started. `routeTo` currently has ZERO
|
|
745
|
+
* consumers, so consolidating onto ONE of these is a free cleanup whenever
|
|
746
|
+
* someone touches the routing path.
|
|
747
|
+
*/
|
|
748
|
+
routing: Type.Optional(Type.String()),
|
|
476
749
|
},
|
|
477
750
|
{ additionalProperties: false },
|
|
478
751
|
),
|
|
@@ -495,6 +768,13 @@ export const MatrixVerdictFileSchema = Type.Object(
|
|
|
495
768
|
]),
|
|
496
769
|
),
|
|
497
770
|
),
|
|
771
|
+
/**
|
|
772
|
+
* E-NEW additive (first emitted by a live D1 judge): per-criterion REASON a
|
|
773
|
+
* denseMap cell is `na` (`cid → why the scoping predicate is positively
|
|
774
|
+
* falsified`). `na` is the third accounting path of the completeness law —
|
|
775
|
+
* this carries its rationale so the report can display WHY, not just that.
|
|
776
|
+
*/
|
|
777
|
+
naRationale: Type.Optional(Type.Record(Type.String(), Type.String())),
|
|
498
778
|
/**
|
|
499
779
|
* §9.4.2 node 1 — the EXAMINE fidelity gate. `complete:false` means the trace
|
|
500
780
|
* was truncated / unreadable → the trajectory EXITS early as INCOMPLETE (no
|
|
@@ -508,6 +788,19 @@ export const MatrixVerdictFileSchema = Type.Object(
|
|
|
508
788
|
),
|
|
509
789
|
/** §9.4.2 node 2.5 — candidate eval/dataset items for UNMATCHED detections. */
|
|
510
790
|
candidates: Type.Optional(Type.Array(CandidateItemSchema)),
|
|
791
|
+
// ── v3 LAYERED WALK emissions (E-NEW — OPTIONAL/additive, pre-v3 files validate) ──
|
|
792
|
+
/** E-NEW-1 — one verdict per engaged evidence layer (skipped ≠ undecidable). */
|
|
793
|
+
layerVerdicts: Type.Optional(Type.Array(LayerVerdictSchema)),
|
|
794
|
+
/** E-NEW-1 — which layer (if any) the stopping rules exited at (e.g. "L1"). */
|
|
795
|
+
earlyExit: Type.Optional(Type.String()),
|
|
796
|
+
/** E-NEW-1/9 — how many layers the walk actually engaged (economy stat).
|
|
797
|
+
* TOLERANT: a count OR the engaged layer-id list (live-judge shape,
|
|
798
|
+
* e.g. ["L0","L1","L2"] — richer; consumers coerce via length). */
|
|
799
|
+
layersEngaged: Type.Optional(Type.Union([Type.Number(), Type.Array(Type.String())])),
|
|
800
|
+
/** E-NEW-6 — L0 code-eval library hits the judge recorded (it runs the library itself). */
|
|
801
|
+
codeEvalHits: Type.Optional(Type.Array(CodeEvalHitSchema)),
|
|
802
|
+
/** E-NEW-9b — the walk's self-manifest of emitted vs missing emissions (→ MR-5). */
|
|
803
|
+
emissions: Type.Optional(WalkEmissionsSchema),
|
|
511
804
|
/**
|
|
512
805
|
* the per-trajectory judge SELF-REPORTED health micro-summary. NOTE: this is
|
|
513
806
|
* IGNORED for the report's health roll-up — T4 DERIVES health from the walk
|
|
@@ -539,7 +832,9 @@ export type MatrixVerdictFile = Static<typeof MatrixVerdictFileSchema>;
|
|
|
539
832
|
export function localizeText(localize: MatrixVerdictFile["localize"]): string {
|
|
540
833
|
if (localize === undefined) return "";
|
|
541
834
|
if (typeof localize === "string") return localize;
|
|
542
|
-
|
|
835
|
+
// `null` root = an honest "no failure to localize" — the summary carries the band.
|
|
836
|
+
const root = localize.root ?? localize.summary ?? "";
|
|
837
|
+
return localize.symptom !== undefined ? `${root} (symptom: ${localize.symptom})` : root;
|
|
543
838
|
}
|
|
544
839
|
|
|
545
840
|
/**
|
|
@@ -555,6 +850,34 @@ export function parseMatrixVerdictFile(raw: string): MatrixVerdictFile {
|
|
|
555
850
|
} catch {
|
|
556
851
|
throw new Error(`parseMatrixVerdictFile: not valid JSON: ${raw.slice(0, 120)}`);
|
|
557
852
|
}
|
|
853
|
+
// COERCE the live-judge rootless-localize: a judge with NO single root to localize
|
|
854
|
+
// emits a structured localize WITHOUT `root` — carrying a `summary` (clean/hold
|
|
855
|
+
// trajectory) or a `conflict` (a real disagreement whose disagreement IS the thing to
|
|
856
|
+
// localize). Rather than weaken the contract's required-root invariant (a guard test
|
|
857
|
+
// asserts a structured localize with no root is refused), FILL the root from the
|
|
858
|
+
// summary, or from the conflict's own text, so honest rootless output is accepted AND
|
|
859
|
+
// the invariant holds. NOTHING is discarded (root takes precedence when present). A
|
|
860
|
+
// structured localize with NONE of root/summary/conflict still fails — the guard shape.
|
|
861
|
+
if (
|
|
862
|
+
parsed !== null &&
|
|
863
|
+
typeof parsed === "object" &&
|
|
864
|
+
!Array.isArray(parsed) &&
|
|
865
|
+
(parsed as Record<string, unknown>)["localize"] !== null &&
|
|
866
|
+
typeof (parsed as Record<string, unknown>)["localize"] === "object"
|
|
867
|
+
) {
|
|
868
|
+
const loc = (parsed as Record<string, unknown>)["localize"] as Record<string, unknown>;
|
|
869
|
+
if (loc["root"] === undefined) {
|
|
870
|
+
if (typeof loc["summary"] === "string") {
|
|
871
|
+
loc["root"] = loc["summary"];
|
|
872
|
+
} else if (typeof loc["conflict"] === "string") {
|
|
873
|
+
loc["root"] = loc["conflict"];
|
|
874
|
+
} else if (loc["conflict"] !== null && typeof loc["conflict"] === "object") {
|
|
875
|
+
const c = loc["conflict"] as Record<string, unknown>;
|
|
876
|
+
const parts = [c["sideA"], c["sideB"], c["note"]].filter((x): x is string => typeof x === "string");
|
|
877
|
+
if (parts.length > 0) loc["root"] = parts.join(" · ");
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
}
|
|
558
881
|
if (!Value.Check(MatrixVerdictFileSchema, parsed)) {
|
|
559
882
|
const first = [...Value.Errors(MatrixVerdictFileSchema, parsed)][0];
|
|
560
883
|
throw new Error(
|
|
@@ -642,6 +642,22 @@ export interface DiscoveryRationale {
|
|
|
642
642
|
export interface MinedCriterion extends DiscoveredCriterion {
|
|
643
643
|
metadata: MetricMetadata;
|
|
644
644
|
discovery: DiscoveryRationale;
|
|
645
|
+
/**
|
|
646
|
+
* The criterion ids ABSORBED into this one by the near-duplicate MERGE
|
|
647
|
+
* (`scripts/merge-criteria.ts`). Provenance, not a pointer: the absorbed
|
|
648
|
+
* criterion's evidence lives on THIS criterion (refs unioned, prevalence
|
|
649
|
+
* recomputed over the union), so the merge is lossless and auditable. The
|
|
650
|
+
* FIRST-SEEN id survives; every absorbed id is listed here. Absent ⇒ nothing
|
|
651
|
+
* was merged into this criterion.
|
|
652
|
+
*/
|
|
653
|
+
mergedFrom?: string[];
|
|
654
|
+
/**
|
|
655
|
+
* Alternate ids that RESOLVE to this criterion — the absorbed ids kept live so
|
|
656
|
+
* an older report, a dataset recipe or a handoff that names the pre-merge id
|
|
657
|
+
* still finds its criterion (`resolveCriterionId`). A merge must never
|
|
658
|
+
* invalidate an outstanding reference.
|
|
659
|
+
*/
|
|
660
|
+
aliases?: string[];
|
|
645
661
|
/**
|
|
646
662
|
* The EXECUTABLE code-check reference (the uniform-standard companion of the
|
|
647
663
|
* human-readable `statement`). REQUIRED when `metadata.check_method` is
|
|
@@ -848,6 +864,10 @@ export const MinedCriterionSchema = Type.Object(
|
|
|
848
864
|
supportCount: Type.Integer({ minimum: 0 }),
|
|
849
865
|
metadata: MetricMetadataSchema,
|
|
850
866
|
discovery: DiscoveryRationaleSchema,
|
|
867
|
+
/** near-duplicate MERGE provenance — the absorbed ids (first-seen id survives). */
|
|
868
|
+
mergedFrom: Type.Optional(Type.Array(Type.String({ minLength: 1 }))),
|
|
869
|
+
/** alternate ids that still RESOLVE here (an absorbed id never goes dead). */
|
|
870
|
+
aliases: Type.Optional(Type.Array(Type.String({ minLength: 1 }))),
|
|
851
871
|
/** the executable code-check reference (uniform standard); OPTIONAL at the
|
|
852
872
|
* schema layer — `lint-uniformity.ts` enforces presence by check_method. */
|
|
853
873
|
codeEval: Type.Optional(CodeEvalSpecSchema),
|
|
@@ -987,12 +1007,18 @@ function locateByObs(obs: string, traces: EvalTrace[]): EvalTrace | undefined {
|
|
|
987
1007
|
|
|
988
1008
|
/**
|
|
989
1009
|
* Read the value at a dotted `path` (e.g. `output.response`, `observations.0.output`)
|
|
990
|
-
* out of a trace. Numeric segments index arrays.
|
|
991
|
-
*
|
|
992
|
-
*
|
|
1010
|
+
* out of a trace. Numeric segments index arrays. Bracket indices are TOLERATED
|
|
1011
|
+
* (`observations[3].output` ≡ `observations.3.output` — judges naturally emit the
|
|
1012
|
+
* bracket form; a syntax preference must never manufacture a dead ref). Returns
|
|
1013
|
+
* `undefined` when ANY segment is absent (no value at that path) — the caller
|
|
1014
|
+
* treats that as UNRESOLVED. An empty path reads the whole trace object. PURE.
|
|
993
1015
|
*/
|
|
994
1016
|
function readPath(root: unknown, path: string): unknown {
|
|
995
|
-
const segments = path
|
|
1017
|
+
const segments = path
|
|
1018
|
+
.replace(/\[(\d+)\]/g, ".$1")
|
|
1019
|
+
.split(".")
|
|
1020
|
+
.map((s) => s.trim())
|
|
1021
|
+
.filter((s) => s.length > 0);
|
|
996
1022
|
let cur: unknown = root;
|
|
997
1023
|
for (const seg of segments) {
|
|
998
1024
|
if (cur === null || cur === undefined) return undefined;
|
|
@@ -39,6 +39,14 @@ import {
|
|
|
39
39
|
export type JudgeInvoke = (
|
|
40
40
|
systemPrompt: string,
|
|
41
41
|
userPrompt: string,
|
|
42
|
+
/**
|
|
43
|
+
* INF-3 — an OPTIONAL session/trace id the DETERMINER passes so its verdict is
|
|
44
|
+
* keyed per-trace: two sessions with an identical (e.g. empty) determiner prompt
|
|
45
|
+
* never collapse onto one verdict file. Absent for the per-criterion judges (their
|
|
46
|
+
* prompts are already distinct; keying salt-free keeps their hashes byte-identical,
|
|
47
|
+
* C-PIN). Both agent-dispatch seams forward it to `verdictFileName(system,user,keyId)`.
|
|
48
|
+
*/
|
|
49
|
+
keyId?: string,
|
|
42
50
|
) => Promise<string>;
|
|
43
51
|
|
|
44
52
|
// ── Event classification (the intended-goal half of the read) ───────────────
|
|
@@ -149,7 +149,7 @@ export interface EddLoopDecision {
|
|
|
149
149
|
* 1. FULL GREEN — varianceStable AND accuracyMet ⇒ DONE (success).
|
|
150
150
|
* 2. MAX SWINGS — swing ≥ budget.maxSwings ⇒ STOP (report delta).
|
|
151
151
|
* 3. MAX WALLCLOCK— elapsedMs ≥ budget.maxWallclockMs ⇒ STOP.
|
|
152
|
-
* 4. NO-
|
|
152
|
+
* 4. NO-OPTIMIZE — noImprovementStreak ≥ budget.noImprovementStreakLimit ⇒ STOP.
|
|
153
153
|
* else CONTINUE — keep swinging; the next phase is variance until it's stable,
|
|
154
154
|
* then accuracy (F19 ordering is preserved by `nextPhaseAfterVariance`, but the
|
|
155
155
|
* loop controller mirrors it: not-stable ⇒ variance, stable ⇒ accuracy).
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* scripts/edd/edd-types.ts
|
|
3
3
|
* ---------------------------------------------------------------------------
|
|
4
|
-
* Shared categorical constants + TypeBox contracts for the ADL
|
|
4
|
+
* Shared categorical constants + TypeBox contracts for the ADL OPTIMIZE stage —
|
|
5
5
|
* the Eval-Driven-Development (EDD) loop (F18 closure + F19 variance-first).
|
|
6
6
|
*
|
|
7
|
-
* EDD is the ③
|
|
7
|
+
* EDD is the ③ OPTIMIZE stage of the ADL: after the initial *build, the loop
|
|
8
8
|
* drives spec ↔ impl ↔ eval to full green. Two findings live here:
|
|
9
9
|
*
|
|
10
10
|
* F19 — VARIANCE-FIRST. The FIRST focus after the build is eliminating per-case
|