@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/README.md CHANGED
@@ -15,9 +15,8 @@ A structured ledger for offensive-security work — bug bounties, CTFs, audits
15
15
 
16
16
  Cases move `hypothesis → investigating → confirmed → reported`. Promotion between phases is gated:
17
17
 
18
- - **Zero exit is necessary but never proof** — direct-response findings require nonce-bound body evidence plus a DNS-pinned, conclusive `target_only` replay against an operator-approved control
19
- - **Differential confirmation** — `inter_host` (attack vs control host) or `intra_target` (attack vs baseline request) so "it worked" means *the discriminator fired*, not "the agent said so"
20
- - **Blind/OOB classes** confirm through an operator-run oracle with per-run tokens and source-separation attestation
18
+ - **Zero exit is necessary but never proof** — direct-response findings require nonce-bound body evidence plus a DNS-pinned, conclusive `target_only` attack-vs-baseline replay against the case target (recorded at promote; the bundle's baseline binding and differential are re-validated at confirm)
19
+ - **Differential confirmation** — the attack request must satisfy the claimed predicate while a legitimate same-host baseline request must not, so "it worked" means *the discriminator fired*, not "the agent said so"
21
20
  - Only the main agent makes the semantic decision and commits phase transitions
22
21
 
23
22
  Designed for **human + AI workflows**: every confirmed finding carries a reproducible evidence trail a human can audit.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xaccefy/pi-casefile",
3
- "version": "0.10.1",
3
+ "version": "0.11.0",
4
4
  "description": "Offensive security case tracker for Pi Agent \u2014 bug bounties, CTFs, security audits",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -35,7 +35,6 @@
35
35
  "src/index.ts",
36
36
  "src/evidence.ts",
37
37
  "src/harness-verify.ts",
38
- "src/oob-oracle.ts",
39
38
  "src/confirmation.ts",
40
39
  "src/ledger-internal.ts",
41
40
  "src/safe-state.ts",
@@ -6,14 +6,15 @@
6
6
  * one readable module. ledger.ts re-exports every public symbol here, so
7
7
  * callers and tests are unchanged.
8
8
  *
9
- * The gate's contract (docs/confirmation-design.md):
9
+ * The gate's contract:
10
10
  * - Zero exit + complete output capture = run integrity, never proof.
11
11
  * - Evidence must be nonce-bound, schema-valid, carry a discriminating
12
12
  * response-body predicate, and survive durable-hash re-verification.
13
- * - Target-dependence requires a machine differential: inter-host control run,
14
- * intra-target same-host baseline, or a source-separated OOB token delta.
15
- * - Phase 2 requires a fresh harness-owned replay bound to the verdict; only
16
- * the ledger can transition a case to confirmed.
13
+ * - Target-dependence requires a machine differential: the attack request
14
+ * must satisfy the predicate while a legitimate same-host baseline request
15
+ * (declared in the evidence) must not.
16
+ * - Only the main agent commits the phase-2 verdict; only the ledger can
17
+ * transition a case to confirmed.
17
18
  */
18
19
 
19
20
  import { createHash } from "node:crypto";
@@ -25,11 +26,9 @@ import {
25
26
  evidenceNonceMatches,
26
27
  type MainAgentVerdict,
27
28
  normalizeEvidence,
28
- panelQuorumReached,
29
29
  parsePoCEvidence,
30
30
  scanArtifactForSecrets,
31
31
  validateMainAgentVerdict,
32
- validatePanelVotes,
33
32
  } from "./evidence.ts";
34
33
  import { type HarnessVerifyResult, sameRequest, verifyUrlBindingError } from "./harness-verify.ts";
35
34
  import type {
@@ -37,7 +36,6 @@ import type {
37
36
  CaseUpdateResult,
38
37
  EvidenceItem,
39
38
  MainAgentVerdictRecord,
40
- MainAgentVerification,
41
39
  NormalizedCaseInput,
42
40
  PendingConfirmation,
43
41
  PocEvidenceRun,
@@ -271,56 +269,21 @@ function validateRunEvidence(run: PocEvidenceRun, label: string): void {
271
269
  }
272
270
  }
273
271
 
274
- /** Determinism + differential on normalized evidence (nonce/observations stripped). */
275
- function assertEvidenceDifferential(bundle: PendingConfirmation, isIntra = false): void {
272
+ /** Determinism on normalized evidence (nonce/observations stripped). */
273
+ function assertEvidenceDifferential(bundle: PendingConfirmation): void {
276
274
  const [r1, r2] = bundle.targetRuns;
277
275
  if (normalizeEvidence(r1.evidence) !== normalizeEvidence(r2.evidence)) {
278
276
  throw new Error(
279
277
  "Target runs produced inconsistent evidence — the exploit did not reproduce deterministically",
280
278
  );
281
279
  }
282
- // Intra-target target-dependence is proven by the harness attack-vs-baseline
283
- // replay (same host), not by comparing a target run to a separate control run.
284
- if (isIntra) return;
285
- // OOB-only bundles prove target-dependence via the oracle token differential
286
- // (assertMachineConfirmation judges callbackVerified); no control run exists.
287
- if (!bundle.controlRun && bundle.callbackVerified?.attempted) return;
288
- if (!bundle.controlRun) {
289
- throw new Error("inter-host confirmation requires a control run");
290
- }
291
- if (normalizeEvidence(r1.evidence) === normalizeEvidence(bundle.controlRun.evidence)) {
292
- throw new Error(
293
- "Control run produced identical evidence to the target — the claimed impact is not target-dependent",
294
- );
295
- }
296
280
  }
297
281
 
298
282
  function assertMachineConfirmation(bundle: PendingConfirmation): void {
299
- const oob = bundle.callbackVerified;
300
- if (oob?.attempted) {
301
- if (oob.targetHits === 0) {
302
- throw new Error(
303
- `OOB VERIFY FAILED: no interaction with the target-run callback token. ${oob.note}`,
304
- );
305
- }
306
- if (oob.controlHits > 0) {
307
- throw new Error(
308
- `OOB VERIFY FAILED: the control-run callback token received ${oob.controlHits} interaction(s) — the callback is not target-dependent. ${oob.note}`,
309
- );
310
- }
311
- if (oob.sourceSeparated !== true) {
312
- throw new Error(
313
- "OOB VERIFY FAILED: callback source separation was not established. " +
314
- "A loopback listener reachable by the PoC is diagnostic telemetry, not proof that the target caused the interaction.",
315
- );
316
- }
317
- return;
318
- }
319
-
320
283
  assertHarnessTargetOnly(
321
284
  bundle.harnessVerified,
322
285
  "HARNESS DIFFERENTIAL FAILED",
323
- "no machine-owned target/control replay was recorded",
286
+ "no machine-owned attack/baseline replay was recorded",
324
287
  );
325
288
  }
326
289
 
@@ -340,79 +303,6 @@ function assertHarnessTargetOnly(
340
303
  }
341
304
  }
342
305
 
343
- function assertHarnessCanary(
344
- harness: HarnessVerifyResult | undefined,
345
- required: boolean,
346
- label: string,
347
- ): void {
348
- if (!required) return;
349
- if (
350
- harness?.canary?.attempted !== true ||
351
- harness.canary.pass !== true ||
352
- harness.canary.targetObserved !== true ||
353
- harness.canary.controlObserved !== false ||
354
- harness.proofStrength !== "canary_differential"
355
- ) {
356
- throw new Error(`${label}: ${harness?.canary?.note ?? "required canary transcript missing"}`);
357
- }
358
- }
359
-
360
- function assertMainAgentVerification(
361
- bundle: PendingConfirmation,
362
- verification: MainAgentVerification | undefined,
363
- isIntra = false,
364
- ): asserts verification is MainAgentVerification {
365
- if (!verification) {
366
- throw new Error(
367
- "MAIN-AGENT REPLAY REQUIRED: ConfirmFinding must produce a fresh harness-owned target/control transcript",
368
- );
369
- }
370
- const at = Date.parse(verification.at);
371
- const bundleAt = Date.parse(bundle.ranAt);
372
- const now = Date.now();
373
- if (
374
- !Number.isFinite(at) ||
375
- !Number.isFinite(bundleAt) ||
376
- at < bundleAt ||
377
- at > now + 30_000 ||
378
- now - at > 5 * 60 * 1000
379
- ) {
380
- throw new Error(
381
- "MAIN-AGENT REPLAY FAILED: transcript timestamp must be valid, newer than phase 1, and no more than 5 minutes old",
382
- );
383
- }
384
- assertHarnessTargetOnly(
385
- verification.result,
386
- "MAIN-AGENT REPLAY FAILED",
387
- "no fresh phase-2 target/control replay was recorded",
388
- );
389
- assertHarnessCanary(
390
- verification.result,
391
- bundle.targetRuns[0].evidence.verify.canary !== undefined,
392
- "MAIN-AGENT CANARY FAILED",
393
- );
394
- // OOB-only bundles bind by TOKEN identity (enforced at store time on
395
- // evidence.verify.url); there is no control host to bind a transcript to.
396
- if (bundle.callbackVerified?.attempted && bundle.oobTokens) return;
397
- const targetUrl = verification.result.target?.url;
398
- const controlUrl = verification.result.control?.url;
399
- const targetIdentity = bundle.targetRuns[0].target;
400
- if (!targetUrl || verifyUrlBindingError(targetUrl, targetIdentity)) {
401
- throw new Error("MAIN-AGENT REPLAY FAILED: target transcript is not bound to the case target");
402
- }
403
- // Intra-target: the "control" transcript is the legitimate baseline request,
404
- // which is bound to the SAME case target. Inter-host: it is bound to the
405
- // distinct control target.
406
- const controlBindTarget = isIntra ? targetIdentity : bundle.controlTarget;
407
- if (!controlUrl || !controlBindTarget || verifyUrlBindingError(controlUrl, controlBindTarget)) {
408
- throw new Error(
409
- isIntra
410
- ? "MAIN-AGENT REPLAY FAILED: baseline transcript is not bound to the case target"
411
- : "MAIN-AGENT REPLAY FAILED: control transcript is not bound to control_target",
412
- );
413
- }
414
- }
415
-
416
306
  /**
417
307
  * Gate for phase 1 of promotion: case must exist, be investigating, and have
418
308
  * poc/evidence/impact/severity/target. The disconfirmation is provided by the
@@ -460,27 +350,16 @@ export function assertPromotable(id: string): CaseRecord {
460
350
  }
461
351
 
462
352
  /**
463
- * Phase 1 (intra-target): validate a same-host attack-vs-baseline bundle. The
464
- * differential is proven by the harness replay (attack matched, baseline did
465
- * not, both against the case target), not by a separate control run the
466
- * discriminating variable is the request's identity or a parameter, not the host.
353
+ * Phase 1: validate a same-host attack-vs-baseline bundle. The differential is
354
+ * proven by the harness replay (attack matched, baseline did not, both against
355
+ * the case target) the discriminating variable is the request's identity or
356
+ * a parameter, not the host.
467
357
  */
468
- function validateIntraTargetBundle(
469
- current: CaseRecord,
470
- id: string,
471
- bundle: PendingConfirmation,
472
- ): CaseRecord {
473
- if (bundle.targetRuns.length !== 2) {
474
- throw new Error("Intra-target confirmation requires two target runs");
475
- }
476
- if (bundle.controlRun || bundle.controlTarget) {
477
- throw new Error(
478
- "Intra-target confirmation must not carry a control run or control target — the baseline is a same-host request inside the evidence",
479
- );
480
- }
358
+ function validateBundle(current: CaseRecord, id: string, bundle: PendingConfirmation): CaseRecord {
359
+ if (bundle.targetRuns.length !== 2) throw new Error("Confirmation requires two target runs");
481
360
  const targetRunTarget = bundle.targetRuns[0]?.target;
482
361
  if (!targetRunTarget || bundle.targetRuns.some((r) => r.target !== targetRunTarget)) {
483
- throw new Error("Intra-target confirmation requires both runs against the same case target");
362
+ throw new Error("Confirmation requires both runs against the same case target");
484
363
  }
485
364
  let pocHash: string | undefined;
486
365
  try {
@@ -494,35 +373,20 @@ function validateIntraTargetBundle(
494
373
  for (const run of bundle.targetRuns) {
495
374
  validateRunEvidence(run, `${run.mode} run`);
496
375
  const ev = run.evidence;
497
- if (ev.verify.mode !== "intra_target") {
498
- throw new Error(
499
- "INTRA-TARGET FAILED: each run's evidence.verify.mode must be 'intra_target'",
500
- );
501
- }
502
- if (!ev.baseline) {
503
- throw new Error(
504
- "INTRA-TARGET FAILED: evidence.baseline (a legitimate same-host request) is required",
505
- );
506
- }
507
376
  const attackBinding = verifyUrlBindingError(ev.verify.url, targetRunTarget);
508
377
  if (attackBinding) throw new Error(`ATTACK BINDING FAILED: ${attackBinding}`);
509
378
  const baselineBinding = verifyUrlBindingError(ev.baseline.url, targetRunTarget);
510
379
  if (baselineBinding) throw new Error(`BASELINE BINDING FAILED: ${baselineBinding}`);
511
380
  if (ev.baseline && sameRequest(ev.verify, ev.baseline)) {
512
381
  throw new Error(
513
- "INTRA-TARGET FAILED: attack and baseline requests are identical — vary identity or a parameter",
382
+ "BASELINE CHECK FAILED: attack and baseline requests are identical — vary identity or a parameter",
514
383
  );
515
384
  }
516
385
  }
517
386
  if (bundle.caseId !== id) throw new Error("Pending confirmation caseId mismatch");
518
- assertEvidenceDifferential(bundle, true);
387
+ assertEvidenceDifferential(bundle);
519
388
  // Machine floor: attack matched, baseline did not, both against the case target.
520
389
  assertMachineConfirmation(bundle);
521
- assertHarnessCanary(
522
- bundle.harnessVerified,
523
- bundle.targetRuns[0].evidence.verify.canary !== undefined,
524
- "PHASE-1 CANARY FAILED",
525
- );
526
390
  const next = buildRecord({ pendingConfirmation: bundle }, current);
527
391
  validateCase(next);
528
392
  return next;
@@ -530,9 +394,9 @@ function validateIntraTargetBundle(
530
394
 
531
395
  /**
532
396
  * Phase 1: record the harness-observed evidence bundle on the case. The whole
533
- * contract is validated here — same-file control, nonce binding, run
534
- * completion, determinism across the two target runs, and the target/control
535
- * differential — so a bundle that cannot promote is rejected before the
397
+ * contract is validated here — nonce binding, run completion, determinism
398
+ * across the two target runs, and the attack/baseline differential — so a
399
+ * bundle that cannot promote is rejected before the
536
400
  * main agent performs phase-2 review.
537
401
  */
538
402
  export function storePendingConfirmation(id: string, bundle: PendingConfirmation): CaseRecord {
@@ -546,127 +410,22 @@ export function storePendingConfirmation(id: string, bundle: PendingConfirmation
546
410
  );
547
411
  }
548
412
  if (bundle.caseId !== id) throw new Error("Pending confirmation caseId mismatch");
549
- // Panel vote shape is machine-checked at store time — a malformed panel
550
- // must never silently count toward a quorum later.
551
- if (bundle.panelVotes !== undefined) {
552
- const votes = validatePanelVotes(bundle.panelVotes);
553
- if (!votes.ok) throw new Error(`Pending confirmation panel invalid: ${votes.error}`);
554
- }
555
- if (bundle.mode === "intra_target") {
556
- const next = validateIntraTargetBundle(current, id, bundle);
557
- upsertCase(db, next);
558
- appendCaseEvent(db, {
559
- actor: "harness",
560
- caseId: id,
561
- eventType: "promotion_pending",
562
- payload: { mode: "intra_target", evidence_sha256: bundle.targetRuns[0].evidenceSha256 },
563
- });
564
- return next;
565
- }
566
- // Control-run requirements key off controlRun PRESENCE, not the OOB flag:
567
- // an OOB-only bundle has no control run (token differential instead), but
568
- // an OOB+control bundle still carries one and gets the full checks.
569
- if (!bundle.controlRun && !bundle.callbackVerified) {
570
- throw new Error("Pending confirmation requires two target runs and one control run");
571
- }
572
- if (bundle.controlRun && (!bundle.pocPath || !bundle.controlPath || !bundle.controlTarget)) {
573
- throw new Error("Pending confirmation requires pocPath, controlPath, and controlTarget");
574
- }
575
- // Control-target binding (machine-verified here, not just in the tool
576
- // layer): the control run must actually have targeted the declared
577
- // control_target, that target must differ from the target runs' target,
578
- // and the control target must differ from the case's target — otherwise
579
- // "the control demonstrated nothing on the vulnerable target" passes.
580
- const targetRunTarget = bundle.targetRuns[0]?.target;
581
- if (!targetRunTarget || bundle.targetRuns.some((r) => r.target !== targetRunTarget)) {
582
- throw new Error(
583
- "Pending confirmation requires both target runs against the same case target",
584
- );
585
- }
586
- if (bundle.controlRun) {
587
- if (!bundle.controlRun.target || bundle.controlRun.target !== bundle.controlTarget) {
588
- throw new Error(
589
- "CONTROL BINDING FAILED: controlRun.target must equal control_target — a control run " +
590
- "against a different host than the one declared proves nothing.",
591
- );
592
- }
593
- if (bundle.controlRun.target === targetRunTarget) {
594
- throw new Error(
595
- "CONTROL BINDING FAILED: the control run targeted the same host as the target runs — " +
596
- "the claimed impact is not target-dependent.",
597
- );
598
- }
599
- }
600
- if (bundle.controlTarget && bundle.controlTarget === current.target) {
601
- throw new Error(
602
- "CONTROL BINDING FAILED: control_target must differ from the case target; a control run " +
603
- "against the vulnerable target proves nothing.",
604
- );
605
- }
606
- // Same-file contract re-checked at store time (the tool already checked).
607
- // OOB-only bundles carry no separate control script — the PoC hash alone
608
- // is re-verified against the file on disk.
609
413
  let pocHash: string | undefined;
610
- let controlHash: string | undefined;
611
414
  try {
612
415
  pocHash = createHash("sha256").update(readFileSync(bundle.pocPath)).digest("hex");
613
- controlHash = bundle.controlPath
614
- ? createHash("sha256").update(readFileSync(bundle.controlPath)).digest("hex")
615
- : pocHash;
616
416
  } catch {
617
417
  pocHash = undefined;
618
- controlHash = undefined;
619
418
  }
620
- if (!pocHash || !controlHash || pocHash !== controlHash) {
621
- throw new Error(
622
- "CONTROL CHECK FAILED: control_path must be the SAME script as poc_path " +
623
- "(sha256 mismatch). A separately written control file proves nothing.",
624
- );
625
- }
626
- if (bundle.pocSha256 && bundle.pocSha256 !== pocHash) {
419
+ if (!pocHash || (bundle.pocSha256 && bundle.pocSha256 !== pocHash)) {
627
420
  throw new Error("pocSha256 does not match the PoC file on disk");
628
421
  }
629
- // Validate every run that exists — OOB-only bundles have no control run;
630
- // OOB+control bundles validate all three.
631
- const runsToValidate = bundle.controlRun
632
- ? [...bundle.targetRuns, bundle.controlRun]
633
- : [...bundle.targetRuns];
634
- for (const run of runsToValidate) {
635
- validateRunEvidence(run, `${run.mode} run`);
636
- }
637
- assertEvidenceDifferential(bundle);
638
- // Target binding applies to EVERY mode — an OOB bundle's verify.url must
639
- // still belong to the case target, or the PoC could anchor its evidence on
640
- // an unrelated host while the callback alone carries the proof.
641
- for (const run of bundle.targetRuns) {
642
- const bindingError = verifyUrlBindingError(run.evidence.verify.url, targetRunTarget);
643
- if (bindingError) throw new Error(`TARGET BINDING FAILED: ${bindingError}`);
644
- }
645
- if (bundle.controlRun) {
646
- const controlBindingError = verifyUrlBindingError(
647
- bundle.controlRun.evidence.verify.url,
648
- bundle.controlTarget!,
649
- );
650
- if (controlBindingError) {
651
- throw new Error(`CONTROL BINDING FAILED: ${controlBindingError}`);
652
- }
653
- }
654
- // A clean exit and model-authored evidence are necessary inputs, never the
655
- // proof. Promotion requires a harness-observed target/control differential
656
- // or a harness-owned OOB interaction differential.
657
- assertMachineConfirmation(bundle);
658
-
659
- const next = buildRecord({ pendingConfirmation: bundle }, current);
660
- validateCase(next);
422
+ const next = validateBundle(current, id, bundle);
661
423
  upsertCase(db, next);
662
424
  appendCaseEvent(db, {
663
425
  actor: "harness",
664
426
  caseId: id,
665
427
  eventType: "promotion_pending",
666
- payload: {
667
- mode: bundle.callbackVerified?.attempted ? "oob" : "inter_host",
668
- evidence_sha256: bundle.targetRuns[0].evidenceSha256,
669
- },
428
+ payload: { mode: "intra_target", evidence_sha256: bundle.targetRuns[0].evidenceSha256 },
670
429
  });
671
430
  return next;
672
431
  });
@@ -678,16 +437,14 @@ export function storePendingConfirmation(id: string, bundle: PendingConfirmation
678
437
  * CONFIRMED requires the full bundle to still hold (completion, nonce,
679
438
  * determinism, differential), the PoC script to be unchanged since the runs
680
439
  * (pocSha256 — otherwise the main agent reviewed different bytes), and a
681
- * verdict accompanied by a fresh harness-owned target-only replay, a concrete
682
- * review note, and a disconfirmation attempt. NOT_CONFIRMED (positively
683
- * disproved) and INCONCLUSIVE (neither reproduced nor disproved) both record
684
- * the verdict and keep the case investigating INCONCLUSIVE preserves it for
685
- * manual review rather than dropping it.
440
+ * verdict accompanied by a concrete review note and a disconfirmation attempt.
441
+ * NOT_CONFIRMED (positively disproved) and INCONCLUSIVE (neither reproduced
442
+ * nor disproved) both record the verdict and keep the case investigating —
443
+ * INCONCLUSIVE preserves it for manual review rather than dropping it.
686
444
  */
687
445
  export function applyConfirmationResult(
688
446
  id: string,
689
447
  verdictInput: MainAgentVerdict,
690
- phase2Verification?: MainAgentVerification,
691
448
  authority: { startedAsSubagent: boolean } = {
692
449
  startedAsSubagent: PROCESS_STARTED_AS_SUBAGENT || process.env.PI_SUBAGENT_CHILD === "1",
693
450
  },
@@ -720,42 +477,11 @@ export function applyConfirmationResult(
720
477
  const parsed = validateMainAgentVerdict(verdictInput);
721
478
  if (!parsed.ok) throw new Error(`Invalid main-agent confirmation verdict: ${parsed.error}`);
722
479
  const verdict = parsed.verdict;
723
- const canaryRequested = bundle.targetRuns[0].evidence.verify.canary !== undefined;
724
- if (verdict.verdict === "CONFIRMED") {
725
- if (canaryRequested && verdict.canary_assessment !== "verified") {
726
- throw new Error(
727
- "CONFIRMED canary mismatch: evidence requested a harness canary, so canary_assessment must be verified",
728
- );
729
- }
730
- if (!canaryRequested && verdict.canary_assessment !== "not_applicable") {
731
- throw new Error(
732
- "CONFIRMED canary mismatch: this evidence has no canary template; record canary_assessment=not_applicable and explain why",
733
- );
734
- }
735
- // Quorum panel pre-gate: CONFIRMED needs a 2/3 exploit panel or an
736
- // explicit override note recording why the panel was skipped (or
737
- // overruled). Votes are advisory — the main agent still commits — but a
738
- // non-quorum CONFIRMED without a note is refused.
739
- const quorum = panelQuorumReached(bundle.panelVotes);
740
- if (!quorum.quorum && !verdict.panel_override_note?.trim()) {
741
- throw new Error(
742
- `PANEL QUORUM REQUIRED: CONFIRMED needs either a 2/3 exploit panel (got ${quorum.exploit} exploit / ${quorum.total} vote(s)) ` +
743
- "or an explicit panel_override_note recording why the panel was skipped or overruled. " +
744
- "Re-run PromoteFinding with panel_votes, or justify the solo confirmation in panel_override_note.",
745
- );
746
- }
747
- }
748
480
  const recorded: MainAgentVerdictRecord = {
749
481
  ...verdict,
750
482
  at: new Date().toISOString(),
751
483
  reviewer: "main_agent",
752
- phase2Verification: verdict.verdict === "CONFIRMED" ? phase2Verification : undefined,
753
- proofStrength:
754
- verdict.verdict === "CONFIRMED"
755
- ? canaryRequested
756
- ? "canary_differential"
757
- : "predicate_differential"
758
- : undefined,
484
+ proofStrength: verdict.verdict === "CONFIRMED" ? "predicate_differential" : undefined,
759
485
  };
760
486
 
761
487
  if (verdict.verdict !== "CONFIRMED") {
@@ -792,16 +518,11 @@ export function applyConfirmationResult(
792
518
 
793
519
  // CONFIRMED — re-validate the whole bundle (defense in depth; the case may
794
520
  // have been touched between phase 1 and the verdict).
795
- const isIntra = bundle.mode === "intra_target";
796
- const allRuns = isIntra
797
- ? [...bundle.targetRuns]
798
- : [...bundle.targetRuns, ...(bundle.controlRun ? [bundle.controlRun] : [])];
799
- for (const run of allRuns) {
521
+ for (const run of bundle.targetRuns) {
800
522
  validateRunEvidence(run, `${run.mode} run`);
801
523
  }
802
- assertEvidenceDifferential(bundle, isIntra);
524
+ assertEvidenceDifferential(bundle);
803
525
  assertMachineConfirmation(bundle);
804
- assertHarnessCanary(bundle.harnessVerified, canaryRequested, "PHASE-1 CANARY FAILED");
805
526
  let pocHash: string | undefined;
806
527
  try {
807
528
  pocHash = createHash("sha256").update(readFileSync(bundle.pocPath)).digest("hex");
@@ -813,9 +534,8 @@ export function applyConfirmationResult(
813
534
  "PoC script changed since the runs — re-run PromoteFinding (the main agent must review the exact bytes that ran)",
814
535
  );
815
536
  }
816
- // The case target must still be the host the PoC ran against, and still
817
- // differ from the control target. The evidence proves nothing about a
818
- // target the case adopted after the runs.
537
+ // The case target must still be the host the PoC ran against. The
538
+ // evidence proves nothing about a target the case adopted after the runs.
819
539
  const targetRun = bundle.targetRuns[0];
820
540
  if (!current.target || current.target !== targetRun.target) {
821
541
  throw new Error(
@@ -823,12 +543,6 @@ export function applyConfirmationResult(
823
543
  `(bundle target: ${targetRun.target}, case target: ${current.target ?? "(none)"}).`,
824
544
  );
825
545
  }
826
- if (!isIntra && current.target === bundle.controlTarget) {
827
- throw new Error(
828
- "Case target now equals the control target — the claimed impact is not target-dependent; " +
829
- "re-run PromoteFinding with a distinct control_target.",
830
- );
831
- }
832
546
 
833
547
  // The observation must predate the repro (provenance guard).
834
548
  const observation = current.evidenceItems?.find(
@@ -841,11 +555,6 @@ export function applyConfirmationResult(
841
555
  );
842
556
  }
843
557
 
844
- // Phase 1 proves the evidence floor. Phase 2 must freshly replay that same
845
- // request inside the main agent's ConfirmFinding call; a caller-provided
846
- // boolean is not accepted as proof of re-execution.
847
- assertMainAgentVerification(bundle, phase2Verification, isIntra);
848
-
849
558
  const reproductionItem: EvidenceItem = {
850
559
  id: `ev_${stableShortId(`${id}\nreproduction\n${targetRun.ranAt}`)}`,
851
560
  caseId: id,
@@ -855,7 +564,7 @@ export function applyConfirmationResult(
855
564
  // exists, so the item stays artifact-backed and re-verifiable.
856
565
  artifactPath: targetRun.evidencePath ? basename(targetRun.evidencePath) : "evidence.json",
857
566
  sha256: targetRun.evidenceSha256,
858
- summary: `PoC evidence accepted (2 target runs + ${isIntra ? "same-host baseline" : "control"}; ${recorded.proofStrength}) — main agent semantic confirmation${verdict.model ? ` (${verdict.model})` : ""}`,
567
+ summary: `PoC evidence accepted (2 target runs + same-host baseline; ${recorded.proofStrength}) — main agent semantic confirmation${verdict.model ? ` (${verdict.model})` : ""}`,
859
568
  createdAt: targetRun.ranAt,
860
569
  };
861
570
  // Defense in depth: the run's evidence.json may embed secrets in
@@ -897,30 +606,17 @@ export function applyConfirmationResult(
897
606
  mode: "poc",
898
607
  target: targetRun.target,
899
608
  },
900
- controlVerified:
901
- isIntra || !bundle.controlRun
902
- ? {
903
- path: bundle.pocPath,
904
- exitCode: targetRun.exitCode,
905
- ranAt: targetRun.ranAt,
906
- output: `intra-target baseline (same host): ${bundle.harnessVerified?.control?.note ?? "baseline did not satisfy the attack predicate"}`,
907
- sandbox: targetRun.sandbox,
908
- completed: true,
909
- outputComplete: true,
910
- mode: "baseline",
911
- target: targetRun.target,
912
- }
913
- : {
914
- path: bundle.controlPath ?? bundle.pocPath,
915
- exitCode: bundle.controlRun.exitCode,
916
- ranAt: bundle.controlRun.ranAt,
917
- output: bundle.controlRun.output,
918
- sandbox: bundle.controlRun.sandbox,
919
- completed: true,
920
- outputComplete: true,
921
- mode: "control",
922
- target: bundle.controlRun.target,
923
- },
609
+ controlVerified: {
610
+ path: bundle.pocPath,
611
+ exitCode: targetRun.exitCode,
612
+ ranAt: targetRun.ranAt,
613
+ output: `same-host baseline: ${bundle.harnessVerified?.control?.note ?? "baseline did not satisfy the attack predicate"}`,
614
+ sandbox: targetRun.sandbox,
615
+ completed: true,
616
+ outputComplete: true,
617
+ mode: "baseline",
618
+ target: targetRun.target,
619
+ },
924
620
  disconfirmation: verdict.disconfirmation_attempt,
925
621
  confirmerVerdict: recorded,
926
622
  pendingConfirmation: undefined,
@@ -940,8 +636,6 @@ export function applyConfirmationResult(
940
636
  verdict: "CONFIRMED",
941
637
  proof_strength: recorded.proofStrength ?? null,
942
638
  model: verdict.model ?? null,
943
- panel: panelQuorumReached(bundle.panelVotes),
944
- override: verdict.panel_override_note ? true : false,
945
639
  reproduction_evidence_id: reproductionItem.id,
946
640
  },
947
641
  });