@mutagent/evaluator 0.1.0-alpha.6 → 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 +23 -25
- package/.claude/skills/mutagent-evaluator/assets/agents/dataset-builder.md +6 -5
- package/.claude/skills/mutagent-evaluator/assets/agents/evaluator.md +77 -14
- 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/references/data-registry.md +43 -0
- package/.claude/skills/mutagent-evaluator/references/eval-layers.md +52 -0
- package/.claude/skills/mutagent-evaluator/references/eval-stage.md +1 -1
- 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/code-eval-library.ts +201 -0
- package/.claude/skills/mutagent-evaluator/scripts/contracts/agentspec-evals.ts +101 -39
- package/.claude/skills/mutagent-evaluator/scripts/contracts/eval-matrix.ts +287 -3
- package/.claude/skills/mutagent-evaluator/scripts/contracts/eval-types.ts +30 -4
- 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/merge-criteria.ts +849 -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 +2 -1
- package/.claude/skills/mutagent-evaluator/scripts/render-review-report-v3.ts +691 -0
- package/.claude/skills/mutagent-evaluator/scripts/route-failures.ts +10 -7
- package/.claude/skills/mutagent-evaluator/scripts/run-evaluate.ts +46 -1
- package/.claude/skills/mutagent-evaluator/scripts/run-review.ts +266 -0
- package/.claude/skills/mutagent-evaluator/scripts/verify-render.ts +728 -0
- package/package.json +2 -2
|
@@ -0,0 +1,560 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en"><head><meta charset="utf-8">
|
|
3
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
4
|
+
<link rel="icon" href="data:,">
|
|
5
|
+
<title>@@TITLE@@</title>
|
|
6
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
7
|
+
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
|
8
|
+
<style>
|
|
9
|
+
:root{--bg:#0a0a12;--surf:#14141d;--surf2:#1a1a25;--surf3:#22222f;--border:rgba(255,255,255,.09);--borderS:rgba(255,255,255,.16);
|
|
10
|
+
--fg:#d6dbe6;--fgS:#eef1f6;--muted:#8a8698;--dim:#5a5667;--primary:#7E47D7;--primarySoft:#b794f4;--cyan:#45b8cc;
|
|
11
|
+
--pass:#43c39a;--fail:#e06666;--warn:#e8a64d;--pass-bg:rgba(67,195,154,.16);--fail-bg:rgba(224,102,102,.16);--warn-bg:rgba(232,166,77,.16);
|
|
12
|
+
--hm-pass:rgba(67,195,154,.38);--hm-fail:rgba(224,102,102,.42);--hm-indet:rgba(232,166,77,.40);--hm-skip:#22222f;
|
|
13
|
+
--font:'Space Grotesk',system-ui,sans-serif;--mono:'IBM Plex Mono',ui-monospace,monospace}
|
|
14
|
+
*{box-sizing:border-box;border-radius:0}
|
|
15
|
+
body{margin:0;background:var(--bg);color:var(--fg);font-family:var(--font);font-size:14px;line-height:1.5;padding-bottom:120px}
|
|
16
|
+
.wrap{max-width:1180px;margin:0 auto;padding:0 22px 40px}
|
|
17
|
+
.hdr{position:sticky;top:0;z-index:40;background:rgba(10,10,18,.94);backdrop-filter:blur(8px);border-bottom:1px solid var(--border);padding:11px 22px;display:flex;align-items:center;gap:12px;flex-wrap:wrap}
|
|
18
|
+
.wm{font-weight:700;font-size:18px;letter-spacing:.5px}
|
|
19
|
+
.wm b{background:linear-gradient(90deg,var(--primarySoft),var(--cyan));-webkit-background-clip:text;background-clip:text;color:transparent}
|
|
20
|
+
.mockbadge{font-family:var(--mono);font-size:10px;letter-spacing:.1em;color:var(--warn);border:1px solid var(--warn);padding:2px 8px}
|
|
21
|
+
.progress{margin-left:auto;display:flex;align-items:center;gap:9px;font-family:var(--mono);font-size:11px;color:var(--muted)}
|
|
22
|
+
.progress .pt{width:150px;height:8px;background:var(--surf3);border:1px solid var(--border)}
|
|
23
|
+
.progress .pf{height:100%;background:linear-gradient(90deg,var(--primary),var(--cyan))}
|
|
24
|
+
#submitbtn{font-family:var(--mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;padding:6px 14px;background:var(--surf2);border:1px solid var(--pass);color:var(--pass);cursor:pointer}
|
|
25
|
+
.panel{border:1px solid var(--border);background:var(--surf);margin-top:14px}
|
|
26
|
+
.panel-h{display:flex;align-items:center;gap:8px;padding:9px 15px;border-bottom:1px solid var(--border);font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--primarySoft);background:var(--surf2)}
|
|
27
|
+
.panel-h .r{margin-left:auto;color:var(--muted);text-transform:none}
|
|
28
|
+
.panel-b{padding:13px 15px}
|
|
29
|
+
.chip{font-family:var(--mono);font-size:11px;color:var(--muted);border:1px solid var(--border);padding:1px 6px}
|
|
30
|
+
.verd{font-family:var(--mono);font-size:11px;font-weight:700;padding:2px 8px;border:1px solid}
|
|
31
|
+
.verd.pass{color:var(--pass);border-color:var(--pass)} .verd.fail{color:var(--fail);border-color:var(--fail)} .verd.inc{color:var(--warn);border-color:var(--warn)}
|
|
32
|
+
.explain{font-size:14px;line-height:1.6;color:var(--muted);border-left:3px solid var(--cyan);background:rgba(69,184,204,.05);padding:8px 13px;margin:0 0 14px;max-width:88ch}
|
|
33
|
+
.explain b{color:var(--fg)}
|
|
34
|
+
.hero{padding:26px 0 10px;border-bottom:1px solid var(--border);margin-bottom:6px}
|
|
35
|
+
.hero .who{font-family:var(--mono);font-size:11.5px;color:var(--cyan);text-transform:uppercase;letter-spacing:.14em;margin-bottom:7px}
|
|
36
|
+
.hero h1{font-size:clamp(24px,3.4vw,32px);margin:0 0 8px;color:var(--fgS);letter-spacing:-.01em;font-weight:700}
|
|
37
|
+
.hero p{font-size:15.5px;color:var(--muted);max-width:88ch;margin:0 0 8px;line-height:1.65}
|
|
38
|
+
.hero p b{color:var(--fg)}
|
|
39
|
+
.hero .meta{display:flex;gap:8px;flex-wrap:wrap;margin-top:6px}
|
|
40
|
+
/* subject profile card (mirrors the eval report triple card) */
|
|
41
|
+
.profgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:0;border:1px solid var(--border);background:var(--surf2);margin:12px 0 2px}
|
|
42
|
+
.profgrid>div{padding:11px 14px;border-right:1px solid var(--border)}
|
|
43
|
+
.profgrid>div:last-child{border-right:0}
|
|
44
|
+
.pk{font-family:var(--mono);font-size:11px;color:var(--dim);text-transform:uppercase;letter-spacing:.06em;margin-bottom:4px}
|
|
45
|
+
.pv{font-size:14px;color:var(--muted);line-height:1.55}
|
|
46
|
+
.pv b{color:var(--fg)}
|
|
47
|
+
.toolb{font-family:var(--mono);font-size:12px;padding:2px 8px;border:1px solid;margin:2px 4px 2px 0;display:inline-block}
|
|
48
|
+
.toolb.read{color:var(--cyan);border-color:rgba(69,184,204,.6)}
|
|
49
|
+
.toolb.act{color:var(--warn);border-color:rgba(232,166,77,.6)}
|
|
50
|
+
.toolb,.idc,.chip{display:inline-flex;align-items:center;height:20px;line-height:1;box-sizing:border-box}
|
|
51
|
+
.idc{font-family:var(--mono);font-size:12px;padding:0 8px;border:1px solid;margin:5px 4px 2px 0}
|
|
52
|
+
.idc.k{color:var(--primarySoft);border-color:rgba(126,71,215,.6)}
|
|
53
|
+
.idc.m{color:var(--cyan);border-color:rgba(69,184,204,.6)}
|
|
54
|
+
.idc.f{color:var(--warn);border-color:rgba(232,166,77,.6)}
|
|
55
|
+
.lstrip{display:inline-flex;gap:3px;vertical-align:middle}
|
|
56
|
+
.lstrip u{font-family:var(--mono);font-size:11px;text-decoration:none;padding:1px 5px;border:1px solid var(--border);color:var(--dim)}
|
|
57
|
+
.lstrip u.pass{color:var(--pass);border-color:var(--pass)} .lstrip u.fail{color:var(--fail);border-color:var(--fail)}
|
|
58
|
+
.lstrip u.undecidable{color:var(--warn);border-color:var(--warn)} .lstrip u.skip{color:var(--dim);border-style:dashed}
|
|
59
|
+
.lstrip u.fired{color:var(--cyan);border-color:var(--cyan)}
|
|
60
|
+
.confbadge{font-family:var(--mono);font-size:11px;color:var(--fail);border:1px solid var(--fail);padding:1px 6px}
|
|
61
|
+
.vq{border:1px dashed var(--cyan);background:rgba(69,184,204,.05);padding:8px 11px;margin:14px 0}
|
|
62
|
+
.vq .q{font-family:var(--mono);font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--cyan);margin-bottom:5px}
|
|
63
|
+
.vq .opts{display:flex;gap:6px;flex-wrap:wrap}
|
|
64
|
+
.vq .opts button{font-family:var(--mono);font-size:11px;padding:3px 11px;background:var(--surf2);border:1px solid var(--border);color:var(--muted);cursor:pointer}
|
|
65
|
+
.vq .opts button.on{border-color:var(--cyan);color:var(--cyan);background:rgba(69,184,204,.12)}
|
|
66
|
+
/* trace navigator — MATRIX: criteria rows × trace columns (evaluator-report idiom) */
|
|
67
|
+
.navmx{display:grid;gap:3px;align-items:stretch}
|
|
68
|
+
.nmh{border:1px solid rgba(126,71,215,.55);background:var(--surf2);cursor:pointer;padding:5px 4px 4px;text-align:center;position:relative;transition:outline-color .12s}
|
|
69
|
+
.nmh:hover{outline:2px solid var(--primarySoft);outline-offset:1px}
|
|
70
|
+
.nmh:hover::after{content:"▸ open";position:absolute;bottom:-15px;left:50%;transform:translateX(-50%);font-size:11px;color:var(--primarySoft);font-family:var(--mono);white-space:nowrap}
|
|
71
|
+
.nmh.sel{outline:2px solid var(--cyan);outline-offset:1px;background:var(--surf3)}
|
|
72
|
+
.nmh .hid{font-family:var(--mono);font-size:12.5px;font-weight:700;color:var(--fgS);display:block}
|
|
73
|
+
.nmh .hgate{font-family:var(--mono);font-size:11px;font-weight:700}
|
|
74
|
+
.nmh .hgate.pass{color:var(--pass)} .nmh .hgate.fail{color:var(--fail)} .nmh .hgate.incomplete{color:var(--warn)}
|
|
75
|
+
.nmh .hconf{color:var(--fail);font-size:11px}
|
|
76
|
+
.nmh .hrv{font-family:var(--mono);font-size:11px;color:var(--cyan);display:block}
|
|
77
|
+
.nml{font-family:var(--mono);font-size:12px;color:var(--fg);text-align:right;padding-right:10px;display:flex;align-items:center;justify-content:flex-end;white-space:nowrap;height:26px}
|
|
78
|
+
.nml i{font-style:normal;color:var(--dim);margin-left:6px;font-size:11px;border:1px solid var(--border);padding:0 5px}
|
|
79
|
+
.nmcorner{font-family:var(--mono);font-size:11px;color:var(--dim);display:flex;align-items:flex-end;justify-content:flex-end;padding:0 10px 4px 0}
|
|
80
|
+
#copyhandoff{background:var(--surf2);border:1px solid var(--pass);color:var(--pass);font-family:var(--mono);font-size:12px;letter-spacing:.05em;padding:7px 14px;cursor:pointer;margin-top:10px}
|
|
81
|
+
#copyhandoff.done{background:var(--pass-bg)}
|
|
82
|
+
.nmc{height:26px;border:1px solid rgba(0,0,0,.35);cursor:pointer}
|
|
83
|
+
.nmc.pass{background:var(--hm-pass)} .nmc.fail{background:var(--hm-fail)} .nmc.uncertain{background:var(--hm-indet)} .nmc.skip{background:var(--hm-skip)}
|
|
84
|
+
.nmc:hover{outline:1px solid var(--primarySoft)}
|
|
85
|
+
.nmc.selc{outline:1px solid var(--cyan)}
|
|
86
|
+
/* (retired tile styles kept for reference) */
|
|
87
|
+
.navgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(172px,1fr));gap:8px}
|
|
88
|
+
.ntile{border:1px solid rgba(126,71,215,.55);background:var(--surf2);cursor:pointer;position:relative;padding:8px 10px 8px;transition:outline-color .12s,transform .12s}
|
|
89
|
+
.ntile:hover{outline:2px solid var(--primarySoft);outline-offset:1px;transform:translateY(-1px)}
|
|
90
|
+
.ntile:hover::after{content:"▸ open";position:absolute;top:8px;right:9px;font-size:11.5px;color:var(--primarySoft);font-family:var(--mono)}
|
|
91
|
+
.ntile.sel{outline:2px solid var(--cyan);outline-offset:1px;background:var(--surf3)}
|
|
92
|
+
.ntile.sel::after{content:"▾ open";position:absolute;top:8px;right:9px;font-size:11.5px;color:var(--cyan);font-family:var(--mono)}
|
|
93
|
+
.ntile .nid{font-family:var(--mono);font-size:14px;font-weight:700;color:var(--fgS)}
|
|
94
|
+
.ntile .nsc{font-size:12.5px;color:var(--muted);margin:2px 0 7px}
|
|
95
|
+
.ntile .ngate{font-family:var(--mono);font-size:11.5px;font-weight:700;padding:1px 7px;border:1px solid;margin-left:6px;vertical-align:1px}
|
|
96
|
+
.ntile .ngate.pass{color:var(--pass);border-color:var(--pass)} .ntile .ngate.fail{color:var(--fail);border-color:var(--fail)} .ntile .ngate.incomplete{color:var(--warn);border-color:var(--warn)}
|
|
97
|
+
.ntile .nconf{color:var(--fail);font-size:13px;margin-left:5px}
|
|
98
|
+
.ntile .nrv{font-family:var(--mono);font-size:11.5px;color:var(--cyan);margin-left:6px}
|
|
99
|
+
.critrow{display:flex;gap:2px}
|
|
100
|
+
.critrow u{flex:1;height:17px;text-decoration:none;border:1px solid rgba(0,0,0,.35);display:flex;align-items:center;justify-content:center;font-family:var(--mono);font-size:10px;color:rgba(255,255,255,.85)}
|
|
101
|
+
.critrow u.pass{background:var(--hm-pass)} .critrow u.fail{background:var(--hm-fail)} .critrow u.uncertain{background:var(--hm-indet)} .critrow u.skip{background:var(--hm-skip);color:var(--dim)}
|
|
102
|
+
#tip{display:none;position:fixed;z-index:60;background:var(--surf3);border:1px solid var(--primarySoft);padding:9px 12px;font-size:14px;color:var(--fg);max-width:340px;pointer-events:none;box-shadow:0 6px 20px rgba(0,0,0,.5);line-height:1.5}
|
|
103
|
+
#tip .t1{font-family:var(--mono);font-weight:700;color:var(--fgS);font-size:14px}
|
|
104
|
+
#tip .t2{color:var(--muted);margin-top:2px}
|
|
105
|
+
#tip .t3{font-family:var(--mono);font-size:11.5px;color:var(--primarySoft);margin-top:4px}
|
|
106
|
+
.legend{display:flex;gap:14px;flex-wrap:wrap;font-family:var(--mono);font-size:12.5px;color:var(--muted);margin-top:10px}
|
|
107
|
+
.legend i{font-style:normal}
|
|
108
|
+
.legend .sw{display:inline-block;width:11px;height:11px;vertical-align:-1px;margin-right:5px;border:1px solid rgba(0,0,0,.4)}
|
|
109
|
+
/* trace panel */
|
|
110
|
+
.tpanel{border:1px solid var(--borderS);background:var(--bg);margin-top:14px}
|
|
111
|
+
.tpanel-h{position:sticky;top:52px;z-index:20;display:flex;gap:8px;align-items:center;flex-wrap:wrap;padding:8px 13px;background:var(--surf2);border-bottom:1px solid var(--borderS)}
|
|
112
|
+
.tpanel-h .tid{font-family:var(--mono);font-weight:600;color:var(--fgS)}
|
|
113
|
+
.tnav{font-family:var(--mono);font-size:11px;padding:3px 12px;background:rgba(126,71,215,.12);border:1px solid var(--primary);color:var(--primarySoft);cursor:pointer;font-weight:600}
|
|
114
|
+
.tnav:hover{color:var(--fgS);border-color:var(--primarySoft);background:rgba(126,71,215,.25)}
|
|
115
|
+
.tprog{font-family:var(--mono);font-size:12px;color:var(--cyan)}
|
|
116
|
+
.tracelabel{display:flex;gap:5px;align-items:center;font-family:var(--mono);font-size:11px;color:var(--muted)}
|
|
117
|
+
.tracelabel b{padding:2px 8px;border:1px solid var(--border);color:var(--fg);cursor:pointer;font-size:11px}
|
|
118
|
+
.tracelabel b.on-pass{border-color:var(--pass);color:var(--pass);background:var(--pass-bg)}
|
|
119
|
+
.tracelabel b.on-fail{border-color:var(--fail);color:var(--fail);background:var(--fail-bg)}
|
|
120
|
+
.tracelabel b.on-defer{border-color:var(--warn);color:var(--warn);background:var(--warn-bg)}
|
|
121
|
+
.tnote{background:var(--bg);border:1px solid var(--border);color:var(--fg);font-family:var(--font);font-size:13px;padding:3px 8px;width:220px}
|
|
122
|
+
.cbanner{margin:8px 13px;padding:7px 11px;border:1px solid var(--fail);background:var(--fail-bg);font-size:12px;color:var(--fg)}
|
|
123
|
+
.vwrap{display:grid;grid-template-columns:1fr 360px;gap:0;align-items:start}
|
|
124
|
+
.railcol{border-left:1px solid var(--border);padding:6px 10px;background:var(--surf2);align-self:stretch}
|
|
125
|
+
.step{display:flex;gap:10px;padding:8px 13px}
|
|
126
|
+
.step.divg{border-left:3px solid var(--fail)}
|
|
127
|
+
.step .n{font-family:var(--mono);font-size:11px;color:var(--dim);min-width:18px;padding-top:3px}
|
|
128
|
+
.step .body{flex:1;min-width:0}
|
|
129
|
+
.step .tool{font-family:var(--mono);font-size:14px;color:var(--cyan)}
|
|
130
|
+
.step .tool .args{color:var(--dim)}
|
|
131
|
+
.ltag{font-family:var(--mono);font-size:11px;color:var(--primarySoft);border:1px solid rgba(126,71,215,.5);padding:0 4px;margin-left:6px}
|
|
132
|
+
.divmark{font-family:var(--mono);font-size:11px;color:var(--fail);margin-left:8px}
|
|
133
|
+
.out{font-family:var(--mono);font-size:14px;color:var(--muted);background:var(--bg);border:1px solid var(--border);padding:4px 8px;margin-top:4px;overflow-wrap:anywhere}
|
|
134
|
+
.out mark{background:rgba(67,195,154,.25);color:var(--fgS);padding:0 2px}
|
|
135
|
+
.srow{border-bottom:1px solid var(--border)}
|
|
136
|
+
.vcard{border:1px solid var(--border);background:var(--surf);margin:10px 0;padding:0;font-size:14px}
|
|
137
|
+
.vcard .vh{display:flex;gap:10px;align-items:center;flex-wrap:wrap;padding:9px 12px;border-bottom:1px solid var(--border);background:var(--surf3)}
|
|
138
|
+
.vcard .vh .cid{font-weight:700;color:var(--fgS);font-size:14.5px}
|
|
139
|
+
.vpill{font-family:var(--mono);font-size:12px;font-weight:700;padding:3px 10px;border:1px solid;letter-spacing:.04em}
|
|
140
|
+
.vpill.pass{color:var(--pass);border-color:var(--pass);background:var(--pass-bg)}
|
|
141
|
+
.vpill.fail{color:var(--fail);border-color:var(--fail);background:var(--fail-bg)}
|
|
142
|
+
.vpill.uncertain{color:var(--warn);border-color:var(--warn);background:var(--warn-bg)}
|
|
143
|
+
.vsec{padding:8px 12px;border-bottom:1px solid var(--border)}
|
|
144
|
+
.vsec:last-child{border-bottom:0}
|
|
145
|
+
.vlab{font-family:var(--mono);font-size:11px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--primarySoft);margin-bottom:4px}
|
|
146
|
+
.vcard .stmt{color:var(--fg);font-size:14px;line-height:1.55}
|
|
147
|
+
.vcard .defs{font-size:14px;color:var(--muted);margin-top:4px;line-height:1.55}
|
|
148
|
+
.vcard .defs b{color:var(--fg)}
|
|
149
|
+
.vcard .crit{color:var(--muted);font-size:14px;line-height:1.6}
|
|
150
|
+
.vcard .ref{font-family:var(--mono);font-size:13px;color:var(--fg);background:var(--bg);border:1px solid var(--border);padding:4px 8px;display:inline-block}
|
|
151
|
+
.vcard .ref b{color:var(--pass)}
|
|
152
|
+
.arr{display:flex;gap:5px;align-items:center;margin-top:7px;flex-wrap:wrap}
|
|
153
|
+
.arr span{font-family:var(--mono);font-size:11px;color:var(--dim);text-transform:uppercase;letter-spacing:.06em}
|
|
154
|
+
.arr b{font-family:var(--mono);font-size:12px;padding:3px 11px;border:1px solid var(--border);color:var(--muted);cursor:pointer}
|
|
155
|
+
.arr b.on-agree{border-color:var(--pass);color:var(--pass);background:var(--pass-bg)}
|
|
156
|
+
.arr b.on-revise{border-color:var(--warn);color:var(--warn);background:var(--warn-bg)}
|
|
157
|
+
.arr b.on-refute{border-color:var(--fail);color:var(--fail);background:var(--fail-bg)}
|
|
158
|
+
.arr input{flex:1;min-width:180px;background:var(--bg);border:1px solid var(--border);color:var(--fg);font-size:14px;padding:8px 10px;font-family:var(--font)}
|
|
159
|
+
.outpill{font-family:var(--mono);font-size:12.5px;font-weight:700;padding:3px 11px;border:1px solid}
|
|
160
|
+
.outpill.pass{color:var(--pass);border-color:var(--pass);background:var(--pass-bg)}
|
|
161
|
+
.outpill.fail{color:var(--fail);border-color:var(--fail);background:var(--fail-bg)}
|
|
162
|
+
.outpill.undecidable{color:var(--warn);border-color:var(--warn);background:var(--warn-bg)}
|
|
163
|
+
.confpill{font-family:var(--mono);font-size:12.5px;font-weight:700;padding:3px 11px;border:1px solid var(--primary);color:var(--primarySoft);background:rgba(126,71,215,.16)}
|
|
164
|
+
#trail{display:none;border:1px solid var(--pass);background:var(--surf);margin:16px 0}
|
|
165
|
+
#trail.show{display:block}
|
|
166
|
+
#trail .th{display:flex;gap:9px;align-items:center;padding:9px 14px;border-bottom:1px solid var(--border);background:var(--pass-bg);font-family:var(--mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--pass)}
|
|
167
|
+
#trail .tb{padding:11px 15px}
|
|
168
|
+
.trow{display:flex;gap:10px;align-items:flex-start;padding:7px 0;border-bottom:1px dashed var(--border);font-size:14px;color:var(--muted)}
|
|
169
|
+
.trow .tk{font-family:var(--mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--primarySoft);min-width:150px;padding-top:2px}
|
|
170
|
+
.trow b{color:var(--fg)}
|
|
171
|
+
.foot{margin-top:32px;color:var(--dim);font-size:11px;border-top:1px solid var(--border);padding-top:12px;font-family:var(--mono)}
|
|
172
|
+
#fbpanel{position:fixed;bottom:0;left:0;right:0;background:rgba(10,10,18,.97);border-top:1px solid var(--primary);padding:9px 22px 11px;z-index:50}
|
|
173
|
+
#fbpanel .frow{max-width:1180px;margin:0 auto;display:flex;gap:12px;align-items:flex-end}
|
|
174
|
+
#fbpanel label{font-family:var(--mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--primarySoft);display:block;margin-bottom:4px}
|
|
175
|
+
#fbtext{flex:1;background:var(--surf2);border:1px solid var(--border);color:var(--fg);font-family:var(--font);font-size:13px;padding:7px 10px;min-height:40px;max-height:110px;resize:vertical}
|
|
176
|
+
#fbcopy{background:var(--surf2);border:1px solid var(--primary);color:var(--primarySoft);font-family:var(--mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;padding:10px 16px;cursor:pointer;white-space:nowrap}
|
|
177
|
+
#fbcopy.done{border-color:var(--pass);color:var(--pass)}
|
|
178
|
+
@media(max-width:900px){.vwrap{grid-template-columns:1fr}.railcol{border-left:0;border-top:1px solid var(--border)}}
|
|
179
|
+
</style></head><body>
|
|
180
|
+
<div class="hdr">
|
|
181
|
+
<div class="wm">MUTAGENT<b>/evaluator</b> · Review Report</div>
|
|
182
|
+
<div class="progress"><span id="progtext">…</span><div class="pt"><div class="pf" id="progfill" style="width:0%"></div></div>
|
|
183
|
+
<button id="submitbtn" onclick="submitReview()">Submit review</button></div>
|
|
184
|
+
@@HEADER_RIGHT@@
|
|
185
|
+
</div>
|
|
186
|
+
<div class="wrap">
|
|
187
|
+
|
|
188
|
+
<div class="hero" data-component="mgt-report-hero">
|
|
189
|
+
<div class="who">Human-in-the-loop · calibration surface</div>
|
|
190
|
+
<h1>@@HERO_TITLE@@</h1>
|
|
191
|
+
<p>@@HERO_LEDE@@</p>
|
|
192
|
+
<div class="meta">@@HERO_META@@</div>
|
|
193
|
+
</div>
|
|
194
|
+
|
|
195
|
+
<!-- whose traces are these -->
|
|
196
|
+
@@SUBJECT_CARD@@
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
<!-- TRACE NAVIGATOR -->
|
|
200
|
+
<div class="panel"><div class="panel-h">trace navigator <span class="r"><b style="color:var(--primarySoft)">criteria = rows · traces = columns</b> · click a column header (or any cell) to open that trajectory below</span></div><div class="panel-b" style="padding-top:16px">
|
|
201
|
+
<div id="navhost" data-component="mgt-trace-navigator"></div>
|
|
202
|
+
<div class="legend">
|
|
203
|
+
<i><span class="sw" style="background:var(--hm-pass)"></span>criterion pass</i>
|
|
204
|
+
<i><span class="sw" style="background:var(--hm-fail)"></span>criterion fail</i>
|
|
205
|
+
<i><span class="sw" style="background:var(--hm-indet)"></span>undecided</i>
|
|
206
|
+
<i><span class="sw" style="background:var(--hm-skip)"></span>not judged (truncated)</i>
|
|
207
|
+
<i>✓/✗ chip = trace gate</i>
|
|
208
|
+
<i style="color:var(--fail)">⚡ layer conflict</i>
|
|
209
|
+
<i style="color:var(--cyan)">✓ done = fully reviewed</i>
|
|
210
|
+
<i>keys: ←/→ switch · 1/2/D label</i>
|
|
211
|
+
</div>
|
|
212
|
+
</div></div>
|
|
213
|
+
|
|
214
|
+
<!-- OPEN TRACE PANEL -->
|
|
215
|
+
<div id="tracehost"></div>
|
|
216
|
+
|
|
217
|
+
<div id="trail" data-component="mgt-propagation-trail"><div class="th">✓ feedback recorded — propagation trail</div><div class="tb" id="trailbody"></div></div>
|
|
218
|
+
<div id="tip" data-component="mgt-trace-tooltip"></div>
|
|
219
|
+
|
|
220
|
+
<div class="foot">@@FOOT@@</div>
|
|
221
|
+
</div>
|
|
222
|
+
|
|
223
|
+
<div id="fbpanel" data-component="mgt-feedback-bar"><div class="frow">
|
|
224
|
+
<div style="flex:1"><label for="fbtext">@@FEEDBACK_LABEL@@</label>
|
|
225
|
+
<textarea id="fbtext" placeholder="e.g. 'navigator cells need trace duration' …"></textarea></div>
|
|
226
|
+
<button id="fbcopy" type="button">Copy MD</button>
|
|
227
|
+
</div></div>
|
|
228
|
+
|
|
229
|
+
<script>window.ASTER=@@DATA_JSON@@;
|
|
230
|
+
window.ASTER.cellFor=function(id,tr){return ((tr.cells||{})[id])||'skip';};</script>
|
|
231
|
+
<script>
|
|
232
|
+
var place='rail', hl='mark', openTrace=(window.ASTER&&ASTER.openTrace)||null;
|
|
233
|
+
var labels={}, traceLabels={}, noteCache={};
|
|
234
|
+
var SCENS=(window.ASTER&&ASTER.scenarios)||[];
|
|
235
|
+
|
|
236
|
+
function esc(s){return s.split('&').join('&').split('<').join('<');}
|
|
237
|
+
function vKey(tid,six,vix){return tid+'·s'+six+'·v'+vix;}
|
|
238
|
+
function critOf(cid){var c=null;ASTER.criteria.forEach(function(x){if(x.id===cid)c=x;});return c;}
|
|
239
|
+
function traceVerdictCount(tr){var n=0;tr.steps.forEach(function(s){n+=(s.verdicts||[]).length;});return n;}
|
|
240
|
+
function traceReviewed(tr){var n=0;tr.steps.forEach(function(s,six){(s.verdicts||[]).forEach(function(vd,vix){if(labels[vKey(tr.id,six,vix)])n++;});});return n;}
|
|
241
|
+
|
|
242
|
+
/* ── navigator — MATRIX: criteria rows × trace columns ── */
|
|
243
|
+
var LSHORT={outcome:'outc',trajectory:'traj','tool-outputs':'tools',context:'ctx'};
|
|
244
|
+
var CLUSTER_AT=48, navWin=0;
|
|
245
|
+
function navWindowSize(){return Math.max(10,Math.ceil(ASTER.traces.length/20));}
|
|
246
|
+
|
|
247
|
+
/* mgt-trace-matrix — criteria rows × trace columns, for any trace subset */
|
|
248
|
+
function matrixHtml(T){
|
|
249
|
+
var h='<div class="navmx" data-component="mgt-trace-matrix" style="grid-template-columns:255px repeat('+T.length+',minmax(56px,1fr));align-items:center">';
|
|
250
|
+
h+='<span class="nmcorner">criteria ↓ · traces →</span>';
|
|
251
|
+
T.forEach(function(tr){
|
|
252
|
+
var total=traceVerdictCount(tr),done=traceReviewed(tr);
|
|
253
|
+
h+='<div class="nmh'+(openTrace===tr.id?' sel':'')+'" onclick="openT(\''+tr.id+'\')" '
|
|
254
|
+
+'onmouseenter="showTip(event,\''+tr.id+'\')" onmousemove="moveTip(event)" onmouseleave="hideTip()">'
|
|
255
|
+
+'<span class="hid">'+tr.id+'</span>'
|
|
256
|
+
+'<span class="hgate '+tr.gate+'">'+(tr.gate==='pass'?'✓':tr.gate==='fail'?'✗':'◔')+'</span>'
|
|
257
|
+
+(tr.conflict?'<span class="hconf">⚡</span>':'')
|
|
258
|
+
+(total>0&&done===total?'<span class="hrv">✓done</span>':(done>0?'<span class="hrv">'+done+'/'+total+'</span>':'<span class="hrv"> </span>'))
|
|
259
|
+
+'</div>';
|
|
260
|
+
});
|
|
261
|
+
ASTER.criteria.forEach(function(c){
|
|
262
|
+
h+='<span class="nml">'+c.id+' '+c.slug+'<i>'+(LSHORT[c.layer]||c.layer)+'</i></span>';
|
|
263
|
+
T.forEach(function(tr){
|
|
264
|
+
var st=ASTER.cellFor(c.id,tr);
|
|
265
|
+
h+='<span class="nmc '+(st==='undecidable'?'uncertain':st)+(openTrace===tr.id?' selc':'')+'" '
|
|
266
|
+
+'onclick="openT(\''+tr.id+'\')" title="'+tr.id+' × '+c.id+' '+c.slug+': '+st+'"></span>';
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
return h+'</div>';
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/* mgt-window-cluster — large-corpus mode: windows of 25, pass-rate cells (production ehm idiom) */
|
|
273
|
+
function clusterHtml(wins){
|
|
274
|
+
var h='<div class="explain" style="margin-bottom:10px"><b>Large corpus ('+ASTER.traces.length+' traces):</b> traces are grouped into windows of '+navWindowSize()+'. '
|
|
275
|
+
+'Each cell shows the criterion\'s health over that window (<b style="color:var(--pass)">green ≥95% pass</b> · <b style="color:var(--warn)">amber ≥80%</b> · <b style="color:var(--fail)">red <80%</b>; the number = failures). '
|
|
276
|
+
+'Click a window → its per-trace matrix opens below → click a trace to review it.</div>';
|
|
277
|
+
h+='<div class="navmx" data-component="mgt-window-cluster" style="grid-template-columns:255px repeat('+wins.length+',minmax(50px,1fr));align-items:center">';
|
|
278
|
+
h+='<span class="nmcorner">criteria ↓ · windows →</span>';
|
|
279
|
+
wins.forEach(function(w,wi){
|
|
280
|
+
var fails=0;w.forEach(function(t){if(t.gate==='fail')fails++;});
|
|
281
|
+
var cls=fails===0?'pass':(fails<=3?'incomplete':'fail');
|
|
282
|
+
var conf=w.some(function(t){return t.conflict;});
|
|
283
|
+
h+='<div class="nmh'+(navWin===wi?' sel':'')+'" onclick="selWin('+wi+')" title="traces '+w[0].id+' … '+w[w.length-1].id+' · '+fails+' gate-fails of '+w.length+'">'
|
|
284
|
+
+'<span class="hid">'+w[0].id+'–'+w[w.length-1].id+'</span>'
|
|
285
|
+
+'<span class="hgate '+cls+'">'+fails+'✗</span>'+(conf?'<span class="hconf">⚡</span>':'')
|
|
286
|
+
+'</div>';
|
|
287
|
+
});
|
|
288
|
+
ASTER.criteria.forEach(function(c){
|
|
289
|
+
h+='<span class="nml">'+c.id+' '+c.slug+'<i>'+(LSHORT[c.layer]||c.layer)+'</i></span>';
|
|
290
|
+
wins.forEach(function(w,wi){
|
|
291
|
+
var f=0,u=0;
|
|
292
|
+
w.forEach(function(tr){var st=ASTER.cellFor(c.id,tr);if(st==='fail')f++;else if(st!=='pass')u++;});
|
|
293
|
+
var rate=Math.round(100*(w.length-f-u)/w.length);
|
|
294
|
+
var cls=rate>=95?'pass':(rate>=80?'uncertain':'fail');
|
|
295
|
+
h+='<span class="nmc '+cls+(navWin===wi?' selc':'')+'" onclick="selWin('+wi+')" '
|
|
296
|
+
+'title="'+c.id+' × window '+(wi+1)+': '+f+' fail · '+u+' undecided of '+w.length+'" '
|
|
297
|
+
+'style="display:flex;align-items:center;justify-content:center;font-family:var(--mono);font-size:11px;color:rgba(255,255,255,.82)">'
|
|
298
|
+
+(f?f+'✗':'')+'</span>';
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
h+='</div>';
|
|
302
|
+
return h;
|
|
303
|
+
}
|
|
304
|
+
function selWin(wi){persistNotes();navWin=wi;
|
|
305
|
+
var w=windowsOf(ASTER.traces)[wi];
|
|
306
|
+
if(w&&w.indexOf(traceById(openTrace))<0){openTrace=w[0].id;}
|
|
307
|
+
renderNav();renderTrace();updateProg();}
|
|
308
|
+
function windowsOf(T){var w=[];var W=navWindowSize();for(var i=0;i<T.length;i+=W)w.push(T.slice(i,i+W));return w;}
|
|
309
|
+
function traceById(id){var t=null;ASTER.traces.forEach(function(x){if(x.id===id)t=x;});return t;}
|
|
310
|
+
|
|
311
|
+
function renderNav(){
|
|
312
|
+
var T=ASTER.traces,host=document.getElementById('navhost');
|
|
313
|
+
if(T.length<=CLUSTER_AT){host.innerHTML=matrixHtml(T);return;}
|
|
314
|
+
var wins=windowsOf(T);
|
|
315
|
+
if(navWin>=wins.length)navWin=0;
|
|
316
|
+
var h=clusterHtml(wins);
|
|
317
|
+
h+='<div class="h4s" style="margin-top:18px">Window '+(navWin+1)+' of '+wins.length+' — '+wins[navWin][0].id+' … '+wins[navWin][wins[navWin].length-1].id+' — pick a trace</div>';
|
|
318
|
+
h+=matrixHtml(wins[navWin]);
|
|
319
|
+
host.innerHTML=h;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/* ── trace panel ── */
|
|
323
|
+
function vcardHtml(tid,six,vd,vix){
|
|
324
|
+
var key=vKey(tid,six,vix),lab=labels[key]||'',c=critOf(vd.crit);
|
|
325
|
+
return '<div class="vcard" data-component="mgt-verdict-card">'
|
|
326
|
+
+'<div class="vh"><span class="cid">'+vd.crit+' · '+(c?c.slug:'')+'</span>'
|
|
327
|
+
+'<span class="vpill '+vd.verdict+'">VERDICT: '+vd.verdict.toUpperCase()+'</span>'
|
|
328
|
+
+'<span class="ltag">layer: '+(c?c.layer:'')+'</span></div>'
|
|
329
|
+
+(c?'<div class="vsec"><div class="vlab">what it checks</div><div class="stmt">'+esc(c.statement)+'</div>'
|
|
330
|
+
+'<div class="defs"><b>passes:</b> '+esc(c.passDef)
|
|
331
|
+
+(c.failDef?' · <b>fails:</b> '+esc(c.failDef)
|
|
332
|
+
:' · <b>fails:</b> no explicit fail condition is recorded for this criterion — a fail is the negation of the pass condition above')
|
|
333
|
+
+'</div></div>':'')
|
|
334
|
+
+'<div class="vsec"><div class="vlab">judge\'s reasoning · confidence .'+Math.round(vd.conf*100)+'</div>'
|
|
335
|
+
+'<div class="crit">'+esc(vd.critique)+'</div></div>'
|
|
336
|
+
+'<div class="vsec"><div class="vlab">evidence</div>'
|
|
337
|
+
+(vd.ref?'<div class="ref">'+vd.ref.obs+' · '+vd.ref.path+' = <b>"'+esc(vd.ref.value)+'"</b></div>'
|
|
338
|
+
:'<div class="ref" style="color:var(--warn)">'+(vd.verdict==='uncertain'
|
|
339
|
+
?'abstained — no evidence could bind; the open question is recorded'
|
|
340
|
+
:'decided without a structured evidence ref — this verdict is UNGROUNDED, weigh it accordingly')+'</div>')+'</div>'
|
|
341
|
+
+'<div class="vsec"><div class="vlab">your ruling — this note becomes calibration ground truth</div><div class="arr">'
|
|
342
|
+
+'<b class="'+(lab==='agree'?'on-agree':'')+'" onclick="setLab(\''+key+'\',\'agree\')">Agree</b>'
|
|
343
|
+
+'<b class="'+(lab==='revise'?'on-revise':'')+'" onclick="setLab(\''+key+'\',\'revise\')">Revise</b>'
|
|
344
|
+
+'<b class="'+(lab==='refute'?'on-refute':'')+'" onclick="setLab(\''+key+'\',\'refute\')">Refute</b>'
|
|
345
|
+
+'<input placeholder="Explain your ruling" id="note-'+key+'"></div></div></div>';
|
|
346
|
+
}
|
|
347
|
+
function outHtml(s,refs){
|
|
348
|
+
var body=esc(s.output);
|
|
349
|
+
if(hl==='mark'){(refs||[]).forEach(function(r){if(r&&r.value){var ev=esc(r.value);body=body.split(ev).join('<mark>'+ev+'</mark>');}});
|
|
350
|
+
return '<div class="out">'+body+'</div>';}
|
|
351
|
+
var h='<div class="out">'+body;
|
|
352
|
+
(refs||[]).forEach(function(r){if(r&&r.value){h+='<span style="display:block;border-left:3px solid var(--pass);background:var(--pass-bg);padding:2px 7px;margin-top:4px;color:var(--fgS)">▸ cited: "'+esc(r.value)+'"</span>';}});
|
|
353
|
+
return h+'</div>';
|
|
354
|
+
}
|
|
355
|
+
function renderTrace(){
|
|
356
|
+
var tr=null,idx=-1;ASTER.traces.forEach(function(t,i){if(t.id===openTrace){tr=t;idx=i;}});
|
|
357
|
+
var host=document.getElementById('tracehost');if(!tr){host.innerHTML='';return;}
|
|
358
|
+
var total=traceVerdictCount(tr),done=traceReviewed(tr),tl=traceLabels[tr.id]||'';
|
|
359
|
+
var h='<div class="tpanel" data-component="mgt-trace-drill"><div class="tpanel-h" data-component="mgt-drill-header">'
|
|
360
|
+
+'<span class="tnav" onclick="navT(-1)">← prev</span><span class="tnav" onclick="navT(1)">next →</span>'
|
|
361
|
+
+'<span class="tid">'+tr.id+'</span><span class="chip">'+tr.scenario+'</span>'
|
|
362
|
+
+stripH(tr)
|
|
363
|
+
+(tr.gate==='pass'?'<span class="verd pass">GATE ✓</span>':tr.gate==='fail'?'<span class="verd fail">GATE ✗</span>':'<span class="verd inc">INC</span>')
|
|
364
|
+
+(tr.conflict?'<span class="confbadge">⚡</span>':'')
|
|
365
|
+
+'<span class="tprog">'+done+'/'+total+' reviewed</span>'
|
|
366
|
+
+'<span class="tracelabel">trace:'
|
|
367
|
+
+'<b class="'+(tl==='pass'?'on-pass':'')+'" onclick="setTrace(\''+tr.id+'\',\'pass\')">Pass·1</b>'
|
|
368
|
+
+'<b class="'+(tl==='fail'?'on-fail':'')+'" onclick="setTrace(\''+tr.id+'\',\'fail\')">Fail·2</b>'
|
|
369
|
+
+'<b class="'+(tl==='defer'?'on-defer':'')+'" onclick="setTrace(\''+tr.id+'\',\'defer\')">Defer·D</b></span>'
|
|
370
|
+
+'<span style="margin-left:auto;display:inline-flex;gap:7px;align-items:center">'
|
|
371
|
+
+'<span class="outpill '+tr.outcome.verdict+'">outcome '+tr.outcome.verdict.toUpperCase()+'</span>'
|
|
372
|
+
+'<span class="confpill">judge conf .'+Math.round(tr.judgeConf*100)+'</span></span>'
|
|
373
|
+
+'</div>';
|
|
374
|
+
h+='<div class="explain" style="margin:10px 13px"><b>'+tr.id+' — what happened:</b> '
|
|
375
|
+
+(tr.outcome.verdict==='pass'?'the session reached its expected exit ('+esc(tr.outcome.expected)+').':'expected '+esc(tr.outcome.expected)+' — actual: '+esc(tr.outcome.actual)+'.')
|
|
376
|
+
+(tr.divergence?' <b>First divergence:</b> '+esc(tr.divergence)+'.':'')
|
|
377
|
+
+(tr.gapKind?' <b>Context-gap kind:</b> '+tr.gapKind+'.':'')
|
|
378
|
+
+(tr.blockedBy?' <b>Open question:</b> '+esc(tr.blockedBy):'')+'</div>';
|
|
379
|
+
if(tr.conflict) h+='<div class="cbanner">⚡ '+esc(tr.conflictNote)+' — your Agree/Refute on '
|
|
380
|
+
+((tr.conflictCards&&tr.conflictCards.length)?('the '+tr.conflictCards.join(' and ')+' card'+(tr.conflictCards.length>1?'s':'')+' below'):'the verdict cards below')
|
|
381
|
+
+' IS the adjudication of this conflict.</div>';
|
|
382
|
+
if(tr.fidelity) h+='<div class="cbanner" style="border-color:var(--warn);background:var(--warn-bg)">◔ '+esc(tr.fidelity)+'</div>';
|
|
383
|
+
tr.steps.forEach(function(s,six){
|
|
384
|
+
var core='<span class="tool">'+s.tool+' <span class="args">'+esc(s.args)+'</span></span>';
|
|
385
|
+
(s.layers||[]).forEach(function(L){core+='<span class="ltag">'+L+'</span>';});
|
|
386
|
+
if(s.divergence) core+='<span class="divmark">◆ first divergence</span>';
|
|
387
|
+
core+=outHtml(s,(s.verdicts||[]).map(function(vd){return vd.ref;}));
|
|
388
|
+
var cards='';(s.verdicts||[]).forEach(function(vd,vix){cards+=vcardHtml(tr.id,six,vd,vix);});
|
|
389
|
+
if(place==='stack'){
|
|
390
|
+
h+='<div class="srow"><div class="step'+(s.divergence?' divg':'')+'"><span class="n">'+(six+1)+'</span><div class="body">'+core+cards+'</div></div></div>';
|
|
391
|
+
}else{
|
|
392
|
+
h+='<div class="srow vwrap"><div class="step'+(s.divergence?' divg':'')+'"><span class="n">'+(six+1)+'</span><div class="body">'+core+'</div></div>'
|
|
393
|
+
+'<div class="railcol">'+(cards||'<div style="font-family:var(--mono);font-size:11px;color:var(--dim);padding:6px 0">no judge verdicts bind at this step</div>')+'</div></div>';
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
h+='</div>';
|
|
397
|
+
host.innerHTML=h;restoreNotes();
|
|
398
|
+
}
|
|
399
|
+
function stripH(tr){
|
|
400
|
+
var h='<span class="lstrip">';
|
|
401
|
+
['L0','L1','L2','L3','L4'].forEach(function(L){
|
|
402
|
+
var st=tr.layers[L]||'skip';var sym=st==='pass'?'✓':st==='fail'?'✗':st==='undecidable'?'?':st==='fired'?'⚑':'→';
|
|
403
|
+
h+='<u class="'+st+'">'+L+sym+'</u>';});
|
|
404
|
+
return h+'</span>';
|
|
405
|
+
}
|
|
406
|
+
/* ── tooltip ── */
|
|
407
|
+
function showTip(e,id){
|
|
408
|
+
var tr=null;ASTER.traces.forEach(function(t){if(t.id===id)tr=t;});if(!tr)return;
|
|
409
|
+
var total=traceVerdictCount(tr),done=traceReviewed(tr);
|
|
410
|
+
var tip=document.getElementById('tip');
|
|
411
|
+
tip.innerHTML='<div class="t1">'+tr.id+' · '+tr.scenario+'</div>'
|
|
412
|
+
+'<div class="t2">'+(tr.outcome.verdict==='pass'?('reached expected exit: '+esc(tr.outcome.expected)):('expected '+esc(tr.outcome.expected)+' — actual: '+esc(tr.outcome.actual)))+'</div>'
|
|
413
|
+
+'<div class="t2">gate <b style="color:'+(tr.gate==='pass'?'var(--pass)':tr.gate==='fail'?'var(--fail)':'var(--warn)')+'">'+tr.gate.toUpperCase()+'</b>'
|
|
414
|
+
+(tr.conflict?' · <b style="color:var(--fail)">⚡ layer conflict</b>':'')
|
|
415
|
+
+' · '+done+'/'+total+' reviewed</div>'
|
|
416
|
+
+'<div class="t3">▸ click to open this trajectory</div>';
|
|
417
|
+
tip.style.display='block';moveTip(e);
|
|
418
|
+
}
|
|
419
|
+
function moveTip(e){var tip=document.getElementById('tip');
|
|
420
|
+
var x=e.clientX+14,y=e.clientY+14;
|
|
421
|
+
if(x+340>window.innerWidth)x=e.clientX-350;if(y+90>window.innerHeight)y=e.clientY-100;
|
|
422
|
+
tip.style.left=x+'px';tip.style.top=y+'px';}
|
|
423
|
+
function hideTip(){document.getElementById('tip').style.display='none';}
|
|
424
|
+
/* ── state ── */
|
|
425
|
+
function openT(id){persistNotes();hideTip();openTrace=id;renderNav();renderTrace();updateProg();}
|
|
426
|
+
function navT(d){var i=-1;ASTER.traces.forEach(function(t,k){if(t.id===openTrace)i=k;});
|
|
427
|
+
var n=(i+d+ASTER.traces.length)%ASTER.traces.length;openT(ASTER.traces[n].id);}
|
|
428
|
+
function setLab(key,val){labels[key]=val;persistNotes();renderNav();renderTrace();updateProg();}
|
|
429
|
+
function setTrace(tid,val){traceLabels[tid]=val;persistNotes();renderNav();renderTrace();updateProg();}
|
|
430
|
+
function persistNotes(){document.querySelectorAll('input[id^=note-],input[id^=tnote-]').forEach(function(i){if(i.value)noteCache[i.id]=i.value;});}
|
|
431
|
+
function restoreNotes(){for(var id in noteCache){var el=document.getElementById(id);if(el)el.value=noteCache[id];}}
|
|
432
|
+
function updateProg(){
|
|
433
|
+
var total=0;ASTER.traces.forEach(function(tr){total+=traceVerdictCount(tr);});
|
|
434
|
+
var done=Object.keys(labels).length;
|
|
435
|
+
var hc=document.getElementById('herocount');if(hc)hc.textContent=ASTER.traces.length+' sessions · '+total+' judge verdicts to review';
|
|
436
|
+
var pc=document.getElementById('profcorpus');if(pc)pc.textContent=ASTER.traces.length+' traces';
|
|
437
|
+
document.getElementById('progtext').textContent=done+'/'+total+' verdicts · '+Object.keys(traceLabels).length+'/'+ASTER.traces.length+' traces';
|
|
438
|
+
document.getElementById('progfill').style.width=(total?Math.round(done*100/total):0)+'%';
|
|
439
|
+
}
|
|
440
|
+
function buildHandoffMd(){
|
|
441
|
+
persistNotes();
|
|
442
|
+
var agree=0,revise=0,refute=0;
|
|
443
|
+
for(var k in labels){if(labels[k]==='agree')agree++;else if(labels[k]==='revise')revise++;else refute++;}
|
|
444
|
+
var L=[];
|
|
445
|
+
L.push(ASTER.handoffHead||'# Calibration Handoff');
|
|
446
|
+
L.push('**Rulings:** '+Object.keys(labels).length+' verdict rulings ('+agree+' agree · '+revise+' revise · '+refute+' refute) · '
|
|
447
|
+
+Object.keys(traceLabels).length+'/'+ASTER.traces.length+' trace labels · '+Object.keys(noteCache).length+' notes');
|
|
448
|
+
L.push('');
|
|
449
|
+
L.push(ASTER.calibrationMd||'');
|
|
450
|
+
L.push('## Human ↔ judge disagreement ledger');
|
|
451
|
+
var any=false;
|
|
452
|
+
for(var k2 in labels){ if(labels[k2]!=='agree'){any=true; L.push('- `'+k2+'` — judge verdict stands ↔ human ruled **'+labels[k2]+'**'+(noteCache['note-'+k2]?' — "'+noteCache['note-'+k2]+'"':'')); } }
|
|
453
|
+
if(!any)L.push('- none — no reviewed verdict was revised or refuted in this session');
|
|
454
|
+
L.push('');
|
|
455
|
+
L.push('## Trace labels (ground truth for *validate)');
|
|
456
|
+
L.push('\u0060\u0060\u0060json');L.push(JSON.stringify(traceLabels,null,2));L.push('\u0060\u0060\u0060');
|
|
457
|
+
L.push('');
|
|
458
|
+
L.push('## Conflict adjudication');
|
|
459
|
+
var CF=ASTER.conflicts||[];
|
|
460
|
+
if(!CF.length)L.push('- none — no cross-layer conflict was detected on this corpus');
|
|
461
|
+
CF.forEach(function(cf){
|
|
462
|
+
L.push('- '+cf.trace+' ⚡ '+cf.note+' → '+(labels[cf.key]?('human ruled '+cf.crit+' '+labels[cf.key]):'UNADJUDICATED — re-open in next review'));
|
|
463
|
+
});
|
|
464
|
+
L.push('');
|
|
465
|
+
L.push('### Next steps (in order)');
|
|
466
|
+
L.push('1. Merge labels.json via mergeLabels → `*validate`');
|
|
467
|
+
L.push('2. Operator approves/rejects each CAL item above (nothing auto-applies)');
|
|
468
|
+
L.push('3. `*evaluate` rerun (pinned) — confirm deltas + the conflict ledger clears');
|
|
469
|
+
return L.join('\n');
|
|
470
|
+
}
|
|
471
|
+
function copyHandoff(){
|
|
472
|
+
var md=buildHandoffMd();var btn=document.getElementById('copyhandoff');
|
|
473
|
+
function ok(){btn.classList.add('done');btn.textContent='✓ handoff copied — paste into the session';
|
|
474
|
+
setTimeout(function(){btn.classList.remove('done');btn.textContent='Copy calibration handoff (markdown)';},2200);}
|
|
475
|
+
if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(md).then(ok,function(){fbc(md);});}else{fbc(md);}
|
|
476
|
+
function fbc(t){var x=document.createElement('textarea');x.value=t;document.body.appendChild(x);x.select();
|
|
477
|
+
try{document.execCommand('copy');}catch(e){}document.body.removeChild(x);ok();}
|
|
478
|
+
}
|
|
479
|
+
function submitReview(){
|
|
480
|
+
persistNotes();
|
|
481
|
+
var agree=0,revise=0,refute=0;
|
|
482
|
+
for(var k in labels){if(labels[k]==='agree')agree++;else if(labels[k]==='revise')revise++;else refute++;}
|
|
483
|
+
var nL=Object.keys(labels).length,nT=Object.keys(traceLabels).length,nN=Object.keys(noteCache).length;
|
|
484
|
+
var rec=ASTER.feedbackRecord||null;
|
|
485
|
+
var cal=ASTER.calItems||[];
|
|
486
|
+
var CF=ASTER.conflicts||[];
|
|
487
|
+
var t=document.getElementById('trailbody');
|
|
488
|
+
var rows='';
|
|
489
|
+
/* the trail is an ORDERED sequence, so the step number is content, not chrome.
|
|
490
|
+
At the label's 11px a circled numeral measures 6.8px — a ring with an
|
|
491
|
+
unreadable digit (measured against a 6.6px tofu box, i.e. barely wider than
|
|
492
|
+
nothing). Rendered one size up it reads, and the sequence survives. */
|
|
493
|
+
function n(g){return '<span style="font-size:15px;vertical-align:-2px">'+g+'</span> ';}
|
|
494
|
+
/* an inline list of every item does not scale — six near-identical rows made the
|
|
495
|
+
queue unreadable on a 12-trace corpus. Cap it and DECLARE the cap; the full
|
|
496
|
+
list always lives in the handoff markdown. */
|
|
497
|
+
var CAP=4;
|
|
498
|
+
function capped(list,render){
|
|
499
|
+
var shown=list.slice(0,CAP).map(render).join(' · ');
|
|
500
|
+
return list.length>CAP?shown+' — <b>+'+(list.length-CAP)+' more</b> (showing first '+CAP+'; the full list is in the handoff markdown)':shown;
|
|
501
|
+
}
|
|
502
|
+
rows+='<div class="trow"><span class="tk">'+n('①')+'record receipt</span><div>'
|
|
503
|
+
+(rec?('<b>'+rec.id+'</b>'+(rec.store?' appended to '+rec.store+' (append-only)':'')+' — '):'<b>not yet written</b> — no append-only feedback store is configured for this run, so this session is held in the browser only; ')
|
|
504
|
+
+nL+' verdict rulings ('+agree+' agree · '+revise+' revise · '+refute+' refute) · '+nT+' trace labels · '+nN+' notes</div></div>';
|
|
505
|
+
rows+='<div class="trow"><span class="tk">'+n('②')+'validation delta</span><div>'
|
|
506
|
+
+(ASTER.validationDelta||'<b>not computed in this session</b> — TPR/TNR, Rogan-Gladen θ and the bootstrap CI are produced by <b>*validate</b> when it ingests these labels. No delta is shown because none exists yet.')
|
|
507
|
+
+'</div></div>';
|
|
508
|
+
rows+='<div class="trow"><span class="tk">'+n('③')+'calibration queue</span><div>'
|
|
509
|
+
+(cal.length?('<b>'+cal.length+' proposal(s) (operator-gated, nothing auto-applies):</b> '+capped(cal,function(c){return c.title;})):'<b>no calibration proposal is derivable from this run</b> — no abstain and no cross-layer conflict gave a trigger. Your rulings are still recorded.')
|
|
510
|
+
+'</div></div>';
|
|
511
|
+
var unadj=CF.filter(function(cf){return !labels[cf.key];}).length;
|
|
512
|
+
rows+='<div class="trow"><span class="tk">'+n('④')+'conflict adjudication</span><div>'
|
|
513
|
+
+(CF.length?('<b>'+CF.length+' conflict(s) · '+(CF.length-unadj)+' ruled · '+unadj+' unadjudicated:</b> '
|
|
514
|
+
+capped(CF,function(cf){return cf.trace+' ⚡ '+(labels[cf.key]?(cf.crit+' '+labels[cf.key]):'unadjudicated');})
|
|
515
|
+
+' — feeds the conflict ledger (humans resolve, code never does)')
|
|
516
|
+
:'no cross-layer conflict was detected on this corpus — nothing to adjudicate')
|
|
517
|
+
+'</div></div>';
|
|
518
|
+
rows+='<div class="trow"><span class="tk">'+n('⑤')+'exports</span><div><b>labels.json</b> (superset — mergeLabels-compatible → *validate) · <b>review.md</b> (session paste-back)'
|
|
519
|
+
+(rec&&rec.store?' — written beside the feedback store':'')+'</div></div>';
|
|
520
|
+
rows+='<div class="trow" style="border-bottom:0"><span class="tk">'+n('⑥')+'formal handoff</span><div>The structured human-vs-judge calibration task — the calibration agent completes it from this document alone.<br><button id="copyhandoff" onclick="copyHandoff()">Copy calibration handoff (markdown)</button></div></div>';
|
|
521
|
+
t.innerHTML=rows;
|
|
522
|
+
document.getElementById('trail').classList.add('show');
|
|
523
|
+
document.getElementById('trail').scrollIntoView({behavior:'smooth'});
|
|
524
|
+
}
|
|
525
|
+
document.addEventListener('keydown',function(e){
|
|
526
|
+
if(e.target && (e.target.tagName==='INPUT'||e.target.tagName==='TEXTAREA')) return;
|
|
527
|
+
if(e.key==='ArrowLeft')navT(-1); else if(e.key==='ArrowRight')navT(1);
|
|
528
|
+
else if(e.key==='1')setTrace(openTrace,'pass'); else if(e.key==='2')setTrace(openTrace,'fail');
|
|
529
|
+
else if(e.key==='d'||e.key==='D')setTrace(openTrace,'defer');
|
|
530
|
+
});
|
|
531
|
+
function setPlace(v,btn){persistNotes();place=v;vqOn(btn);renderTrace();}
|
|
532
|
+
function setHl(v,btn){persistNotes();hl=v;vqOn(btn);renderTrace();}
|
|
533
|
+
function vqOn(btn){btn.parentElement.querySelectorAll('button').forEach(function(b){b.classList.remove('on');});btn.classList.add('on');}
|
|
534
|
+
renderNav();renderTrace();updateProg();
|
|
535
|
+
(function(){
|
|
536
|
+
var btn=document.getElementById('fbcopy'),ta=document.getElementById('fbtext');
|
|
537
|
+
if(!btn||!ta)return;
|
|
538
|
+
function buildMd(){
|
|
539
|
+
persistNotes();
|
|
540
|
+
var lines=['## Feedback — '+(ASTER.feedbackTitle||document.title),'','Artifact: `'+(ASTER.artifactPath||'review-report.html')+'`'];
|
|
541
|
+
lines.push('','### Review interaction state');
|
|
542
|
+
lines.push('- verdict rulings: '+Object.keys(labels).length+' set');
|
|
543
|
+
for(var k in labels){lines.push(' - '+k+' → '+labels[k]);}
|
|
544
|
+
lines.push('- trace labels: '+JSON.stringify(traceLabels));
|
|
545
|
+
var noted=false;
|
|
546
|
+
for(var id in noteCache){if(!noted){lines.push('- notes:');noted=true;}lines.push(' - '+id+': '+noteCache[id]);}
|
|
547
|
+
lines.push('','### Notes');
|
|
548
|
+
var note=ta.value.trim();lines.push(note.length?note:'_(no notes entered)_');
|
|
549
|
+
return lines.join('\n');
|
|
550
|
+
}
|
|
551
|
+
function done(){btn.classList.add('done');btn.textContent='Copied ✓';setTimeout(function(){btn.classList.remove('done');btn.textContent='Copy MD';},1800);}
|
|
552
|
+
btn.addEventListener('click',function(){
|
|
553
|
+
var md=buildMd();
|
|
554
|
+
if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(md).then(done,function(){fb(md);});}else{fb(md);}
|
|
555
|
+
function fb(t){var x=document.createElement('textarea');x.value=t;document.body.appendChild(x);x.select();
|
|
556
|
+
try{document.execCommand('copy');}catch(e){}document.body.removeChild(x);done();}
|
|
557
|
+
});
|
|
558
|
+
})();
|
|
559
|
+
</script>
|
|
560
|
+
</body></html>
|