@mutagent/evaluator 0.1.0-alpha.4 → 0.1.0-alpha.6
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 +6 -5
- package/.claude/skills/mutagent-evaluator/assets/agents/evaluator.md +76 -12
- package/.claude/skills/mutagent-evaluator/assets/code-quality-criteria.yaml +75 -0
- package/.claude/skills/mutagent-evaluator/lenses/methodology-critic-lens.md +1 -1
- package/.claude/skills/mutagent-evaluator/references/edd-loop.md +6 -6
- package/.claude/skills/mutagent-evaluator/references/eval-stage.md +36 -3
- package/.claude/skills/mutagent-evaluator/references/memory-format.md +1 -1
- package/.claude/skills/mutagent-evaluator/references/operation-inventory.md +1 -0
- 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/build-review-ui.ts +320 -6
- package/.claude/skills/mutagent-evaluator/scripts/cli/audit-run.ts +6 -3
- 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-quality-verdict.ts +277 -0
- package/.claude/skills/mutagent-evaluator/scripts/config/schema.ts +3 -3
- package/.claude/skills/mutagent-evaluator/scripts/contracts/eval-matrix.ts +39 -0
- 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/memory/append.ts +1 -1
- package/.claude/skills/mutagent-evaluator/scripts/memory/ratify.ts +165 -0
- package/.claude/skills/mutagent-evaluator/scripts/persist-eval-criteria.ts +232 -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-eval-report.ts +9 -91
- package/.claude/skills/mutagent-evaluator/scripts/report-fragments.ts +173 -0
- package/.claude/skills/mutagent-evaluator/scripts/route-failures.ts +14 -4
- package/.claude/skills/mutagent-evaluator/scripts/run-deterministic.ts +114 -18
- package/.claude/skills/mutagent-evaluator/scripts/run-pipeline.ts +39 -4
- package/.claude/skills/mutagent-evaluator/scripts/subject-profile.ts +82 -0
- package/.claude/skills/mutagent-evaluator/scripts/sync-eval-criteria.ts +244 -0
- package/.claude/skills/mutagent-evaluator/scripts/unitf-to-evaltrace.ts +64 -21
- package/bin/mutagent-cli.mjs +659 -8
- package/package.json +2 -2
|
@@ -15,6 +15,17 @@
|
|
|
15
15
|
* - auto-save on every action (localStorage) + a labels export;
|
|
16
16
|
* - a trace counter + jump-to-id + labeled/unlabeled counts.
|
|
17
17
|
*
|
|
18
|
+
* EV-3 — the review screen used to dump each whole session as a FLAT sibling
|
|
19
|
+
* list of collapsible steps (10,254 step-blocks / up to 1,686 per card in the
|
|
20
|
+
* real run → unreviewable). This renderer now ALSO ports the eval report's
|
|
21
|
+
* step<->criterion SIDE-BY-SIDE view onto review (the SAME extracted render
|
|
22
|
+
* functions — `report-fragments.ts`), with (a) criterion-scoped fragments (show
|
|
23
|
+
* only the steps a criterion examined, rendered by the REUSED `sideBySide`),
|
|
24
|
+
* (b) a VIRTUALIZED / windowed scroll so a 1,686-step card scrolls instead of
|
|
25
|
+
* walling the DOM, and (c) pre-labelled evidence steps (the steps a criterion's
|
|
26
|
+
* refs already identify). Activated ONLY when `opts.sideBySide` carries a
|
|
27
|
+
* per-trace bundle; without it the legacy flat review is unchanged.
|
|
28
|
+
*
|
|
18
29
|
* Austerity: holds NO judge prompt, makes NO pass/fail decision (the HUMAN
|
|
19
30
|
* decides). DETERMINISTIC: `renderReviewUi(traces, opts)` is byte-identical for
|
|
20
31
|
* the same input — NO clock / random / network in the generator. The browser
|
|
@@ -26,6 +37,7 @@
|
|
|
26
37
|
* (the subject profile), never hard-coded.
|
|
27
38
|
*/
|
|
28
39
|
import type {
|
|
40
|
+
CriterionVerdict,
|
|
29
41
|
DiscoveryAssumption,
|
|
30
42
|
DiscoveryRef,
|
|
31
43
|
EvalTrace,
|
|
@@ -34,6 +46,11 @@ import type {
|
|
|
34
46
|
VerdictBlock,
|
|
35
47
|
} from "./contracts/eval-types.ts";
|
|
36
48
|
import { type HumanLabel } from "./contracts/validation.ts";
|
|
49
|
+
import {
|
|
50
|
+
REVIEW_SIDE_BY_SIDE_DEPS_JS,
|
|
51
|
+
SIDE_BY_SIDE_FRAGMENT_JS,
|
|
52
|
+
STEP_ROW_FRAGMENT_JS,
|
|
53
|
+
} from "./report-fragments.ts";
|
|
37
54
|
|
|
38
55
|
/**
|
|
39
56
|
* GA — the judge's adjudication for ONE trace, surfaced on the review screen so
|
|
@@ -61,6 +78,63 @@ export function esc(s: unknown): string {
|
|
|
61
78
|
.replace(/'/g, "'");
|
|
62
79
|
}
|
|
63
80
|
|
|
81
|
+
/** JSON for a `<script>` inline injection — `<` escaped so no `</script>` breakout. */
|
|
82
|
+
function jsonInject(v: unknown): string {
|
|
83
|
+
return JSON.stringify(v ?? null).replace(/</g, "\\u003c");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ── EV-3 side-by-side data model (per-trace) ─────────────────────────────────
|
|
87
|
+
|
|
88
|
+
/** One agent step in the side-by-side lane (mirrors the eval report's AgentStep). */
|
|
89
|
+
export interface ReviewStep {
|
|
90
|
+
n: number | string;
|
|
91
|
+
tool?: string;
|
|
92
|
+
status?: string;
|
|
93
|
+
detail?: string;
|
|
94
|
+
/** the observation id the criterion refs bind to (`ref.obs === step.obs`). */
|
|
95
|
+
obs?: string;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** One judge-walk step (optional — most review bundles carry none). */
|
|
99
|
+
export interface ReviewJudgeStep {
|
|
100
|
+
kind: string;
|
|
101
|
+
text?: string;
|
|
102
|
+
ref?: unknown;
|
|
103
|
+
anchor?: number | null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* EV-3 — the per-trace SIDE-BY-SIDE bundle: the agent steps on the left, the
|
|
108
|
+
* per-criterion verdicts (with refs) that examined them on the right. Shaped to
|
|
109
|
+
* be consumed BOTH by the virtualized windowed renderer AND (criterion-scoped)
|
|
110
|
+
* by the REUSED `sideBySide` render fn from `report-fragments.ts`.
|
|
111
|
+
*/
|
|
112
|
+
export interface ReviewSideBySide {
|
|
113
|
+
agentSteps: ReviewStep[];
|
|
114
|
+
/** the per-criterion verdicts for this trace (refs bind them to the steps). */
|
|
115
|
+
criterionVerdicts: CriterionVerdict[];
|
|
116
|
+
judgeSteps?: ReviewJudgeStep[];
|
|
117
|
+
context?: { harness?: string; scenario?: string; exitStates?: string };
|
|
118
|
+
health?: { contextGathered?: boolean; grounded?: number; assumed?: number; stoppedAtSymptom?: boolean };
|
|
119
|
+
verdict?: string;
|
|
120
|
+
route?: string;
|
|
121
|
+
res?: string;
|
|
122
|
+
localize?: string;
|
|
123
|
+
input?: string;
|
|
124
|
+
/** analyzer-identified evidence obs ids — steps to PRE-LABEL as evidence. */
|
|
125
|
+
evidenceObs?: string[];
|
|
126
|
+
// pass-through for `sideBySide`'s optional bands (rendered when present).
|
|
127
|
+
subjectProfile?: unknown;
|
|
128
|
+
understanding?: unknown;
|
|
129
|
+
expectedTrajectory?: unknown;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Criterion metadata for the method tag (`C[id].m` → CODE/JUDGE/HYBRID). */
|
|
133
|
+
export interface ReviewCriterionMeta {
|
|
134
|
+
n?: string;
|
|
135
|
+
m?: string;
|
|
136
|
+
}
|
|
137
|
+
|
|
64
138
|
export interface ReviewUiOptions {
|
|
65
139
|
/** subject display name for the header badge (from the subject profile). */
|
|
66
140
|
subjectName?: string;
|
|
@@ -72,6 +146,14 @@ export interface ReviewUiOptions {
|
|
|
72
146
|
* eliminate capture. OPTIONAL — absent ⇒ the legacy label-only review screen.
|
|
73
147
|
*/
|
|
74
148
|
adjudications?: Record<string, ReviewAdjudication>;
|
|
149
|
+
/**
|
|
150
|
+
* EV-3 — the per-trace side-by-side bundle (agent steps + per-criterion
|
|
151
|
+
* verdicts). When present for a trace, the card renders the criterion-scoped,
|
|
152
|
+
* virtualized step<->criterion view. OPTIONAL — absent ⇒ legacy flat review.
|
|
153
|
+
*/
|
|
154
|
+
sideBySide?: Record<string, ReviewSideBySide>;
|
|
155
|
+
/** criterion metadata (id → {n,m}) for the CODE/JUDGE/HYBRID method tag. */
|
|
156
|
+
criteriaMeta?: Record<string, ReviewCriterionMeta>;
|
|
75
157
|
}
|
|
76
158
|
|
|
77
159
|
// ── per-trace native-format render (server-side, deterministic) ──────────────
|
|
@@ -140,23 +222,42 @@ function renderAdjudicationPanel(adj: ReviewAdjudication): string {
|
|
|
140
222
|
);
|
|
141
223
|
}
|
|
142
224
|
|
|
225
|
+
/**
|
|
226
|
+
* EV-3 — the side-by-side MOUNT for one trace. The card carries an empty mount
|
|
227
|
+
* div (data-trace-id) that the client controller fills with the criterion-scoped,
|
|
228
|
+
* virtualized step<->criterion view. Server emits only the shell (deterministic);
|
|
229
|
+
* the heavy step DOM is windowed at runtime so a 1,686-step card never walls.
|
|
230
|
+
*/
|
|
231
|
+
function renderSbsMount(traceId: string): string {
|
|
232
|
+
return (
|
|
233
|
+
`<div class="role role-sbs"><h4>Step ‖ Criterion — side-by-side (virtualized)</h4>` +
|
|
234
|
+
`<div class="sbs-mount" data-trace-id="${esc(traceId)}">` +
|
|
235
|
+
`<div class="sbs-boot">loading side-by-side…</div>` +
|
|
236
|
+
`</div></div>`
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
143
240
|
/**
|
|
144
241
|
* Render one trace as a card (native format: escaped text, collapsible tool
|
|
145
242
|
* observations, color-coded role borders, full trace accessible). All cards are
|
|
146
243
|
* emitted; the client shows exactly one at a time. When a GA adjudication is
|
|
147
244
|
* supplied for the trace, the judge panel + verify/eliminate capture is surfaced.
|
|
245
|
+
* When a side-by-side bundle is supplied, the criterion-scoped virtualized
|
|
246
|
+
* step<->criterion view is mounted.
|
|
148
247
|
*/
|
|
149
248
|
function renderTraceCard(
|
|
150
249
|
trace: EvalTrace,
|
|
151
250
|
index: number,
|
|
152
251
|
subjectName: string,
|
|
153
252
|
adj?: ReviewAdjudication,
|
|
253
|
+
hasSbs = false,
|
|
154
254
|
): string {
|
|
155
255
|
const prompt = esc(trace.input?.prompt ?? "");
|
|
156
256
|
const response = esc(trace.output?.response ?? "");
|
|
157
257
|
const obs = trace.observations.map(renderObservation).join("");
|
|
158
258
|
const toolCount = trace.observations.filter((o) => o.type === "TOOL").length;
|
|
159
259
|
const panel = adj !== undefined ? renderAdjudicationPanel(adj) : "";
|
|
260
|
+
const sbs = hasSbs ? renderSbsMount(trace.id) : "";
|
|
160
261
|
return (
|
|
161
262
|
`<section class="trace-card" data-index="${index}" data-trace-id="${esc(trace.id)}" hidden>` +
|
|
162
263
|
`<div class="card-head">` +
|
|
@@ -165,6 +266,7 @@ function renderTraceCard(
|
|
|
165
266
|
`<span class="badge meta">${toolCount} tool call(s)</span>` +
|
|
166
267
|
`</div>` +
|
|
167
268
|
`<div class="role role-user"><h4>Input</h4><pre>${prompt}</pre></div>` +
|
|
269
|
+
sbs +
|
|
168
270
|
`<div class="role role-tool"><h4>Trace (${trace.observations.length} step(s))</h4>${obs || "<em>no observations</em>"}</div>` +
|
|
169
271
|
`<div class="role role-assistant"><h4>Output</h4><pre>${response}</pre></div>` +
|
|
170
272
|
panel +
|
|
@@ -172,6 +274,58 @@ function renderTraceCard(
|
|
|
172
274
|
);
|
|
173
275
|
}
|
|
174
276
|
|
|
277
|
+
// ── EV-3 derive: build a per-trace side-by-side bundle from a trace + verdicts ─
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Derive a `ReviewSideBySide` from a trace + its per-criterion verdicts. PURE /
|
|
281
|
+
* deterministic. Synthesizes agent steps from the trace observations (n · tool ·
|
|
282
|
+
* detail · obs) and pre-labels the evidence obs ids the verdict refs cite. When
|
|
283
|
+
* `agentSteps` are supplied directly (already-projected judge steps), they win.
|
|
284
|
+
*/
|
|
285
|
+
export function deriveReviewSideBySide(
|
|
286
|
+
trace: EvalTrace,
|
|
287
|
+
verdicts: CriterionVerdict[],
|
|
288
|
+
extra: Partial<ReviewSideBySide> = {},
|
|
289
|
+
): ReviewSideBySide {
|
|
290
|
+
const agentSteps: ReviewStep[] =
|
|
291
|
+
extra.agentSteps ??
|
|
292
|
+
trace.observations.map((o, i) => {
|
|
293
|
+
const obsId = (o as { id?: string }).id;
|
|
294
|
+
let detail = "";
|
|
295
|
+
try {
|
|
296
|
+
detail = JSON.stringify(o.output ?? o.input ?? {});
|
|
297
|
+
} catch {
|
|
298
|
+
detail = String(o.output ?? "");
|
|
299
|
+
}
|
|
300
|
+
return {
|
|
301
|
+
n: i + 1,
|
|
302
|
+
tool: o.name ?? o.type,
|
|
303
|
+
status: o.type === "TOOL" ? "" : String(o.type),
|
|
304
|
+
detail: detail.length > 240 ? detail.slice(0, 240) + "…" : detail,
|
|
305
|
+
obs: obsId,
|
|
306
|
+
};
|
|
307
|
+
});
|
|
308
|
+
// evidence obs = every obs id a verdict ref cites (analyzer-identified).
|
|
309
|
+
const evidence = new Set<string>(extra.evidenceObs ?? []);
|
|
310
|
+
for (const v of verdicts) for (const r of v.refs ?? []) if (r.obs) evidence.add(String(r.obs));
|
|
311
|
+
return {
|
|
312
|
+
agentSteps,
|
|
313
|
+
criterionVerdicts: verdicts,
|
|
314
|
+
input: extra.input ?? trace.input?.prompt,
|
|
315
|
+
verdict: extra.verdict,
|
|
316
|
+
route: extra.route,
|
|
317
|
+
res: extra.res,
|
|
318
|
+
localize: extra.localize,
|
|
319
|
+
context: extra.context,
|
|
320
|
+
health: extra.health,
|
|
321
|
+
judgeSteps: extra.judgeSteps,
|
|
322
|
+
evidenceObs: [...evidence],
|
|
323
|
+
subjectProfile: extra.subjectProfile,
|
|
324
|
+
understanding: extra.understanding,
|
|
325
|
+
expectedTrajectory: extra.expectedTrajectory,
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
175
329
|
// ── the deterministic HTML document ──────────────────────────────────────────
|
|
176
330
|
|
|
177
331
|
// Brand: the unified MutagenT design-system — SHARP corners (radius 0), SUBTLE
|
|
@@ -179,15 +333,15 @@ function renderTraceCard(
|
|
|
179
333
|
// mirror @mutagent/templates/design-system/tokens.css (self-contained inline copy;
|
|
180
334
|
// the review UI is a standalone HTML doc with no bundled brand-asset read).
|
|
181
335
|
const STYLE = `
|
|
182
|
-
:root{--bg:#0a0a12;--surf:#14141d;--surf-2:#1a1a25;--fg:#d6dbe6;--fg-strong:#eef1f6;--mut:#8a8698;--bd:rgba(255,255,255,.09);--bstr:rgba(255,255,255,.16);--pass:#43c39a;--fail:#e06666;--defer:#e8a64d;--user:#45b8cc;--tool:#7E47D7;--asst:#43c39a;--fs:'Space Grotesk',system-ui,-apple-system,sans-serif;--fm:'IBM Plex Mono',ui-monospace,monospace}
|
|
336
|
+
:root{--bg:#0a0a12;--surf:#14141d;--surf-2:#1a1a25;--fg:#d6dbe6;--fg-strong:#eef1f6;--mut:#8a8698;--dim:#6b6878;--bd:rgba(255,255,255,.09);--bstr:rgba(255,255,255,.16);--pass:#43c39a;--fail:#e06666;--defer:#e8a64d;--warn:#e8a64d;--cyan:#45b8cc;--user:#45b8cc;--tool:#7E47D7;--asst:#43c39a;--primary-soft:#a986e8;--fs:'Space Grotesk',system-ui,-apple-system,sans-serif;--fm:'IBM Plex Mono',ui-monospace,monospace;--fs-sm:12px;--fs-xs:11px;--fs-2xs:10px}
|
|
183
337
|
*{box-sizing:border-box;border-radius:0}body{margin:0;background:var(--bg);color:var(--fg);font:14px/1.55 var(--fs)}
|
|
184
338
|
header{position:sticky;top:0;background:var(--surf);border-bottom:1px solid var(--bstr);padding:10px 16px;display:flex;gap:12px;align-items:center;flex-wrap:wrap;z-index:10}
|
|
185
339
|
header strong{color:var(--fg-strong)}
|
|
186
|
-
main{padding:16px;max-width:
|
|
340
|
+
main{padding:16px;max-width:1180px;margin:0 auto}
|
|
187
341
|
.badge{display:inline-block;padding:2px 8px;background:var(--surf-2);border:1px solid var(--bd);font-size:12px;font-family:var(--fm)}
|
|
188
342
|
.badge.subject{background:var(--surf-2);border-color:var(--bstr)}.badge.tid{font-family:var(--fm)}
|
|
189
343
|
.role{border-left:3px solid var(--bd);padding:4px 12px;margin:10px 0}
|
|
190
|
-
.role-user{border-color:var(--user)}.role-tool{border-color:var(--tool)}.role-assistant{border-color:var(--asst)}
|
|
344
|
+
.role-user{border-color:var(--user)}.role-tool{border-color:var(--tool)}.role-assistant{border-color:var(--asst)}.role-sbs{border-color:var(--primary-soft)}
|
|
191
345
|
.role h4{margin:4px 0;color:var(--mut);font-weight:600;text-transform:uppercase;font-size:11px;letter-spacing:.04em;font-family:var(--fm)}
|
|
192
346
|
pre{white-space:pre-wrap;word-break:break-word;background:var(--surf);border:1px solid var(--bd);padding:10px;margin:4px 0;font-family:var(--fm)}
|
|
193
347
|
details.obs{margin:4px 0;border:1px solid var(--bd);padding:4px 8px;background:var(--surf-2)}
|
|
@@ -207,6 +361,57 @@ input[type=text]{background:var(--surf);color:var(--fg);border:1px solid var(--b
|
|
|
207
361
|
.ga-assumptions{margin:4px 0;padding-left:18px}
|
|
208
362
|
.badge.verdict-pass{border-color:var(--pass);color:var(--pass)}.badge.verdict-fail{border-color:var(--fail);color:var(--fail)}.badge.verdict-indeterminate{border-color:var(--defer);color:var(--defer)}
|
|
209
363
|
button.calib{padding:2px 8px;font-size:11px}button.calib.verify.active{background:var(--pass);color:#0a0a12}button.calib.eliminate.active{background:var(--fail);color:#0a0a12}
|
|
364
|
+
/* EV-3 — side-by-side (criterion-scoped, virtualized, evidence-highlighted) */
|
|
365
|
+
.sbs-mount{border:1px solid var(--bd);background:var(--surf-2);padding:8px}
|
|
366
|
+
.sbs-boot{color:var(--mut);font-family:var(--fm);font-size:12px;padding:8px}
|
|
367
|
+
.sbs-chips{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px}
|
|
368
|
+
.sbs-chip{padding:3px 9px;font-size:12px;font-family:var(--fm);background:var(--surf);border:1px solid var(--bd);color:var(--fg)}
|
|
369
|
+
.sbs-chip.on{border-color:var(--primary-soft);color:var(--fg-strong);background:var(--surf-2)}
|
|
370
|
+
.lanehdr{display:grid;grid-template-columns:1fr auto 1fr;gap:8px;padding:5px 6px;border-bottom:1px solid var(--bstr);color:var(--mut);font-family:var(--fm);font-size:11px;text-transform:uppercase;letter-spacing:.03em}
|
|
371
|
+
.lanehdr .x{text-align:center}.lanehdr .j{text-align:left}
|
|
372
|
+
.sbs-scroll{height:440px;overflow:auto;position:relative;border:1px solid var(--bd);background:var(--surf)}
|
|
373
|
+
.sbs-sizer{position:relative;width:100%}
|
|
374
|
+
.sbs-window{position:absolute;left:0;right:0;top:0;will-change:transform}
|
|
375
|
+
.srow{display:grid;grid-template-columns:1fr auto 1fr;gap:8px;border-bottom:1px solid var(--bd);overflow:hidden;padding:2px 0}
|
|
376
|
+
.srow.evidence{background:rgba(126,71,215,.10);border-left:3px solid var(--primary-soft)}
|
|
377
|
+
.step-l,.step-r{overflow:auto;padding:4px 8px}
|
|
378
|
+
.step-l .evb,.step-r .evb{font-family:var(--fm);font-size:11px}
|
|
379
|
+
.step-l .top{display:flex;gap:6px;align-items:center}
|
|
380
|
+
.step-l .tool{color:var(--fg-strong)}.step-l .st{color:var(--warn)}
|
|
381
|
+
.step-l .det{color:var(--mut);margin-top:2px;word-break:break-word}
|
|
382
|
+
.node{display:flex;flex-direction:column;align-items:center;justify-content:center;min-width:34px}
|
|
383
|
+
.node .n{font-family:var(--fm);font-size:11px;color:var(--mut);border:1px solid var(--bd);padding:0 5px}
|
|
384
|
+
.node .ln{flex:1;width:1px;background:var(--bd);min-height:6px}
|
|
385
|
+
.jcov{border:1px solid var(--bd);border-left:3px solid var(--bd);padding:4px 7px;margin:3px 0;background:var(--surf-2)}
|
|
386
|
+
.jcov.pass{border-left-color:var(--pass)}.jcov.fail{border-left-color:var(--fail)}.jcov.uncertain,.jcov.indeterminate{border-left-color:var(--warn)}
|
|
387
|
+
.jcov-h{display:flex;gap:6px;align-items:center;flex-wrap:wrap;margin-bottom:2px}
|
|
388
|
+
.cvb{font-family:var(--fm);font-size:10px;text-transform:uppercase;letter-spacing:.03em;padding:0 5px;border:1px solid var(--bstr)}
|
|
389
|
+
.cvb.pass{color:var(--pass);border-color:var(--pass)}.cvb.fail{color:var(--fail);border-color:var(--fail)}.cvb.uncertain,.cvb.indeterminate{color:var(--warn);border-color:var(--warn)}.cvb.na{color:var(--dim)}
|
|
390
|
+
.jm{font-family:var(--fm);font-size:9px;padding:0 4px;border:1px solid var(--bd);color:var(--mut)}.jm.code{color:var(--cyan);border-color:var(--cyan)}
|
|
391
|
+
.jcid{font-family:var(--fm);font-size:11px;color:var(--fg-strong)}
|
|
392
|
+
.jcrit{font-size:12px;color:var(--fg);line-height:1.45}
|
|
393
|
+
.cvrefs{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}
|
|
394
|
+
.cvref{font-family:var(--fm);font-size:10px;color:var(--cyan);border:1px solid var(--bd);padding:0 4px;word-break:break-all}
|
|
395
|
+
.jstep{font-family:var(--fm);font-size:11px;color:var(--fg);padding:2px 0}.jstep.noexam{color:var(--dim)}
|
|
396
|
+
.jstep .k{color:var(--primary-soft);margin-right:5px}.jstep .ref{color:var(--cyan)}
|
|
397
|
+
.dim{color:var(--dim)}
|
|
398
|
+
.sbs-meta{color:var(--mut);font-family:var(--fm);font-size:11px;margin-top:6px}
|
|
399
|
+
.sbs-full{margin-top:8px}.sbs-hint{color:var(--mut);font-family:var(--fm);font-size:11px;padding:6px}
|
|
400
|
+
.sbs-fulldet{border:1px solid var(--bd);background:var(--surf);padding:6px 8px}
|
|
401
|
+
.sbs-fulldet summary{color:var(--primary-soft);font-family:var(--fm);font-size:12px}
|
|
402
|
+
/* the reused sideBySide fragment renders a drillbox — give its bands legible defaults */
|
|
403
|
+
.drillbox{padding:6px 2px}.drillbox .mono{font-family:var(--fm)}
|
|
404
|
+
.drillbox .chip{font-family:var(--fm);font-size:11px;border:1px solid var(--bd);padding:0 6px;margin:0 4px}
|
|
405
|
+
.drillbox .verd{font-family:var(--fm);font-size:11px;padding:0 6px;border:1px solid var(--bstr)}.drillbox .verd.fail{color:var(--fail);border-color:var(--fail)}.drillbox .verd.pass{color:var(--pass);border-color:var(--pass)}.drillbox .verd.inc{color:var(--warn);border-color:var(--warn)}
|
|
406
|
+
.drillbox .ctx,.drillbox .band{border:1px solid var(--bd);padding:6px 8px;margin:6px 0;background:var(--surf-2)}
|
|
407
|
+
.drillbox .ctx-h,.drillbox .bh{color:var(--mut);font-family:var(--fm);font-size:11px;text-transform:uppercase;letter-spacing:.03em;margin-bottom:4px}
|
|
408
|
+
.drillbox .ctx-g{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:8px}
|
|
409
|
+
.drillbox .ctx-c .l{color:var(--dim);font-family:var(--fm);font-size:10px;text-transform:uppercase}.drillbox .ctx-c .v{color:var(--fg)}
|
|
410
|
+
.drillbox .grid2{display:grid;grid-template-columns:1fr auto 1fr;gap:8px;margin-top:6px}
|
|
411
|
+
.drillbox .health{display:flex;gap:10px;flex-wrap:wrap;margin-top:6px}.drillbox .hc{border:1px solid var(--bd);padding:3px 8px;font-family:var(--fm);font-size:11px}.drillbox .hc .v.good{color:var(--pass)}.drillbox .hc .v.warn{color:var(--warn)}
|
|
412
|
+
.cvblock .cvbody{display:flex;flex-direction:column;gap:5px}.cvrow{border:1px solid var(--bd);border-left:3px solid var(--bd);padding:5px 7px;background:var(--surf)}.cvrow.pass{border-left-color:var(--pass)}.cvrow.fail{border-left-color:var(--fail)}.cvrow.uncertain,.cvrow.indeterminate{border-left-color:var(--warn)}
|
|
413
|
+
.cvh{display:flex;gap:6px;align-items:center;flex-wrap:wrap;margin-bottom:2px}.cvid{font-family:var(--fm);color:var(--fg-strong);font-size:11px}.cvconf{font-family:var(--fm);font-size:10px;color:var(--dim);margin-left:auto}.cvcrit{font-size:12px}.cvcrit.dim{color:var(--dim)}
|
|
414
|
+
.routing{display:flex;gap:6px;align-items:center;margin:4px 0;font-family:var(--fm);font-size:11px}.re-rephrase,.re-ul,.re-rat,.why-note{font-size:12px}.whychain .jstep{font-size:11px}
|
|
210
415
|
`;
|
|
211
416
|
|
|
212
417
|
/**
|
|
@@ -215,11 +420,16 @@ button.calib{padding:2px 8px;font-size:11px}button.calib.verify.active{backgroun
|
|
|
215
420
|
* NO trace data (the cards are server-rendered) and NO subject specifics. The
|
|
216
421
|
* `STORAGE_KEY` is parameterized by a stable subject key so multiple subjects'
|
|
217
422
|
* labels don't collide in one browser.
|
|
423
|
+
*
|
|
424
|
+
* EV-3 — when side-by-side data (`SBS`) is injected, the controller ALSO mounts
|
|
425
|
+
* the criterion-scoped, virtualized step<->criterion view per card (lazily, on
|
|
426
|
+
* first show), reusing the extracted `sideBySide` fn for the scoped fragment.
|
|
218
427
|
*/
|
|
219
|
-
function clientScript(storageKey: string): string {
|
|
428
|
+
function clientScript(storageKey: string, sbsJson: string, critJson: string): string {
|
|
220
429
|
return `
|
|
221
430
|
const STORAGE_KEY=${JSON.stringify(storageKey)};
|
|
222
431
|
const CALIB_KEY=STORAGE_KEY+':calibration';
|
|
432
|
+
const SBS=${sbsJson},C=${critJson},RES={};
|
|
223
433
|
const cards=[...document.querySelectorAll('.trace-card')];
|
|
224
434
|
const ids=cards.map(c=>c.dataset.traceId);
|
|
225
435
|
let cur=0;
|
|
@@ -232,6 +442,69 @@ function saveCalib(m){localStorage.setItem(CALIB_KEY,JSON.stringify(m))}
|
|
|
232
442
|
let calib=loadCalib();
|
|
233
443
|
let labels=loadLabels();
|
|
234
444
|
let history=[];
|
|
445
|
+
// ── EV-3 side-by-side deps + extracted render fns + virtualization mirror ──
|
|
446
|
+
${REVIEW_SIDE_BY_SIDE_DEPS_JS}
|
|
447
|
+
${SIDE_BY_SIDE_FRAGMENT_JS}
|
|
448
|
+
${STEP_ROW_FRAGMENT_JS}
|
|
449
|
+
var SBS_ROW_H=112,SBS_OVERSCAN=6;
|
|
450
|
+
function sbsStepsFor(d,scope){
|
|
451
|
+
var steps=d.agentSteps||[];
|
|
452
|
+
if(scope==='all')return steps;
|
|
453
|
+
var v=(d.criterionVerdicts||[]).filter(function(x){return x.criterionId===scope;});
|
|
454
|
+
return steps.filter(function(a){return stepExaminedByR(a,v);});
|
|
455
|
+
}
|
|
456
|
+
function sbsEvidence(a,d){
|
|
457
|
+
if(d.evidenceObs&&a.obs&&d.evidenceObs.indexOf(String(a.obs))>=0)return true;
|
|
458
|
+
return stepExaminedByR(a,d.criterionVerdicts||[]);
|
|
459
|
+
}
|
|
460
|
+
function sbsChipBar(d){
|
|
461
|
+
var steps=d.agentSteps||[];var ev=steps.filter(function(a){return sbsEvidence(a,d);}).length;
|
|
462
|
+
var chips='<button class="sbs-chip on" data-scope="all">All · '+steps.length+' steps · '+ev+' evidence</button>';
|
|
463
|
+
(d.criterionVerdicts||[]).forEach(function(v){
|
|
464
|
+
var n=sbsStepsFor(d,v.criterionId).length;var res=v.result||'na';var disp=res==='uncertain'?'indeterminate':res;
|
|
465
|
+
chips+='<button class="sbs-chip" data-scope="'+esc(v.criterionId)+'" title="'+esc(v.critique||'')+'"><span class="cvb '+esc(res)+'">'+esc(disp)+'</span> '+esc(v.criterionId)+' · '+n+'</button>';
|
|
466
|
+
});
|
|
467
|
+
return '<div class="sbs-chips">'+chips+'</div>';
|
|
468
|
+
}
|
|
469
|
+
function renderSbsWindow(mount){
|
|
470
|
+
var d=mount._d,scope=mount._scope;var steps=sbsStepsFor(d,scope);
|
|
471
|
+
var scroll=mount.querySelector('.sbs-scroll'),sizer=mount.querySelector('.sbs-sizer'),win=mount.querySelector('.sbs-window');
|
|
472
|
+
var cvAll=scope==='all'?(d.criterionVerdicts||[]):(d.criterionVerdicts||[]).filter(function(x){return x.criterionId===scope;});
|
|
473
|
+
sizer.style.height=(steps.length*SBS_ROW_H)+'px';
|
|
474
|
+
var top=scroll.scrollTop,h=scroll.clientHeight||440;
|
|
475
|
+
var start=Math.max(0,Math.floor(top/SBS_ROW_H)-SBS_OVERSCAN);
|
|
476
|
+
var count=Math.ceil(h/SBS_ROW_H)+SBS_OVERSCAN*2;var end=Math.min(steps.length,start+count);
|
|
477
|
+
var html='';
|
|
478
|
+
for(var i=start;i<end;i++){var a=steps[i];html+='<div class="srow'+(sbsEvidence(a,d)?' evidence':'')+'" data-step="'+esc(a.n)+'" style="height:'+SBS_ROW_H+'px">'+stepRowInnerR(a,cvAll,d.judgeSteps)+'</div>';}
|
|
479
|
+
win.style.transform='translateY('+(start*SBS_ROW_H)+'px)';win.innerHTML=html;
|
|
480
|
+
var meta=mount.querySelector('.sbs-meta');
|
|
481
|
+
if(meta)meta.textContent=steps.length+' step(s) in scope · '+(steps.length?(end-start):0)+' in DOM (rows '+(steps.length?start+1:0)+'–'+end+') · virtualized window';
|
|
482
|
+
}
|
|
483
|
+
function renderSbsFull(mount){
|
|
484
|
+
var d=mount._d,scope=mount._scope,full=mount.querySelector('.sbs-full');if(!full)return;
|
|
485
|
+
if(scope==='all'){full.innerHTML='<div class="sbs-hint">Pick a criterion chip above to open its full side-by-side fragment (reused eval-report renderer).</div>';return;}
|
|
486
|
+
var v=(d.criterionVerdicts||[]).filter(function(x){return x.criterionId===scope;});
|
|
487
|
+
var steps=sbsStepsFor(d,scope);var dScoped={};for(var k in d)dScoped[k]=d[k];
|
|
488
|
+
dScoped.agentSteps=steps;dScoped.criterionVerdicts=v;dScoped.traceId=mount.getAttribute('data-trace-id');
|
|
489
|
+
full.innerHTML='<details class="sbs-fulldet" open><summary>criterion-scoped fragment · '+esc(scope)+' · '+steps.length+' step(s) (reused sideBySide)</summary>'+sideBySide(dScoped)+'</details>';
|
|
490
|
+
}
|
|
491
|
+
function mountSbs(mount){
|
|
492
|
+
if(mount._wired)return;var tid=mount.getAttribute('data-trace-id');var d=SBS[tid];
|
|
493
|
+
if(!d){mount.innerHTML='<div class="sbs-hint">no side-by-side data for this trace.</div>';mount._wired=true;return;}
|
|
494
|
+
mount._d=d;mount._scope='all';mount._wired=true;
|
|
495
|
+
mount.innerHTML=sbsChipBar(d)+
|
|
496
|
+
'<div class="lanehdr"><div class="a">agent step — what it did</div><div class="x">#</div><div class="j">criteria that examined this step</div></div>'+
|
|
497
|
+
'<div class="sbs-scroll"><div class="sbs-sizer"><div class="sbs-window"></div></div></div>'+
|
|
498
|
+
'<div class="sbs-meta"></div><div class="sbs-full"></div>';
|
|
499
|
+
var scroll=mount.querySelector('.sbs-scroll');
|
|
500
|
+
scroll.addEventListener('scroll',function(){renderSbsWindow(mount);});
|
|
501
|
+
mount.querySelectorAll('.sbs-chip').forEach(function(ch){ch.addEventListener('click',function(){
|
|
502
|
+
mount.querySelectorAll('.sbs-chip').forEach(function(x){x.classList.remove('on');});ch.classList.add('on');
|
|
503
|
+
mount._scope=ch.getAttribute('data-scope');scroll.scrollTop=0;renderSbsWindow(mount);renderSbsFull(mount);
|
|
504
|
+
});});
|
|
505
|
+
renderSbsWindow(mount);renderSbsFull(mount);
|
|
506
|
+
}
|
|
507
|
+
function sbsOnShow(i){var card=cards[i];if(!card)return;var m=card.querySelector('.sbs-mount');if(m)try{mountSbs(m);}catch(e){}}
|
|
235
508
|
function show(i){
|
|
236
509
|
if(i<0)i=0;if(i>=cards.length)i=cards.length-1;cur=i;
|
|
237
510
|
cards.forEach((c,k)=>c.hidden=k!==i);
|
|
@@ -240,6 +513,7 @@ function show(i){
|
|
|
240
513
|
document.getElementById('notes').value=rec.notes||'';
|
|
241
514
|
document.getElementById('jump').value=id;
|
|
242
515
|
updateCounter();
|
|
516
|
+
sbsOnShow(i);
|
|
243
517
|
}
|
|
244
518
|
function updateCounter(){
|
|
245
519
|
const done=ids.filter(id=>labels[id]&&labels[id].label).length;
|
|
@@ -318,8 +592,10 @@ export function renderReviewUi(traces: EvalTrace[], opts: ReviewUiOptions = {}):
|
|
|
318
592
|
// stable storage key so labels namespace per subject (no clock/random).
|
|
319
593
|
const storageKey = `mutagent-evaluator:review:${subjectName}`;
|
|
320
594
|
const adj = opts.adjudications ?? {};
|
|
595
|
+
const sbs = opts.sideBySide ?? {};
|
|
596
|
+
const criteriaMeta = opts.criteriaMeta ?? {};
|
|
321
597
|
const cards = traces
|
|
322
|
-
.map((t, i) => renderTraceCard(t, i, subjectName, adj[t.id]))
|
|
598
|
+
.map((t, i) => renderTraceCard(t, i, subjectName, adj[t.id], sbs[t.id] !== undefined))
|
|
323
599
|
.join("");
|
|
324
600
|
const empty = traces.length === 0 ? `<p><em>No traces to review.</em></p>` : "";
|
|
325
601
|
return (
|
|
@@ -341,7 +617,7 @@ export function renderReviewUi(traces: EvalTrace[], opts: ReviewUiOptions = {}):
|
|
|
341
617
|
`<span class="kbd">← → nav · 1 Pass · 2 Fail · D Defer · U Undo · ⌘S Save · ⌘⏎ Save&Next</span>` +
|
|
342
618
|
`</span></header>` +
|
|
343
619
|
`<main>${empty}${cards}<textarea id="notes" placeholder="notes — what went wrong / right"></textarea></main>` +
|
|
344
|
-
`<script>${clientScript(storageKey)}</script></body></html>`
|
|
620
|
+
`<script>${clientScript(storageKey, jsonInject(sbs), jsonInject(criteriaMeta))}</script></body></html>`
|
|
345
621
|
);
|
|
346
622
|
}
|
|
347
623
|
|
|
@@ -391,3 +667,41 @@ export function labelStats(traceIds: string[], labels: HumanLabel[]): LabelStats
|
|
|
391
667
|
}
|
|
392
668
|
return { total: traceIds.length, labeled, unlabeled: traceIds.length - labeled, pass, fail, defer };
|
|
393
669
|
}
|
|
670
|
+
|
|
671
|
+
// ── CLI entrypoint ───────────────────────────────────────────────────────────
|
|
672
|
+
//
|
|
673
|
+
// bun scripts/build-review-ui.ts <input.json> [out.html]
|
|
674
|
+
// Reads { traces, subjectName?, title?, adjudications?, sideBySide?, criteriaMeta? }
|
|
675
|
+
// and writes the review HTML. This is the production caller the `*review`
|
|
676
|
+
// command's parent Bash invokes (references/build-review-interface.md).
|
|
677
|
+
declare const Bun: { argv: string[] } | undefined;
|
|
678
|
+
|
|
679
|
+
interface ReviewCliInput extends ReviewUiOptions {
|
|
680
|
+
traces: EvalTrace[];
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
async function main(): Promise<void> {
|
|
684
|
+
const argv = typeof Bun !== "undefined" ? Bun.argv.slice(2) : process.argv.slice(2);
|
|
685
|
+
const [inputPath, outArg] = argv;
|
|
686
|
+
if (!inputPath) {
|
|
687
|
+
console.error("usage: build-review-ui.ts <input.json> [out.html]");
|
|
688
|
+
process.exit(2);
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
const { readFileSync, writeFileSync, mkdirSync } = await import("node:fs");
|
|
692
|
+
const { dirname } = await import("node:path");
|
|
693
|
+
const input = JSON.parse(readFileSync(inputPath, "utf8")) as ReviewCliInput;
|
|
694
|
+
const { traces, ...opts } = input;
|
|
695
|
+
const outPath = outArg ?? "review.html";
|
|
696
|
+
mkdirSync(dirname(outPath) || ".", { recursive: true });
|
|
697
|
+
writeFileSync(outPath, renderReviewUi(traces ?? [], opts));
|
|
698
|
+
console.info(`review UI written: ${outPath} (${(traces ?? []).length} trace(s))`);
|
|
699
|
+
process.exit(0);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
const isMain =
|
|
703
|
+
typeof import.meta !== "undefined" &&
|
|
704
|
+
(import.meta as unknown as { main?: boolean }).main === true;
|
|
705
|
+
if (isMain) {
|
|
706
|
+
void main();
|
|
707
|
+
}
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
resolveProfilePaths,
|
|
27
27
|
} from "../load-profile.ts";
|
|
28
28
|
import { loadBundle } from "../load-bundle.ts";
|
|
29
|
-
import { runDeterministic } from "../run-deterministic.ts";
|
|
29
|
+
import { runDeterministic, reexecDeterministicCheck } from "../run-deterministic.ts";
|
|
30
30
|
import { assembleScorecard } from "../assemble-scorecard.ts";
|
|
31
31
|
import { renderReport } from "../render-report.ts";
|
|
32
32
|
import { maskedCanonicalJson } from "../mask.ts";
|
|
@@ -107,8 +107,11 @@ export function main(argvIn?: string[]): number {
|
|
|
107
107
|
// 2. Run-bundle
|
|
108
108
|
const { bundle } = loadBundle(args.bundleDir, args.runId);
|
|
109
109
|
|
|
110
|
-
// 3. Deterministic pass
|
|
111
|
-
|
|
110
|
+
// 3. Deterministic pass — WIRE the real live re-exec (Item #4): every mapped
|
|
111
|
+
// deterministic row runs an actual checkMethod-keyed check over the produced
|
|
112
|
+
// artifact instead of a presence proxy. In-cell, no sub-agents (PR-ORCH-01),
|
|
113
|
+
// judge-only (EV-051), C-PIN byte-stable.
|
|
114
|
+
const det = runDeterministic(matrix, bundle, { liveReexec: reexecDeterministicCheck });
|
|
112
115
|
|
|
113
116
|
// 4. Two-track scorecard
|
|
114
117
|
const scorecard = assembleScorecard({
|
|
@@ -30,9 +30,11 @@ import { execSync } from "node:child_process";
|
|
|
30
30
|
import { readFileSync, writeFileSync } from "node:fs";
|
|
31
31
|
import { join, resolve } from "node:path";
|
|
32
32
|
import { parseUnitfJsonl } from "../read-unitf-traces.ts";
|
|
33
|
+
import { validateSiblingManifest } from "../read-manifest.ts";
|
|
33
34
|
import { prepDeterminerTasks, prepJudgeTasks } from "../prep-tasks.ts";
|
|
34
35
|
import { selectColdStartSuite, type ColdStartMeta } from "../cold-start-project.ts";
|
|
35
36
|
import { profileSubject } from "../profile-subject.ts";
|
|
37
|
+
import { deriveSubjectFrame } from "../subject-profile.ts";
|
|
36
38
|
import { loadProfileVocab } from "../load-profile-vocab.ts";
|
|
37
39
|
import { buildMatrixPacket, writeMatrixPacket, packetFileName } from "../matrix-judge.ts";
|
|
38
40
|
import { configPathFor, loadEvaluatorConfig, type SourceBinding } from "../config/load.ts";
|
|
@@ -208,7 +210,29 @@ async function main(): Promise<void> {
|
|
|
208
210
|
if (startContext !== "") process.stdout.write(`prep: run-start context —\n${startContext}\n`);
|
|
209
211
|
const pin: PinnedEnvelope = { model, temperature: 0 };
|
|
210
212
|
const ndjson = loadNdjson(tracesFile, limit !== undefined ? Number.parseInt(limit, 10) : undefined);
|
|
211
|
-
const { traces } = parseUnitfJsonl(ndjson);
|
|
213
|
+
const { traces, skipped, emptyPromptTraceIds } = parseUnitfJsonl(ndjson);
|
|
214
|
+
|
|
215
|
+
// EV-6 — read + validate the sibling TraceManifest (count/format/truncation) and
|
|
216
|
+
// WARN on mismatch, the way diagnostics does (read-unitf.ts). The evaluator used
|
|
217
|
+
// to read ONLY the JSONL, so a truncated/partial slice was judged as if complete.
|
|
218
|
+
for (const w of validateSiblingManifest(tracesFile, traces.length)) {
|
|
219
|
+
process.stderr.write(`prep: MANIFEST WARNING — ${w}\n`);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// INF-1 — never silently emit empty: surface any record whose prompt-bearing span
|
|
223
|
+
// still projected an empty prompt (the Claude Code 21/21-blank class). Loud on
|
|
224
|
+
// stderr so a projection miss can never pass unnoticed again.
|
|
225
|
+
if (emptyPromptTraceIds.length > 0) {
|
|
226
|
+
process.stderr.write(
|
|
227
|
+
`prep: EMPTY-PROMPT WARNING — ${emptyPromptTraceIds.length}/${traces.length} trace(s) have a ` +
|
|
228
|
+
`prompt-bearing span but projected an EMPTY input.prompt (a trace-read miss; the judge would ` +
|
|
229
|
+
`score them blind). traceIds: ${emptyPromptTraceIds.slice(0, 10).join(", ")}` +
|
|
230
|
+
`${emptyPromptTraceIds.length > 10 ? ", …" : ""}\n`,
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
if (skipped > 0) {
|
|
234
|
+
process.stderr.write(`prep: ${skipped} line(s) skipped (malformed / non-UniTF).\n`);
|
|
235
|
+
}
|
|
212
236
|
|
|
213
237
|
// DEFAULT *evaluate PREP — one eval-matrix packet per trajectory (the headline cell).
|
|
214
238
|
if (stage === "matrix") {
|
|
@@ -253,7 +277,13 @@ async function main(): Promise<void> {
|
|
|
253
277
|
const coldSize = coldSizeFlag !== undefined ? Number.parseInt(coldSizeFlag, 10) : traces.length;
|
|
254
278
|
const cold = selectColdStartSuite(traces, { size: coldSize });
|
|
255
279
|
coldStartMeta = cold.meta;
|
|
256
|
-
|
|
280
|
+
// EV-1 — the subject-aware determiner frame, derived from the FULL parsed batch
|
|
281
|
+
// (NOT the cold subsample) via the SHARED `deriveSubjectFrame` so it is byte-
|
|
282
|
+
// identical to what the Stage-B pipeline builds → the cross-stage determiner cache
|
|
283
|
+
// lines up. subjectName mirrors run-pipeline's `subject.name` (traces[0].name).
|
|
284
|
+
const determinerSubjectName = traces[0]?.name ?? "unknown-subject";
|
|
285
|
+
const subjectFrame = deriveSubjectFrame(determinerSubjectName, traces);
|
|
286
|
+
specs = prepDeterminerTasks(cold.selected, { dir: taskDir, pin, vocab, subject: subjectFrame });
|
|
257
287
|
} else if (stage === "judge") {
|
|
258
288
|
const criteriaFile = flag(argv, "criteria");
|
|
259
289
|
const verdictDir = flag(argv, "verdict-dir");
|
|
@@ -34,7 +34,7 @@ const MR_RUBRIC_SKELETON = [
|
|
|
34
34
|
{ id: "MR-2", title: "Data-flow efficiency", reads: "pipeline trace", how: "scan for redundant/recomputed transforms, collapsible stages", family: "data-flow-efficiency", advisory: true },
|
|
35
35
|
{ id: "MR-3", title: "Methodology fitness given findings", reads: "run trajectory + findings", how: "did depth/breadth match the need?", family: "methodology-fitness", advisory: true },
|
|
36
36
|
{ id: "MR-4", title: "Sequence soundness", reads: "transcript trajectory", how: "does later work invalidate earlier work?", family: "sequence-soundness", advisory: true },
|
|
37
|
-
{ id: "MR-5", title: "Process self-feedback", reads: "all of the above", how: "ranked rearrange/
|
|
37
|
+
{ id: "MR-5", title: "Process self-feedback", reads: "all of the above", how: "ranked rearrange/optimize proposals", family: "process-self-feedback", advisory: true },
|
|
38
38
|
{ id: "MR-6", title: "Followed != Right", reads: "matrix (Tab-1) vs this (Tab-4)", how: "separate conformance from fitness", family: "conformance-vs-fitness", advisory: true },
|
|
39
39
|
{ id: "MR-7", title: "Signal/failure-mode selection", reads: "tier0 -> awareness -> deep-read chain", how: "was the primary signal grounded in the right evidence tier?", family: "signal-selection", advisory: true },
|
|
40
40
|
{ id: "MR-8", title: "Confidence derivation", reads: "coverageConfidence vs deep-read sample", how: "does the confidence FOLLOW from the LLM-trace evidence?", family: "confidence-derivation", advisory: true },
|