skalpel 4.0.43 → 4.0.45
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/card.mjs +64 -12
- package/first-run.mjs +722 -0
- package/metrics.mjs +35 -1
- package/package.json +1 -1
- package/skalpel-hook.mjs +165 -28
- package/skalpel-setup.mjs +8 -0
- package/verify-races.test.mjs +182 -0
- package/verify-shadow.mjs +60 -10
package/card.mjs
CHANGED
|
@@ -69,7 +69,20 @@ export function isGenuineCatch(row) {
|
|
|
69
69
|
// Ship-status catches (category:"ship", outcome SHIP_FAIL) record the check under probe_command, not
|
|
70
70
|
// proof_command — accept either so a genuine "you said deployed, it's 404" catch is not invisible.
|
|
71
71
|
const command = row.proof_command || row.probe_command;
|
|
72
|
-
|
|
72
|
+
if (!failed || !command || !row.claim_text) return false;
|
|
73
|
+
// RETRO catches (category:"retro") are RECORDED at claim time — never re-run. The whole indictment rests
|
|
74
|
+
// on the exit code the transcript already recorded, so a retro row is a genuine catch ONLY when it carries
|
|
75
|
+
// that recorded non-zero exit code; without it we can't render the "already failed" provenance truthfully.
|
|
76
|
+
if (row.category === "retro") {
|
|
77
|
+
return Number.isInteger(row.recorded_exit_code) && row.recorded_exit_code !== 0;
|
|
78
|
+
}
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// A retro row is RECORDED at claim time (from the user's own transcript), never re-run — so its wording
|
|
83
|
+
// must never borrow the live card's "skalpel re-ran its own proof" language.
|
|
84
|
+
function isRetro(row) {
|
|
85
|
+
return row && row.category === "retro";
|
|
73
86
|
}
|
|
74
87
|
|
|
75
88
|
// readCatches() → all genuine-catch rows in the shadow log, oldest→newest as written. Fail-open: any
|
|
@@ -133,9 +146,17 @@ export function extractCode(evidence) {
|
|
|
133
146
|
|
|
134
147
|
// verdictPhrase(row) → the honest one-line verdict. Always truthful for a catch row.
|
|
135
148
|
function verdictPhrase(row) {
|
|
136
|
-
const code = extractCode(row.evidence);
|
|
137
149
|
const failN = extractFailCount(row.evidence);
|
|
138
150
|
const count = failN != null ? ` · ${failN} failing` : "";
|
|
151
|
+
// RETRO: the exit code was RECORDED in the transcript at claim time — we never re-ran it, so the verdict
|
|
152
|
+
// must say "had already failed", never "re-ran". recorded_exit_code is a required field for a retro catch.
|
|
153
|
+
if (isRetro(row)) {
|
|
154
|
+
const n = Number.isInteger(row.recorded_exit_code)
|
|
155
|
+
? ` (recorded exit ${row.recorded_exit_code})`
|
|
156
|
+
: "";
|
|
157
|
+
return `FAIL — its own test had already failed when it said this${n}${count}`;
|
|
158
|
+
}
|
|
159
|
+
const code = extractCode(row.evidence);
|
|
139
160
|
if (code && code.kind === "http") return `FAIL — its own proof got HTTP ${code.value}${count}`;
|
|
140
161
|
if (code && code.kind === "exit") return `FAIL — its own proof exited ${code.value}${count}`;
|
|
141
162
|
return `FAIL — its own proof re-ran and exited non-zero${count}`;
|
|
@@ -152,13 +173,18 @@ export function renderPlainCard(row) {
|
|
|
152
173
|
const claim = clean(row.claim_text, 200) || "it's done";
|
|
153
174
|
const proof = clean(row.proof_command || row.probe_command, 200) || "its own proof";
|
|
154
175
|
const evidence = clean(row.evidence, 200);
|
|
176
|
+
const retro = isRetro(row);
|
|
155
177
|
const L = [];
|
|
156
|
-
L.push("🔬 skalpel — verified catch");
|
|
178
|
+
L.push(retro ? "🔬 skalpel — recorded catch" : "🔬 skalpel — verified catch");
|
|
157
179
|
L.push("");
|
|
158
180
|
L.push("The agent claimed:");
|
|
159
181
|
L.push(` "${claim}"`);
|
|
160
182
|
L.push("");
|
|
161
|
-
L.push(
|
|
183
|
+
L.push(
|
|
184
|
+
retro
|
|
185
|
+
? "Its own test had already failed when it said this — recorded in your transcript at claim time:"
|
|
186
|
+
: "skalpel re-ran the agent's OWN proof, out-of-band:",
|
|
187
|
+
);
|
|
162
188
|
L.push(` $ ${proof}`);
|
|
163
189
|
L.push(` → ${verdictPhrase(row)}`);
|
|
164
190
|
if (evidence) {
|
|
@@ -167,8 +193,16 @@ export function renderPlainCard(row) {
|
|
|
167
193
|
L.push(` ${evidence}`);
|
|
168
194
|
}
|
|
169
195
|
L.push("");
|
|
170
|
-
L.push(
|
|
171
|
-
|
|
196
|
+
L.push(
|
|
197
|
+
retro
|
|
198
|
+
? `recorded ${stamp(row.ts)} (your transcript, at claim time)`
|
|
199
|
+
: `caught ${stamp(row.ts)}`,
|
|
200
|
+
);
|
|
201
|
+
L.push(
|
|
202
|
+
retro
|
|
203
|
+
? "The agent said done. Its own test, recorded at that moment, had already failed."
|
|
204
|
+
: "The agent said done. Its own proof, re-run, disagreed.",
|
|
205
|
+
);
|
|
172
206
|
return L.join("\n");
|
|
173
207
|
}
|
|
174
208
|
|
|
@@ -177,13 +211,18 @@ export function renderMarkdownCard(row) {
|
|
|
177
211
|
const claim = clean(row.claim_text, 200) || "it's done";
|
|
178
212
|
const proof = clean(row.proof_command || row.probe_command, 200) || "its own proof";
|
|
179
213
|
const evidence = clean(row.evidence, 200);
|
|
214
|
+
const retro = isRetro(row);
|
|
180
215
|
const FENCE = "```";
|
|
181
216
|
const L = [];
|
|
182
|
-
L.push("**🔬 skalpel — verified catch**");
|
|
217
|
+
L.push(retro ? "**🔬 skalpel — recorded catch**" : "**🔬 skalpel — verified catch**");
|
|
183
218
|
L.push("");
|
|
184
219
|
L.push(`> The agent claimed: _"${claim}"_`);
|
|
185
220
|
L.push("");
|
|
186
|
-
L.push(
|
|
221
|
+
L.push(
|
|
222
|
+
retro
|
|
223
|
+
? "Its own test had already failed when it said this — recorded in your transcript at claim time:"
|
|
224
|
+
: "skalpel re-ran the agent's own proof, out-of-band:",
|
|
225
|
+
);
|
|
187
226
|
L.push(FENCE);
|
|
188
227
|
L.push(`$ ${proof}`);
|
|
189
228
|
L.push(`→ ${verdictPhrase(row)}`);
|
|
@@ -194,7 +233,11 @@ export function renderMarkdownCard(row) {
|
|
|
194
233
|
L.push(evidence);
|
|
195
234
|
L.push(FENCE);
|
|
196
235
|
}
|
|
197
|
-
L.push(
|
|
236
|
+
L.push(
|
|
237
|
+
retro
|
|
238
|
+
? `_Recorded ${stamp(row.ts)} in your transcript, at claim time. The agent said done; its own test had already failed._`
|
|
239
|
+
: `_Caught ${stamp(row.ts)}. The agent said done; its own proof, re-run, disagreed._`,
|
|
240
|
+
);
|
|
198
241
|
return L.join("\n");
|
|
199
242
|
}
|
|
200
243
|
|
|
@@ -203,14 +246,21 @@ function renderTerminalCard(row) {
|
|
|
203
246
|
const claim = clean(row.claim_text, 200) || "it's done";
|
|
204
247
|
const proof = clean(row.proof_command || row.probe_command, 200) || "its own proof";
|
|
205
248
|
const evidence = clean(row.evidence, 180);
|
|
249
|
+
const retro = isRetro(row);
|
|
206
250
|
const L = [];
|
|
207
251
|
L.push("");
|
|
208
|
-
L.push(
|
|
252
|
+
L.push(
|
|
253
|
+
` ${B}🔬 skalpel${X} ${D}·${X} ${B}${R}${retro ? "recorded catch" : "verified catch"}${X}`,
|
|
254
|
+
);
|
|
209
255
|
L.push(` ${D}${"─".repeat(70)}${X}`);
|
|
210
256
|
L.push(` ${D}The agent claimed:${X}`);
|
|
211
257
|
L.push(` ${B}"${claim}"${X}`);
|
|
212
258
|
L.push("");
|
|
213
|
-
L.push(
|
|
259
|
+
L.push(
|
|
260
|
+
retro
|
|
261
|
+
? ` ${D}Its own test had already failed when it said this — recorded at claim time:${X}`
|
|
262
|
+
: ` ${D}skalpel re-ran the agent's OWN proof, out-of-band:${X}`,
|
|
263
|
+
);
|
|
214
264
|
L.push(` ${D}$${X} ${proof}`);
|
|
215
265
|
L.push(` ${R}${B}→ ${verdictPhrase(row)}${X}`);
|
|
216
266
|
if (evidence) {
|
|
@@ -219,7 +269,9 @@ function renderTerminalCard(row) {
|
|
|
219
269
|
}
|
|
220
270
|
L.push(` ${D}${"─".repeat(70)}${X}`);
|
|
221
271
|
L.push(
|
|
222
|
-
|
|
272
|
+
retro
|
|
273
|
+
? ` ${D}recorded ${stamp(row.ts)} — the agent said done; its own test had already failed.${X}`
|
|
274
|
+
: ` ${D}caught ${stamp(row.ts)} — the agent said done; its own proof, re-run, disagreed.${X}`,
|
|
223
275
|
);
|
|
224
276
|
L.push("");
|
|
225
277
|
return L.join("\n");
|