@xaccefy/pi-casefile 0.10.1 → 0.11.0

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/src/index.ts CHANGED
@@ -12,20 +12,12 @@ import type { ExtensionAPI, ToolDefinition } from "@earendil-works/pi-coding-age
12
12
  import { matchesKey, Text, truncateToWidth } from "@earendil-works/pi-tui";
13
13
  import { type TSchema, Type } from "typebox";
14
14
  import {
15
- CANARY_ASSESSMENT_VALUES,
16
15
  CONFIRM_DIFFERENTIAL_VALUES,
17
16
  CONFIRM_VERDICT_VALUES,
18
- PANEL_VERDICT_VALUES,
19
17
  SEVERITY_MATCH_VALUES,
20
18
  validateMainAgentVerdict,
21
- validatePanelVotes,
22
19
  } from "./evidence.ts";
23
- import {
24
- controlTargetAuthorizationError,
25
- type HarnessVerifyResult,
26
- replayDifferential,
27
- replayIntraTarget,
28
- } from "./harness-verify.ts";
20
+ import { type HarnessVerifyResult, replayIntraTarget } from "./harness-verify.ts";
29
21
  import {
30
22
  addCaseResult,
31
23
  addEvidenceItemResult,
@@ -54,8 +46,6 @@ import {
54
46
  getCasefilePath,
55
47
  LINK_KIND_VALUES,
56
48
  linkCasesResult,
57
- type MainAgentVerification,
58
- type OobVerification,
59
49
  type PendingConfirmation,
60
50
  type PocEvidenceRun,
61
51
  PRIORITY_VALUES,
@@ -71,13 +61,6 @@ import {
71
61
  updateCaseResult,
72
62
  writeCaseContext,
73
63
  } from "./ledger.ts";
74
- import {
75
- type OobOracleConfig,
76
- type ProvisionedCallback,
77
- provisionCallback,
78
- readOobOracleConfig,
79
- verifyOobDifferential,
80
- } from "./oob-oracle.ts";
81
64
  import { type PocRun, type PocRunOptions, runPoc } from "./poc-runner.ts";
82
65
  import {
83
66
  detectWorkspaceRoot,
@@ -240,12 +223,13 @@ const CoverageAddSchema = Type.Object(
240
223
  // ── Tool: PromoteFinding (phase 1) / ConfirmFinding (phase 2) ──────────
241
224
  //
242
225
  // Confirmation is TWO-PHASE and main-agent-owned: PromoteFinding runs the PoC
243
- // 2x + control, validates nonce-bound evidence.json, and records the pending
244
- // bundle; ConfirmFinding then performs the main coordinator's review/replay and
226
+ // twice against the case target, validates nonce-bound evidence.json, replays
227
+ // the attack and baseline requests itself, and records the pending bundle;
228
+ // ConfirmFinding then performs the main coordinator's semantic review and
245
229
  // commits or refuses the verdict. Subagents may gather or challenge evidence,
246
230
  // but they cannot run validation or confirmation gates. Zero exit is necessary
247
- // run integrity and markers are diagnostic only; the machine records
248
- // predicate/canary differentials and the main agent owns the semantic judgment.
231
+ // run integrity and markers are diagnostic only; the machine records the
232
+ // predicate differential and the main agent owns the semantic judgment.
249
233
 
250
234
  const PromoteSchema = Type.Object(
251
235
  {
@@ -253,55 +237,12 @@ const PromoteSchema = Type.Object(
253
237
  poc_path: Type.String({
254
238
  description: "Absolute path to the PoC script on disk",
255
239
  }),
256
- control_path: Type.Optional(
257
- Type.String({
258
- description:
259
- "Optional absolute path to the SAME script as poc_path (sha256-equality is ENFORCED). Defaults to poc_path. The harness runs it with PI_POC_MODE=control and PI_POC_TARGET=control_target.",
260
- }),
261
- ),
262
- mode: Type.Optional(
263
- Type.String({
264
- enum: ["inter_host", "intra_target"],
265
- description:
266
- "Differential shape. 'inter_host' (default) proves target-dependence with a distinct patched control host — for body-carried proof (file read, injection exfil, info leak, reflection). 'intra_target' proves it with a legitimate same-host baseline request declared in the evidence — for access-control / business-logic classes (IDOR, auth bypass, privilege escalation, logic flaws) where the discriminating variable is identity or a parameter, not the host. In intra_target the evidence must set verify.mode='intra_target' and include a baseline; control_target/control_path are not used.",
267
- }),
268
- ),
269
- control_target: Type.Optional(
270
- Type.String({
271
- minLength: 1,
272
- description:
273
- "REQUIRED for mode='inter_host': a distinct baseline target that lacks the vulnerability and is operator-approved through PI_POC_CONTROL_TARGETS (patched replica, second account, baseline service). Not used for mode='intra_target'.",
274
- }),
275
- ),
276
240
  local: Type.Optional(
277
241
  Type.Boolean({
278
242
  description:
279
243
  "Run with network access instead of --network none. Requires operator authorization via PI_POC_ALLOW_NETWORK=1. True host fallback additionally requires PI_POC_ALLOW_LOCAL=1.",
280
244
  }),
281
245
  ),
282
- oob: Type.Optional(
283
- Type.Boolean({
284
- description:
285
- "Blind/OOB confirmation via the operator-run oracle (PI_OOB_ORACLE_URL). The harness provisions per-run callback tokens, injects PI_POC_CALLBACK_DOMAIN into the runs, and polls the oracle itself: promotion requires target-token interactions, ZERO control-token interactions, attested source separation (PI_OOB_SOURCE_SEPARATED=1), and self-source/missing-src_ip interactions are rejected. Without an oracle this fails closed.",
286
- }),
287
- ),
288
- panel_votes: Type.Optional(
289
- Type.Array(
290
- Type.Object(
291
- {
292
- verdict: Type.String({ enum: [...PANEL_VERDICT_VALUES] }),
293
- rationale: Type.String({ description: "Why this voter reached its verdict" }),
294
- model: Type.String({ description: "Which model voted" }),
295
- at: Type.Optional(Type.String({ description: "Vote timestamp (ISO)" })),
296
- },
297
- { additionalProperties: false },
298
- ),
299
- {
300
- description:
301
- "Optional pre-gate panel votes (≤5). CONFIRMED later requires a 2/3 exploit quorum or an explicit override note on the verdict; votes never commit anything.",
302
- },
303
- ),
304
- ),
305
246
  },
306
247
  { additionalProperties: false },
307
248
  );
@@ -321,12 +262,12 @@ const ConfirmSchema = Type.Object(
321
262
  re_execution_note: Type.Optional(
322
263
  Type.String({
323
264
  description:
324
- "What the main agent observed during review and the fresh harness-owned target/control replay. Mandatory for CONFIRMED.",
265
+ "What the main agent observed during review of the runs and transcripts. Mandatory for CONFIRMED.",
325
266
  }),
326
267
  ),
327
268
  differential: Type.String({
328
269
  enum: [...CONFIRM_DIFFERENTIAL_VALUES],
329
- description: "Target vs control evidence comparison. CONFIRMED requires target_only.",
270
+ description: "Attack vs baseline evidence comparison. CONFIRMED requires target_only.",
330
271
  }),
331
272
  severity_match: Type.Optional(
332
273
  Type.String({
@@ -340,25 +281,6 @@ const ConfirmSchema = Type.Object(
340
281
  "The main agent's own failed attempt to disprove — becomes the case's disconfirmation",
341
282
  }),
342
283
  ),
343
- canary_assessment: Type.Optional(
344
- Type.String({
345
- enum: [...CANARY_ASSESSMENT_VALUES],
346
- description:
347
- "verified when the replay carried a harness-generated reflection canary; otherwise not_applicable with a concrete reason",
348
- }),
349
- ),
350
- canary_reason: Type.Optional(
351
- Type.String({
352
- description:
353
- "Why a causal reflection canary is not meaningful for this exploit class. Required when canary_assessment=not_applicable.",
354
- }),
355
- ),
356
- panel_override_note: Type.Optional(
357
- Type.String({
358
- description:
359
- "Why CONFIRMED proceeds without a 2/3 exploit panel quorum (panel skipped, unavailable, or documented disagreement). Required for CONFIRMED whenever quorum was not reached.",
360
- }),
361
- ),
362
284
  model: Type.Optional(
363
285
  Type.String({ description: "Which model judged (recorded for the accuracy ledger)" }),
364
286
  ),
@@ -1005,19 +927,15 @@ export default function casefileExtension(pi: ExtensionAPI) {
1005
927
  name: "PromoteFinding",
1006
928
  label: "Run PoC Evidence",
1007
929
  description:
1008
- "Main-agent phase 1 of confirmation: run the same PoC twice against the case target and once against an operator-approved control_target, validate nonce-bound evidence.json with a response-body assertion, then have the harness execute one immutable HTTP request template against both target and control. control_path defaults to poc_path; if supplied, sha256 equality is enforced. The machine records a predicate differential, or a stronger canary differential when a reflection placeholder is requested and observed only on target; neither is automatically a vulnerability verdict. Exit 0 is necessary run integrity, never proof. Networked execution, controls, and private replay are operator-gated. Blind/OOB confirmation fails closed until source separation exists. Records a pending bundle for main-agent semantic review via ConfirmFinding. Worker/subagent processes are rejected.",
1009
- promptSnippet:
1010
- "Phase 1: run PoC evidence (target x2 + control) and record the pending bundle",
930
+ "Main-agent phase 1 of confirmation: run the same PoC twice against the case target, validate nonce-bound evidence.json with a response-body assertion, then have the harness replay the attack request and a legitimate same-host baseline request itself. The machine records a predicate differential (attack matched, baseline did not); that is not automatically a vulnerability verdict. Exit 0 is necessary run integrity, never proof. Networked execution and private replay are operator-gated. Records a pending bundle for main-agent semantic review via ConfirmFinding. Worker/subagent processes are rejected.",
931
+ promptSnippet: "Phase 1: run PoC evidence (target x2) and record the pending bundle",
1011
932
  promptGuidelines: [
1012
933
  "Use PromoteFinding only from the main/coordinator agent when an investigating case has a concrete PoC script on disk and you are ready to subject its claim to the machine gate.",
1013
934
  "Prerequisites: status='investigating' and non-empty poc, evidence, impact, severity, target, plus an artifact-backed EvidenceAdd 'observation' item on the case (the initial signal, with artifact_path). The final disconfirmation comes from the main agent at confirm time.",
1014
- "The PoC MUST write evidence.json to $PI_POC_EVIDENCE_DIR: { nonce (echo $PI_POC_NONCE), claim, verify: { method, url, expect: { status?, body_contains/body_regex } }, observations }. A non-empty body predicate is mandatory; status-only evidence is rejected. verify.url must belong to the case target.",
1015
- "For reflection-capable requests, place {{PI_POC_CANARY}} exactly once in verify.url/body/header values and declare verify.canary={mode:'reflection',placeholder:'{{PI_POC_CANARY}}'}. The harness substitutes an unpredictable value only after the PoC exits and requires target-only reflection; the raw token is not persisted.",
1016
- "control_path is optional and defaults to poc_path; if supplied, it must be the SAME script as poc_path. control_target must be pre-approved by the operator in PI_POC_CONTROL_TARGETS. The harness derives the control request from the target request, changes only its origin, and applies the same predicates to two conclusive responses.",
1017
- "oob=true unlocks blind/OOB classes (SSRF, blind XSS, XXE): the harness provisions per-run callback tokens via the operator's oracle (PI_OOB_ORACLE_URL), injects PI_POC_CALLBACK_DOMAIN into the runs, and polls the oracle itself — target-token interactions with ZERO control-token interactions are required. Promotion additionally requires attested source separation (PI_OOB_SOURCE_SEPARATED=1); without it the verification stays diagnostic.",
935
+ "The PoC MUST write evidence.json to $PI_POC_EVIDENCE_DIR: { nonce (echo $PI_POC_NONCE), claim, verify: { method, url, expect: { status?, body_contains/body_regex } }, observations, baseline }. A non-empty body predicate is mandatory; status-only evidence is rejected. verify.url and baseline.url must belong to the case target.",
936
+ "baseline is a legitimate same-host request whose response must NOT satisfy the attack predicate your own account's resource for IDOR, the request without the payload for injection. It must differ from the attack request (identity or a parameter, not just whitespace).",
1018
937
  "local:true requires PI_POC_ALLOW_NETWORK=1. Private/internal harness replay additionally requires PI_POC_ALLOW_PRIVATE_REPLAY=1. Neither silently falls back to a model verdict.",
1019
- "Blind/OOB classes fail closed unless the operator configured an OOB oracle; self-interactions (PI_OOB_SELF_IPS) are rejected and never counted as target hits.",
1020
- "After the bundle is recorded, stay in the main agent: inspect the script/evidence, attempt disconfirmation, and call ConfirmFinding itself; that call performs a fresh harness-owned target/control replay. Never delegate validation/confirmation and never CaseUpdate status='confirmed' directly.",
938
+ "After the bundle is recorded, stay in the main agent: inspect the script/evidence, attempt disconfirmation, and call ConfirmFinding yourself. Never delegate validation/confirmation and never CaseUpdate status='confirmed' directly.",
1021
939
  ],
1022
940
  parameters: PromoteSchema,
1023
941
 
@@ -1039,155 +957,60 @@ export default function casefileExtension(pi: ExtensionAPI) {
1039
957
  };
1040
958
 
1041
959
  const pocPath = (params.poc_path as string | undefined)?.trim() ?? "";
1042
- const controlPath = (params.control_path as string | undefined)?.trim() || pocPath;
1043
- const controlTarget = (params.control_target as string | undefined)?.trim() ?? "";
1044
- const mode: "inter_host" | "intra_target" =
1045
- (params.mode as string | undefined) === "intra_target" ? "intra_target" : "inter_host";
1046
- const isIntra = mode === "intra_target";
1047
960
  if (!pocPath) {
1048
961
  return fail("poc_path is REQUIRED: absolute path to the PoC script run by the harness.");
1049
962
  }
1050
963
  const caseTarget = current.target ?? "";
1051
- // Panel votes (advisory pre-gate): validated here so a malformed panel
1052
- // is rejected before any sandboxed run is paid for.
1053
- let panelVotes: PendingConfirmation["panelVotes"];
1054
- if (params.panel_votes !== undefined) {
1055
- const parsedVotes = validatePanelVotes(params.panel_votes);
1056
- if (!parsedVotes.ok) {
1057
- return fail(`Invalid panel_votes: ${parsedVotes.error}`);
1058
- }
1059
- panelVotes = parsedVotes.votes;
1060
- }
1061
- // ── OOB callback (Tier 1, opt-in for blind classes) ──
1062
- // The operator-run oracle owns the evidence channel; the harness owns
1063
- // the secret (per-run token, provisioned before the runs and injected
1064
- // as env — the value does not exist when the script was written).
1065
- // Without an oracle this stays fail-closed.
1066
- const oobRequested = params.oob === true;
1067
- // Intra-target + OOB is rejected up front: intra_target's
1068
- // discriminating variable is identity/parameter on the SAME host;
1069
- // mixing it with a callback differential would make precedence
1070
- // ambiguous. OOB is for inter-host/blind classes.
1071
- if (isIntra && oobRequested) {
1072
- return fail(
1073
- "mode:'intra_target' cannot be combined with oob:true — intra-target proof uses a same-host baseline request, not a callback channel. Use one or the other.",
1074
- );
1075
- }
1076
- let oobConfig: OobOracleConfig | undefined;
1077
- let targetCallback: ProvisionedCallback | undefined;
1078
- let controlCallback: ProvisionedCallback | undefined;
1079
- if (oobRequested) {
1080
- const oracle = readOobOracleConfig();
1081
- if (!oracle.config) {
1082
- return fail(`OOB CONFIRMATION UNAVAILABLE: ${oracle.error}`);
1083
- }
1084
- oobConfig = oracle.config;
1085
- // Provision both identities concurrently — each is an oracle round trip.
1086
- [targetCallback, controlCallback] = await Promise.all([
1087
- provisionCallback(oobConfig),
1088
- provisionCallback(oobConfig),
1089
- ]);
1090
- }
1091
- // OOB-only bundles (blind classes, no operator-approved control host)
1092
- // prove target-dependence via the token differential instead.
1093
- const oobOnly = oobRequested && !controlTarget;
1094
- if (!isIntra && !oobOnly) {
1095
- if (!controlTarget) {
1096
- return fail(
1097
- "control_target is REQUIRED for inter-host mode: a distinct baseline target that lacks the vulnerability. For access-control/logic bugs use mode='intra_target' with an evidence baseline instead; for blind/OOB classes pass oob=true (with or without a control target).",
1098
- );
1099
- }
1100
- if (controlTarget === current.target) {
1101
- return fail(
1102
- "control_target must differ from the case target; a control run against the vulnerable target proves nothing.",
1103
- );
1104
- }
1105
- }
1106
964
  if (params.local === true && process.env.PI_POC_ALLOW_NETWORK !== "1") {
1107
965
  return fail(
1108
966
  "Networked PoC execution is operator-gated. Set PI_POC_ALLOW_NETWORK=1 to authorize the host-network sandbox for this session.",
1109
967
  );
1110
968
  }
1111
- if (!isIntra && !oobOnly) {
1112
- const controlAuthorization = controlTargetAuthorizationError(controlTarget);
1113
- if (controlAuthorization) {
1114
- return fail(
1115
- `CONTROL AUTHORIZATION FAILED: ${controlAuthorization}. ` +
1116
- "The operator must set PI_POC_CONTROL_TARGETS to the exact approved control host/origin before this control can anchor confirmation.",
1117
- );
1118
- }
1119
- }
1120
969
 
1121
- // Anti-cheat: hash the PoC (always) and, for inter-host, require the
1122
- // control script to be the SAME bytes (differing only via harness env).
970
+ // Anti-cheat: hash the PoC so the recorded bundle is bound to the exact
971
+ // bytes that ran (re-verified at confirm time).
1123
972
  let pocHash: string | undefined;
1124
973
  try {
1125
974
  pocHash = createHash("sha256").update(readFileSync(pocPath)).digest("hex");
1126
975
  } catch (e) {
1127
976
  return fail(`Cannot read PoC script: ${(e as Error).message}`);
1128
977
  }
1129
- if (!isIntra && !oobOnly) {
1130
- let controlHash: string | undefined;
1131
- try {
1132
- controlHash = createHash("sha256").update(readFileSync(controlPath)).digest("hex");
1133
- } catch (e) {
1134
- return fail(
1135
- `Cannot read control script for the same-file check: ${(e as Error).message}`,
1136
- );
1137
- }
1138
- if (pocHash !== controlHash) {
1139
- return fail(
1140
- "CONTROL CHECK FAILED: control_path must be the SAME script as poc_path (sha256 mismatch). Case remains investigating.",
1141
- );
1142
- }
1143
- }
1144
978
 
1145
- // ── OOB callback tokens were provisioned above, before the runs ──
1146
- const runOptions = (pocMode: string, target: string): PocRunOptions => ({
979
+ const runOptions = (target: string): PocRunOptions => ({
1147
980
  network: params.local === true ? "host" : "none",
1148
981
  local: params.local === true,
1149
982
  env: {
1150
- PI_POC_MODE: pocMode,
983
+ PI_POC_MODE: "poc",
1151
984
  PI_POC_TARGET: target,
1152
- ...(oobRequested && targetCallback && controlCallback
1153
- ? {
1154
- PI_POC_CALLBACK_DOMAIN:
1155
- pocMode === "control" ? controlCallback.domain : targetCallback.domain,
1156
- }
1157
- : {}),
1158
985
  },
1159
986
  });
1160
987
 
1161
988
  // Determinism: TWO target runs. Exit 0 is run integrity only; nonce-bound
1162
- // body evidence plus the harness-owned differential replay (inter-host
1163
- // control, or intra-target same-host baseline) form the machine gate.
1164
- const run1 = runPoc(pocPath, runOptions("poc", caseTarget));
1165
- const run2 = runPoc(pocPath, runOptions("poc", caseTarget));
1166
-
1167
- const evidenceRun = (
1168
- r: PocRun,
1169
- mode: "poc" | "control",
1170
- target: string,
1171
- ): PocEvidenceRun => {
989
+ // body evidence plus the harness-owned attack/baseline replay form the
990
+ // machine gate.
991
+ const run1 = runPoc(pocPath, runOptions(caseTarget));
992
+ const run2 = runPoc(pocPath, runOptions(caseTarget));
993
+
994
+ const evidenceRun = (r: PocRun, target: string): PocEvidenceRun => {
1172
995
  if (!r.completed || !r.outputComplete) {
1173
996
  return fail(
1174
- `${mode} run did not complete or output capture was incomplete` +
997
+ `PoC run did not complete or output capture was incomplete` +
1175
998
  (r.infraError ? ` (infra: ${r.output.trim()})` : "") +
1176
999
  ". A crash is not evidence. Case remains investigating.",
1177
1000
  );
1178
1001
  }
1179
1002
  if (r.evidenceError) {
1180
1003
  return fail(
1181
- `EVIDENCE CONTRACT FAILED (${mode} run): ${r.evidenceError}. ` +
1182
- "The PoC must write evidence.json to $PI_POC_EVIDENCE_DIR — { nonce (echo $PI_POC_NONCE), claim, verify: { method, url, expect: { status?, body_contains / body_regex } }, observations }; a response-body assertion is mandatory — " +
1004
+ `EVIDENCE CONTRACT FAILED: ${r.evidenceError}. ` +
1005
+ "The PoC must write evidence.json to $PI_POC_EVIDENCE_DIR — { nonce (echo $PI_POC_NONCE), claim, verify: { method, url, expect: { status?, body_contains / body_regex } }, observations, baseline }; a response-body assertion is mandatory — " +
1183
1006
  "the file is bound to this run and validated by the harness. Case remains investigating.",
1184
1007
  );
1185
1008
  }
1186
1009
  if (!r.evidence || !r.evidenceSha256 || !r.nonce) {
1187
- return fail(`${mode} run produced no evidence. Case remains investigating.`);
1010
+ return fail("PoC run produced no evidence. Case remains investigating.");
1188
1011
  }
1189
1012
  return {
1190
- mode,
1013
+ mode: "poc",
1191
1014
  target,
1192
1015
  nonce: r.nonce,
1193
1016
  ranAt: r.ranAt,
@@ -1203,89 +1026,26 @@ export default function casefileExtension(pi: ExtensionAPI) {
1203
1026
  };
1204
1027
 
1205
1028
  const targetRuns: [PocEvidenceRun, PocEvidenceRun] = [
1206
- evidenceRun(run1, "poc", caseTarget),
1207
- evidenceRun(run2, "poc", caseTarget),
1029
+ evidenceRun(run1, caseTarget),
1030
+ evidenceRun(run2, caseTarget),
1208
1031
  ];
1209
1032
 
1210
- // Reflection canary + OOB is rejected after run 1 (the canary is
1211
- // declared inside evidence.json): the canary path requires a harness
1212
- // response transcript, which OOB-only bundles never produce — the
1213
- // per-run callback token IS the causality signal there.
1214
- if (oobRequested && targetRuns.some((r) => r.evidence.verify.canary !== undefined)) {
1215
- return fail(
1216
- "verify.canary cannot be combined with oob:true — the per-run callback token already provides a harness-owned causality signal. Remove the {{PI_POC_CANARY}} placeholder and verify.canary from evidence.json, then re-promote.",
1217
- );
1218
- }
1219
1033
  const allowPrivateReplay = process.env.PI_POC_ALLOW_PRIVATE_REPLAY === "1";
1220
- let harnessVerified: HarnessVerifyResult | undefined;
1221
- let controlRun: PocEvidenceRun | undefined;
1222
- if (isIntra) {
1223
- // Intra-target: prove target-dependence with the evidence's same-host
1224
- // baseline request — no separate control run. The harness sends attack +
1225
- // baseline to the case target and requires the proof on attack only.
1226
- const ev0 = targetRuns[0].evidence;
1227
- if (ev0.verify.mode !== "intra_target") {
1228
- return fail(
1229
- "INTRA-TARGET FAILED: the PoC's evidence.json must set verify.mode='intra_target' when promoting in intra-target mode.",
1230
- );
1231
- }
1232
- if (!ev0.baseline) {
1233
- return fail(
1234
- "INTRA-TARGET FAILED: evidence.json must include a baseline — a legitimate same-host request whose response must NOT satisfy the attack predicate.",
1235
- );
1236
- }
1237
- harnessVerified = await replayIntraTarget(ev0, caseTarget, {
1238
- allowPrivate: allowPrivateReplay,
1239
- });
1240
- } else if (!oobOnly) {
1241
- // Inter-host (Tier 2): the harness executes the SAME request template
1242
- // against target and operator-approved control, applying the target's
1243
- // predicates to both. DNS is pinned at connect time.
1244
- controlRun = evidenceRun(
1245
- runPoc(controlPath, runOptions("control", controlTarget)),
1246
- "control",
1247
- controlTarget,
1248
- );
1249
- harnessVerified = await replayDifferential(
1250
- targetRuns[0].evidence,
1251
- caseTarget,
1252
- controlTarget,
1253
- { allowPrivate: allowPrivateReplay },
1254
- );
1255
- }
1256
- // OOB differential: poll the oracle for both run tokens. The ledger's
1257
- // assertMachineConfirmation consumes this BEFORE the response-diff
1258
- // requirement — blind classes pass via this path when the oracle saw
1259
- // the target token and NOT the control token under attested source
1260
- // separation.
1261
- let callbackVerified: OobVerification | undefined;
1262
- if (oobConfig && targetCallback && controlCallback) {
1263
- callbackVerified = (
1264
- await verifyOobDifferential({
1265
- targetToken: targetCallback.token,
1266
- controlToken: controlCallback.token,
1267
- })
1268
- ).verification;
1269
- }
1034
+ // Intra-target differential: prove target-dependence with the evidence's
1035
+ // same-host baseline request. The harness sends attack + baseline to the
1036
+ // case target and requires the proof on attack only.
1037
+ const harnessVerified: HarnessVerifyResult = await replayIntraTarget(
1038
+ targetRuns[0].evidence,
1039
+ caseTarget,
1040
+ { allowPrivate: allowPrivateReplay },
1041
+ );
1270
1042
  const bundle: PendingConfirmation = {
1271
1043
  caseId,
1272
1044
  ranAt: new Date().toISOString(),
1273
1045
  pocPath,
1274
1046
  pocSha256: pocHash,
1275
- mode,
1276
1047
  targetRuns,
1277
1048
  harnessVerified,
1278
- ...(panelVotes ? { panelVotes } : {}),
1279
- ...(callbackVerified && targetCallback && controlCallback
1280
- ? {
1281
- callbackVerified,
1282
- oobTokens: {
1283
- targetToken: targetCallback.token,
1284
- controlToken: controlCallback.token,
1285
- },
1286
- }
1287
- : {}),
1288
- ...(!(isIntra || oobOnly) ? { controlPath, controlTarget, controlRun } : {}),
1289
1049
  };
1290
1050
 
1291
1051
  let record: CaseRecord;
@@ -1301,15 +1061,12 @@ export default function casefileExtension(pi: ExtensionAPI) {
1301
1061
  type: "text",
1302
1062
  text:
1303
1063
  `Phase 1 complete — evidence bundle recorded on ${caseId} (expires in 1h).\n` +
1304
- `Mode: ${mode}. ${isIntra ? "Target runs: 2, same-host baseline differential" : "Target runs: 2, Control run: 1"} — all with validated nonce-bound evidence.json.\n` +
1064
+ `Target runs: 2, same-host baseline differential — all with validated nonce-bound evidence.json.\n` +
1305
1065
  `Evidence sha256: ${targetRuns[0].evidenceSha256}\n` +
1306
1066
  `PoC script sha256 (at run time): ${pocHash}\n` +
1307
1067
  `Harness verify replay: ${harnessVerified?.attempted ? (harnessVerified.pass ? `PASS (status ${harnessVerified.status})` : `FAILED — ${harnessVerified.note}`) : (harnessVerified?.note ?? "not run")}
1308
1068
  ` +
1309
- (callbackVerified
1310
- ? `OOB oracle: target-token hits ${callbackVerified.targetHits}, control-token hits ${callbackVerified.controlHits}, source-separated: ${String(callbackVerified.sourceSeparated)} — ${callbackVerified.note}\n`
1311
- : "") +
1312
- `\nMAIN-AGENT REVIEW REQUIRED (do not delegate): inspect case ${caseId}, PoC ${pocPath}, ${isIntra ? "same-host baseline" : `control ${controlTarget}`}, evidence ${targetRuns[0].evidenceSha256}, and PoC hash ${pocHash}. Hunt for a trivial predicate or fabricated differential and perform a concrete disconfirmation attempt, then call ConfirmFinding yourself. A CONFIRMED call performs and stores a fresh harness-owned ${isIntra ? "attack/baseline" : "target/control"} replay; NOT_CONFIRMED keeps the case investigating.`,
1069
+ `\nMAIN-AGENT REVIEW REQUIRED (do not delegate): inspect case ${caseId}, PoC ${pocPath}, the same-host baseline, evidence ${targetRuns[0].evidenceSha256}, and PoC hash ${pocHash}. Hunt for a trivial predicate or fabricated differential and perform a concrete disconfirmation attempt, then call ConfirmFinding yourself. NOT_CONFIRMED keeps the case investigating.`,
1313
1070
  },
1314
1071
  ],
1315
1072
  details: {
@@ -1317,10 +1074,7 @@ export default function casefileExtension(pi: ExtensionAPI) {
1317
1074
  bundle: {
1318
1075
  caseId,
1319
1076
  ranAt: bundle.ranAt,
1320
- mode,
1321
1077
  pocPath,
1322
- controlPath: isIntra ? undefined : controlPath,
1323
- controlTarget: isIntra ? undefined : controlTarget,
1324
1078
  pocSha256: pocHash,
1325
1079
  evidenceSha256: targetRuns[0].evidenceSha256,
1326
1080
  harnessVerified,
@@ -1358,15 +1112,15 @@ export default function casefileExtension(pi: ExtensionAPI) {
1358
1112
  name: "ConfirmFinding",
1359
1113
  label: "Main-Agent Confirmation",
1360
1114
  description:
1361
- "Phase 2 of confirmation, reserved for the main/coordinator agent: commit or refuse promotion after independently re-testing the finding. On CONFIRMED, this tool performs a fresh harness-owned target/control replay; the verdict requires a target-only differential, a concrete re_execution_note and disconfirmation_attempt, a canary assessment, and the still-valid PromoteFinding bundle. The machine transcript is evidence, not the semantic vulnerability verdict. Worker/subagent processes are rejected. Three verdicts: CONFIRMED (you reproduced real impact), NOT_CONFIRMED (you POSITIVELY disproved it), INCONCLUSIVE (you could neither reproduce nor disprove — the case is preserved for manual review, never dropped).",
1115
+ "Phase 2 of confirmation, reserved for the main/coordinator agent: commit or refuse promotion after independently reviewing the recorded evidence. The verdict requires a target-only differential, a concrete re_execution_note and disconfirmation_attempt, and the still-valid PromoteFinding bundle. The machine floor is the promote-time harness replay plus confirm-time bundle re-validation — there is no fresh network replay at verdict time, so weigh bundle age (1h TTL) in your review. The machine transcript is evidence, not the semantic vulnerability verdict. Worker/subagent processes are rejected. Three verdicts: CONFIRMED (you reproduced real impact), NOT_CONFIRMED (you POSITIVELY disproved it), INCONCLUSIVE (you could neither reproduce nor disprove — the case is preserved for manual review, never dropped).",
1362
1116
  promptSnippet: "Main agent: independently re-test, then commit or refuse PoC confirmation",
1363
1117
  promptGuidelines: [
1364
1118
  "Run only in the main/coordinator agent after PromoteFinding returns. Do not dispatch a worker to decide or author this verdict.",
1365
- "Verify with DISBELIEF: assume the finding is a false positive until your OWN re-test proves otherwise. Reproduce the exact observable yourself from the primary evidence (not the hunter's narrative), with a negative/baseline control — a difference you cannot tie to the control is not proof. ConfirmFinding itself re-sends the immutable verify request against target and operator-approved control so phase 2 has a harness-owned transcript.",
1119
+ "Verify with DISBELIEF: assume the finding is a false positive until the recorded evidence proves otherwise. Read the PoC script, both run transcripts, the attack/baseline replay, and the evidence artifacts (not the hunter's narrative) — a difference you cannot tie to the baseline is not proof.",
1366
1120
  "Provenance: the proof must exercise THIS finding's own mechanism. Evidence obtained through a DIFFERENT bug (e.g. 'SQLi' proven by dumping the DB via an RCE) does not confirm it — that is INCONCLUSIVE at best.",
1367
1121
  "Kill the cheapest benign explanation: is this the technology's intended behavior? Did the attacker supply the 'secret' themselves (circular)? Is the claimed C/I/A impact actually demonstrated?",
1368
1122
  "Want a second pair of eyes? Dispatch a read-only skeptic subagent to re-test — it CANNOT confirm (only the main agent commits). You review its verdict and commit it here.",
1369
- "CONFIRMED requires differential: 'target_only', re_execution_note, and disconfirmation_attempt (your failed disproof). A verdict missing any of these is rejected. Set canary_assessment='verified' when the immutable request declared a canary; otherwise not_applicable with a reason.",
1123
+ "CONFIRMED requires differential: 'target_only', re_execution_note, and disconfirmation_attempt (your failed disproof). A verdict missing any of these is rejected.",
1370
1124
  "NOT_CONFIRMED means you POSITIVELY disproved it (by-design, circular, mislabeled, no impact). Never mark NOT_CONFIRMED merely because you could not reproduce it.",
1371
1125
  "INCONCLUSIVE when you could neither reproduce nor disprove (needs auth, a second account, specific state, timing, or a blind/stored trigger you cannot observe). The case stays investigating and is preserved for manual review — dropping a real finding is worse than keeping an unproven one.",
1372
1126
  "Every verdict consumes the attempt: a fresh PromoteFinding run is required to try again. Never CaseUpdate status='confirmed' directly — always PromoteFinding + ConfirmFinding.",
@@ -1384,83 +1138,7 @@ export default function casefileExtension(pi: ExtensionAPI) {
1384
1138
  if (!parsedVerdict.ok) {
1385
1139
  throw new Error(`Invalid main-agent confirmation verdict: ${parsedVerdict.error}`);
1386
1140
  }
1387
- let phase2Verification: MainAgentVerification | undefined;
1388
- if (parsedVerdict.verdict.verdict === "CONFIRMED") {
1389
- const current = getCaseById(caseId);
1390
- if (!current) throw new Error(`Case not found: ${caseId}`);
1391
- const bundle = current.pendingConfirmation;
1392
- if (!bundle) {
1393
- throw new Error("No pending confirmation on this case — run PromoteFinding first");
1394
- }
1395
- const allowPrivate = process.env.PI_POC_ALLOW_PRIVATE_REPLAY === "1";
1396
- const caseTargetForReplay = current.target ?? bundle.targetRuns[0].target;
1397
- let replay: HarnessVerifyResult;
1398
- if (bundle.mode === "intra_target") {
1399
- // Same-host attack-vs-baseline replay; no control target to authorize.
1400
- replay = await replayIntraTarget(bundle.targetRuns[0].evidence, caseTargetForReplay, {
1401
- allowPrivate,
1402
- });
1403
- } else if (bundle.callbackVerified?.attempted && bundle.oobTokens) {
1404
- // OOB differential: fresh harness-owned re-poll of BOTH run tokens.
1405
- // Re-polling at confirm time catches interactions that landed after
1406
- // phase 1 (e.g. a delayed control-token hit) — the verdict is bound
1407
- // to this fresh observation, not the stored one.
1408
- const { verification } = await verifyOobDifferential({
1409
- targetToken: bundle.oobTokens.targetToken,
1410
- controlToken: bundle.oobTokens.controlToken,
1411
- });
1412
- const oobPass =
1413
- verification.targetHits > 0 &&
1414
- verification.controlHits === 0 &&
1415
- verification.sourceSeparated === true;
1416
- replay = {
1417
- attempted: true,
1418
- pass: oobPass,
1419
- target: {
1420
- attempted: true,
1421
- matched: verification.targetHits > 0,
1422
- url: bundle.targetRuns[0].evidence.verify.url,
1423
- note: verification.note,
1424
- },
1425
- control: {
1426
- attempted: true,
1427
- matched: verification.controlHits > 0,
1428
- url: bundle.targetRuns[0].evidence.verify.url,
1429
- note: `${verification.controlHits} control-token interaction(s)`,
1430
- },
1431
- differential:
1432
- verification.targetHits > 0
1433
- ? verification.controlHits === 0
1434
- ? "target_only"
1435
- : "both"
1436
- : "neither",
1437
- note: `harness OOB re-poll: ${verification.note}`,
1438
- };
1439
- } else if (bundle.callbackVerified?.attempted) {
1440
- throw new Error(
1441
- "OOB bundle lacks its provisioned tokens (pre-token-storage ledger) — re-run PromoteFinding for a fresh bundle",
1442
- );
1443
- } else {
1444
- if (!bundle.controlTarget) {
1445
- throw new Error("inter-host confirmation requires a control target");
1446
- }
1447
- const controlAuthorizationError = controlTargetAuthorizationError(bundle.controlTarget);
1448
- if (controlAuthorizationError) {
1449
- throw new Error(`CONTROL AUTHORIZATION FAILED: ${controlAuthorizationError}`);
1450
- }
1451
- replay = await replayDifferential(
1452
- bundle.targetRuns[0].evidence,
1453
- caseTargetForReplay,
1454
- bundle.controlTarget,
1455
- { allowPrivate },
1456
- );
1457
- }
1458
- phase2Verification = {
1459
- at: new Date().toISOString(),
1460
- result: replay,
1461
- };
1462
- }
1463
- const result = applyConfirmationResult(caseId, parsedVerdict.verdict, phase2Verification, {
1141
+ const result = applyConfirmationResult(caseId, parsedVerdict.verdict, {
1464
1142
  startedAsSubagent: isSubagentProcess(),
1465
1143
  });
1466
1144
  const record = result.record;