@clear-capabilities/agentic-security-scanner 0.161.0 → 0.163.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.
Files changed (182) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/bin/agentic-security.js +98 -2
  3. package/dist/1340.index.js +1871 -0
  4. package/dist/3477.index.js +727 -0
  5. package/dist/3499.index.js +23 -3
  6. package/dist/4113.index.js +59 -8
  7. package/dist/5014.index.js +833 -0
  8. package/dist/5756.index.js +2 -2
  9. package/dist/6257.index.js +1 -1
  10. package/dist/6907.index.js +248 -0
  11. package/dist/6994.index.js +1 -1
  12. package/dist/7033.index.js +33 -5
  13. package/dist/7439.index.js +1822 -0
  14. package/dist/7838.index.js +38 -2
  15. package/dist/8798.index.js +1 -1
  16. package/dist/9207.index.js +5 -0
  17. package/dist/9560.index.js +2336 -27
  18. package/dist/957.index.js +1 -1
  19. package/dist/{1905.index.js → 9999.index.js} +306 -13
  20. package/dist/agentic-security.mjs +12 -12
  21. package/dist/agentic-security.mjs.sha256 +1 -1
  22. package/package.json +39 -7
  23. package/src/capabilities/CLAUDE.md +114 -0
  24. package/src/capabilities/address.js +73 -0
  25. package/src/capabilities/attack-coverage.js +93 -0
  26. package/src/capabilities/decide.js +256 -0
  27. package/src/capabilities/delegate.js +69 -0
  28. package/src/capabilities/egress.js +20 -0
  29. package/src/capabilities/hook-advice.js +50 -0
  30. package/src/capabilities/index.js +32 -0
  31. package/src/capabilities/manifest.js +344 -0
  32. package/src/capabilities/outbound.js +189 -0
  33. package/src/capabilities/paths.js +57 -0
  34. package/src/capabilities/probes.js +211 -0
  35. package/src/capabilities/proxy.js +182 -0
  36. package/src/capabilities/reasons.js +67 -0
  37. package/src/capabilities/receipts.js +356 -0
  38. package/src/capabilities/records.js +58 -0
  39. package/src/capabilities/recovery.js +367 -0
  40. package/src/capabilities/report.js +81 -0
  41. package/src/capabilities/runner.js +236 -0
  42. package/src/capabilities/secrets.js +26 -0
  43. package/src/capabilities/tool-gate.js +119 -0
  44. package/src/capabilities/tool-registry.js +60 -0
  45. package/src/dataflow/CLAUDE.md +29 -0
  46. package/src/dataflow/catalog.js +21 -0
  47. package/src/dataflow/engine.js +20 -0
  48. package/src/dataflow/guard-dominance.js +352 -0
  49. package/src/discovery/CLAUDE.md +18 -0
  50. package/src/discovery/index.js +43 -1
  51. package/src/discovery/lenses.js +18 -0
  52. package/src/discovery/memory.js +7 -5
  53. package/src/engine.js +80 -15
  54. package/src/fix/apply-fix-service.js +33 -3
  55. package/src/integrations/index.js +5 -2
  56. package/src/ir/CLAUDE.md +14 -0
  57. package/src/ir/implicit-handler-params.js +74 -0
  58. package/src/ir/parser-cs.js +20 -0
  59. package/src/ir/parser-go.js +30 -13
  60. package/src/ir/parser-java.js +11 -0
  61. package/src/language/nix-eval-isolation.js +33 -5
  62. package/src/lineage/CLAUDE.md +31 -0
  63. package/src/lineage/deployment/adapter-cloud.js +202 -0
  64. package/src/lineage/deployment/adapter-compose.js +90 -0
  65. package/src/lineage/deployment/adapter-kit.js +142 -0
  66. package/src/lineage/deployment/adapter-kubernetes.js +247 -0
  67. package/src/lineage/deployment/attack-paths.js +443 -0
  68. package/src/lineage/deployment/boundaries-run.js +223 -0
  69. package/src/lineage/deployment/boundary-graph.js +567 -0
  70. package/src/lineage/deployment/cross-repo.js +253 -0
  71. package/src/lineage/deployment/drift.js +383 -0
  72. package/src/lineage/deployment/ingest.js +221 -0
  73. package/src/lineage/deployment/projection.js +244 -0
  74. package/src/lineage/deployment/trace-correlation.js +541 -0
  75. package/src/lineage/source-registry.js +19 -0
  76. package/src/mcp/CLAUDE.md +14 -3
  77. package/src/mcp/invariant-tools.js +64 -0
  78. package/src/mcp/portfolio-tools.js +79 -0
  79. package/src/mcp/redact.js +15 -0
  80. package/src/mcp/server.js +24 -3
  81. package/src/mcp/tools.js +30 -5
  82. package/src/posture/CLAUDE.md +505 -0
  83. package/src/posture/accuracy-scorecard.js +95 -4
  84. package/src/posture/assurance/baseline-inventory.js +218 -0
  85. package/src/posture/assurance/baseline.js +322 -0
  86. package/src/posture/assurance/bounded-io.js +145 -0
  87. package/src/posture/assurance/config.js +299 -0
  88. package/src/posture/assurance/contracts.js +315 -0
  89. package/src/posture/assurance/identity.js +62 -0
  90. package/src/posture/assurance/migrations.js +259 -0
  91. package/src/posture/assurance/rollback.js +214 -0
  92. package/src/posture/assurance/rollout.js +200 -0
  93. package/src/posture/assurance/schema-kit.js +111 -0
  94. package/src/posture/assurance/verification-record.js +258 -0
  95. package/src/posture/attestation.js +5 -0
  96. package/src/posture/autopilot.js +28 -1
  97. package/src/posture/business-logic.js +26 -4
  98. package/src/posture/evaluation/bakeoff.js +148 -0
  99. package/src/posture/evaluation/custody.js +200 -0
  100. package/src/posture/evaluation/deployment-ablation.js +416 -0
  101. package/src/posture/evaluation/dev-cases.js +65 -0
  102. package/src/posture/evaluation/economics.js +85 -0
  103. package/src/posture/evaluation/gates.js +161 -0
  104. package/src/posture/evaluation/grouping.js +101 -0
  105. package/src/posture/evaluation/interval.js +132 -0
  106. package/src/posture/evaluation/invariant-ablation.js +325 -0
  107. package/src/posture/evaluation/labels.js +200 -0
  108. package/src/posture/evaluation/protocol.js +308 -0
  109. package/src/posture/evaluation/release-gate.js +209 -0
  110. package/src/posture/evaluation/report.js +158 -0
  111. package/src/posture/evaluation/runner.js +273 -0
  112. package/src/posture/evaluation/scan-child.js +80 -0
  113. package/src/posture/evaluation/score.js +174 -0
  114. package/src/posture/evaluation/synthetic.js +90 -0
  115. package/src/posture/evaluation/why-missed.js +219 -0
  116. package/src/posture/evidence-bundle.js +93 -7
  117. package/src/posture/execution-proof.js +11 -1
  118. package/src/posture/fix-verify-loop.js +20 -6
  119. package/src/posture/fix-verify.js +37 -2
  120. package/src/posture/fleet.js +11 -2
  121. package/src/posture/invariants/cli.js +95 -0
  122. package/src/posture/invariants/coverage.js +164 -0
  123. package/src/posture/invariants/export.js +178 -0
  124. package/src/posture/invariants/expressions.js +46 -0
  125. package/src/posture/invariants/lifecycle.js +289 -0
  126. package/src/posture/invariants/project-input.js +55 -0
  127. package/src/posture/invariants/repair.js +340 -0
  128. package/src/posture/invariants/run.js +45 -0
  129. package/src/posture/invariants/scenarios.js +311 -0
  130. package/src/posture/invariants/schema.js +167 -0
  131. package/src/posture/invariants/shrink.js +407 -0
  132. package/src/posture/invariants/state-assertions.js +165 -0
  133. package/src/posture/logic-claims.js +12 -0
  134. package/src/posture/model-routing.js +40 -0
  135. package/src/posture/oracles/adapters.js +531 -0
  136. package/src/posture/oracles/conformance.js +276 -0
  137. package/src/posture/oracles/oracle.js +453 -0
  138. package/src/posture/oracles/registry.js +76 -0
  139. package/src/posture/oracles/scenario-classes.js +223 -0
  140. package/src/posture/portfolio/backend.js +279 -0
  141. package/src/posture/portfolio/bundle.js +314 -0
  142. package/src/posture/portfolio/cli.js +142 -0
  143. package/src/posture/portfolio/manifest.js +263 -0
  144. package/src/posture/portfolio/progress.js +267 -0
  145. package/src/posture/portfolio/resume.js +130 -0
  146. package/src/posture/portfolio/retention.js +207 -0
  147. package/src/posture/portfolio/scheduler.js +488 -0
  148. package/src/posture/portfolio/signing.js +155 -0
  149. package/src/posture/portfolio/wording.js +59 -0
  150. package/src/posture/portfolio/work-units.js +405 -0
  151. package/src/posture/replay/replay.js +250 -0
  152. package/src/posture/routing/adapter.js +140 -0
  153. package/src/posture/routing/calibration.js +278 -0
  154. package/src/posture/routing/canary.js +141 -0
  155. package/src/posture/routing/control.js +35 -0
  156. package/src/posture/routing/decide.js +211 -0
  157. package/src/posture/routing/drift.js +137 -0
  158. package/src/posture/routing/economics.js +185 -0
  159. package/src/posture/routing/feedback.js +207 -0
  160. package/src/posture/routing/index.js +31 -0
  161. package/src/posture/routing/outcomes.js +281 -0
  162. package/src/posture/routing/promotion.js +291 -0
  163. package/src/posture/routing/receipts.js +59 -0
  164. package/src/posture/routing/report.js +142 -0
  165. package/src/posture/routing/shadow.js +53 -0
  166. package/src/posture/specification-mining.js +26 -0
  167. package/src/posture/verification/advisory-state.js +71 -0
  168. package/src/posture/verification/emit.js +257 -0
  169. package/src/posture/verification/hypothesis-promotion.js +211 -0
  170. package/src/posture/verification/patch-negative.js +226 -0
  171. package/src/posture/verification/patch-promotion.js +113 -0
  172. package/src/posture/verification/projection.js +183 -0
  173. package/src/posture/verification/repair-records.js +124 -0
  174. package/src/posture/verifier.js +16 -0
  175. package/src/report/index.js +100 -1
  176. package/src/sandbox/CLAUDE.md +51 -0
  177. package/src/sandbox/backend-namespace.js +7 -0
  178. package/src/sandbox/backend-userspace.js +151 -34
  179. package/src/sandbox/control-probes.js +215 -0
  180. package/src/sandbox/supervise.js +201 -0
  181. package/src/sandbox/trust-boundary.js +113 -0
  182. package/src/sandbox/trust-domains.js +171 -0
@@ -6,11 +6,13 @@ export const modules = {
6
6
  /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
7
7
 
8
8
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
9
- /* harmony export */ H: () => (/* binding */ lensByKey),
9
+ /* harmony export */ Hy: () => (/* binding */ lensByKey),
10
10
  /* harmony export */ LENSES: () => (/* binding */ LENSES),
11
- /* harmony export */ j: () => (/* binding */ buildHunterPrompt)
11
+ /* harmony export */ gj: () => (/* binding */ invariantProposalFor),
12
+ /* harmony export */ jM: () => (/* binding */ buildHunterPrompt)
12
13
  /* harmony export */ });
13
- /* harmony import */ var _egress_redact_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(74831);
14
+ /* harmony import */ var _egress_redact_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(11723);
15
+ /* harmony import */ var _posture_invariants_lifecycle_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(80891);
14
16
  //
15
17
  // The seven hunting lenses. Each hunter run is one (focus area × lens) pair.
16
18
  //
@@ -21,6 +23,7 @@ export const modules = {
21
23
  // no single prompt reaches. `wildcard` exists because a fixed taxonomy is a
22
24
  // ceiling, and the classes worth finding are the ones not on the list.
23
25
 
26
+
24
27
  const LENSES = Object.freeze([
25
28
  { key: 'injection', title: 'Injection', family: 'injection', cwe: 'CWE-74',
26
29
  brief: 'Untrusted input reaching an interpreter: SQL, shell, template, XPath, LDAP, or deserialization. Follow the value, not the function name.' },
@@ -38,6 +41,23 @@ const LENSES = Object.freeze([
38
41
  brief: 'Anything the other lenses do not cover. Prefer the surprising and specific over the generic; report nothing rather than something already obvious.' },
39
42
  ]);
40
43
 
44
+ // X-402: the lenses that reason about who may do what to whose data can propose an INVARIANT for a candidate they raise. The
45
+ // proposal is a skeleton contract authored by the model (`proposed`, with the candidate as source evidence and a high uncertainty),
46
+ // advisory until a reviewer approves it in the signed ledger. A lens whose candidates are not about state (injection, crypto) has
47
+ // no mapping and proposes nothing.
48
+ const TENANT_HINT = /tenant|idor|ownership|object reference|cross[- ]?(?:account|user|org)|leak|another user|other user/i;
49
+ const WORKFLOW_HINT = /refund|order|status|workflow|state machine|out[- ]of[- ]order|step|approval|checkout|paid|ship/i;
50
+
51
+ function invariantProposalFor(candidate) {
52
+ const text = `${candidate?.title || ''} ${candidate?.description || ''} ${candidate?.rationale || ''}`;
53
+ let cls = null;
54
+ if (candidate?.lens === 'authz') cls = TENANT_HINT.test(text) ? 'tenant-isolation' : 'privilege-constraint';
55
+ else if (candidate?.lens === 'feature-abuse' && TENANT_HINT.test(text)) cls = 'tenant-isolation';
56
+ else if (candidate?.lens === 'business-logic' && WORKFLOW_HINT.test(text)) cls = 'workflow-order';
57
+ if (!cls || typeof candidate.file !== 'string') return null;
58
+ return (0,_posture_invariants_lifecycle_js__WEBPACK_IMPORTED_MODULE_1__/* .inferredInvariant */ .mB)({ class: cls, source: 'discovery-lens', evidence: { file: candidate.file, line: Number.isInteger(candidate.line) ? candidate.line : null, lens: candidate.lens }, uncertainty: 0.85 });
59
+ }
60
+
41
61
  function lensByKey(key) {
42
62
  if (typeof key !== 'string') return null;
43
63
  return LENSES.find(l => l.key === key) || null;
@@ -531,6 +531,7 @@ __webpack_require__.a(__webpack_module__, async (__webpack_handle_async_dependen
531
531
  /* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(73024);
532
532
  /* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(76760);
533
533
  /* harmony import */ var _fix_verify_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(27838);
534
+ /* harmony import */ var _verification_emit_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(85578);
534
535
  var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([_fix_verify_js__WEBPACK_IMPORTED_MODULE_3__]);
535
536
  _fix_verify_js__WEBPACK_IMPORTED_MODULE_3__ = (__webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__)[0];
536
537
  // Closed-loop fix verification (v0.68).
@@ -559,6 +560,7 @@ _fix_verify_js__WEBPACK_IMPORTED_MODULE_3__ = (__webpack_async_dependencies__.th
559
560
 
560
561
 
561
562
 
563
+
562
564
  const DEFAULT_TIMEOUT_MS = 120_000;
563
565
 
564
566
  // Test-runner discovery. Each entry: a sentinel-file check + a command +
@@ -666,20 +668,32 @@ async function verifyFixWithTests({
666
668
  runTests = true,
667
669
  testRunnerOverride,
668
670
  testTimeoutMs,
671
+ patchNegative,
672
+ assuranceConfig,
669
673
  } = {}) {
670
- const scanLint = await (0,_fix_verify_js__WEBPACK_IMPORTED_MODULE_3__.verifyFix)({ scanRoot, originalFindingStableId, files, depFileContents });
674
+ const scanLint = await (0,_fix_verify_js__WEBPACK_IMPORTED_MODULE_3__.verifyFix)({ scanRoot, originalFindingStableId, files, depFileContents, patchNegative, assuranceConfig });
671
675
  const legs = {
672
676
  scan: { ok: scanLint.rescan?.ok ?? scanLint.ok, detail: scanLint.rescan ?? scanLint },
673
677
  lint: { ok: scanLint.lint?.ok ?? true, detail: scanLint.lint ?? null },
674
678
  tests: { ok: true, detail: null, skipped: true, reason: 'not-run' },
675
679
  };
676
- if (!legs.scan.ok || !legs.lint.ok) {
677
- return {
680
+ // X-201: the closed loop's own record (additive). It runs the detector, linter and project tests, never an exploit
681
+ // oracle, so it can say `not-run` or `error` and nothing stronger.
682
+ const withRecord = (res) => {
683
+ const e = (0,_verification_emit_js__WEBPACK_IMPORTED_MODULE_4__/* .emitVerification */ .T)('fix-verify-loop', res, { originalFindingStableId, files, scanRoot });
684
+ return { ...res, verificationRecord: e.ok ? e.record : null };
685
+ };
686
+ // X-204: the patch-negative leg is present only when it was requested and its feature is on. A patch the oracle did not verify
687
+ // is never `verified-clean`, whatever the other legs say.
688
+ const pn = scanLint.patchNegative && scanLint.patchNegative.status !== 'disabled' ? scanLint.patchNegative : null;
689
+ if (pn) legs.patchNegative = { ok: pn.verifiedFix === true, detail: { status: pn.status, incompleteStep: pn.incompleteStep, failureCode: pn.failureCode, reason: pn.reason } };
690
+ if (!legs.scan.ok || !legs.lint.ok || (pn && !legs.patchNegative.ok)) {
691
+ return withRecord({
678
692
  ok: false,
679
693
  verdict: 'verification-failed',
680
694
  legs,
681
695
  summary: _summarize(legs, 'verification-failed'),
682
- };
696
+ });
683
697
  }
684
698
  if (runTests) {
685
699
  const tests = runProjectTests(scanRoot, { runnerOverride: testRunnerOverride, timeoutMs: testTimeoutMs });
@@ -688,8 +702,8 @@ async function verifyFixWithTests({
688
702
  const allOk = legs.scan.ok && legs.lint.ok && legs.tests.ok;
689
703
  const verdict = !allOk
690
704
  ? 'verification-failed'
691
- : (legs.tests.skipped ? 'untested-but-passes' : 'verified-clean');
692
- return { ok: allOk, verdict, legs, summary: _summarize(legs, verdict) };
705
+ : pn ? 'verified-fix' : (legs.tests.skipped ? 'untested-but-passes' : 'verified-clean');
706
+ return withRecord({ ok: allOk, verdict, legs, summary: _summarize(legs, verdict) });
693
707
  }
694
708
 
695
709
  function _summarize(legs, verdict) {
@@ -697,6 +711,7 @@ function _summarize(legs, verdict) {
697
711
  bits.push(`scan: ${legs.scan.ok ? 'pass' : 'fail'}`);
698
712
  bits.push(`lint: ${legs.lint.skipped ? 'skip' : legs.lint.ok ? 'pass' : 'fail'}`);
699
713
  bits.push(`tests: ${legs.tests.skipped ? 'skip' : legs.tests.ok ? 'pass' : 'fail'}`);
714
+ if (legs.patchNegative) bits.push(`patch-negative: ${legs.patchNegative.ok ? 'pass' : `fail (${legs.patchNegative.detail.incompleteStep})`}`);
700
715
  return `${verdict} (${bits.join(' · ')})`;
701
716
  }
702
717
 
@@ -722,6 +737,7 @@ __webpack_require__.r(__webpack_exports__);
722
737
  /* harmony import */ var _fix_honesty_gate_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(27785);
723
738
  /* harmony import */ var _test_runner_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(35136);
724
739
  /* harmony import */ var _fix_metrics_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(32238);
740
+ /* harmony import */ var _verification_emit_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(85578);
725
741
  var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([_engine_js__WEBPACK_IMPORTED_MODULE_3__]);
726
742
  _engine_js__WEBPACK_IMPORTED_MODULE_3__ = (__webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__)[0];
727
743
  // Closed-loop /fix verification (Sentinel-parity FR-L4-4, FR-L4-5).
@@ -749,6 +765,7 @@ _engine_js__WEBPACK_IMPORTED_MODULE_3__ = (__webpack_async_dependencies__.then ?
749
765
 
750
766
 
751
767
 
768
+
752
769
  const SEVERITY_RANK = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };
753
770
 
754
771
  // Run a focused re-scan over just the patched file(s) using the in-memory
@@ -913,6 +930,8 @@ async function verifyFix({
913
930
  testTimeoutMs,
914
931
  recordMetrics = true,
915
932
  poc,
933
+ patchNegative,
934
+ assuranceConfig,
916
935
  } = {}) {
917
936
  // R5 (reporting half) — time each stage as it runs. Measured here rather
918
937
  // than inside each stage because only this function knows the boundaries of
@@ -995,7 +1014,26 @@ async function verifyFix({
995
1014
  }
996
1015
  _lap('honesty');
997
1016
 
998
- const ok = rescan.ok && (lint.ok || lint.skipped) && testsOk && pocOk && (honesty ? honesty.ok : true);
1017
+ // X-204: patch-negative verification, only when the caller asked for it AND the `patch-negative-verification` feature is
1018
+ // on. `patchNegative` is the requester's exploit scenario and functional cases ({ original, functional, commit?, ... }); the
1019
+ // candidate `files` are the proposed diff. With the flag off, or no request, nothing here runs and every field below is
1020
+ // exactly what it was before.
1021
+ let pn = null;
1022
+ if (patchNegative && typeof patchNegative === 'object') {
1023
+ try {
1024
+ const { verifyPatchNegative } = await __webpack_require__.e(/* import() */ 6907).then(__webpack_require__.bind(__webpack_require__, 26907));
1025
+ pn = await verifyPatchNegative({
1026
+ hypothesisId: originalFindingStableId, ...patchNegative, patch: { files },
1027
+ commit: patchNegative.commit ?? (0,_verification_emit_js__WEBPACK_IMPORTED_MODULE_7__.headCommit)(scanRoot),
1028
+ }, { config: assuranceConfig });
1029
+ } catch (e) {
1030
+ pn = { status: 'error', verifiedFix: false, incompleteStep: 'patch-negative', failureCode: 'harness-error', reason: `patch-negative verification failed to run: ${String(e?.message || e).slice(0, 200)}`, summary: '' };
1031
+ }
1032
+ }
1033
+ const pnActive = pn !== null && pn.status !== 'disabled';
1034
+ _lap('patchNegative');
1035
+
1036
+ const ok = rescan.ok && (lint.ok || lint.skipped) && testsOk && pocOk && (honesty ? honesty.ok : true) && (pnActive ? pn.verifiedFix === true : true);
999
1037
 
1000
1038
  // FR-305 (assurance-hardening PRD): `ok` alone conflates "every leg
1001
1039
  // genuinely ran and passed" with "passed, but a required leg was skipped
@@ -1037,6 +1075,7 @@ async function verifyFix({
1037
1075
  : pocLeg.status === 'no-longer-proven' ? 'poc: PASS (ran against the patch and no longer demonstrates the vulnerability)'
1038
1076
  : `poc: inconclusive — not counted either way (${pocLeg.reason || 'no detail reported'})`,
1039
1077
  // FR-305: never let a degraded pass read the same as a full one.
1078
+ pnActive ? `patch-negative: ${pn.verifiedFix ? 'PASS (verified-fix)' : `FAIL - not verified-fix, incomplete step '${pn.incompleteStep}' (${pn.failureCode}): ${pn.reason}`}` : null,
1040
1079
  ok && !verifiedFull ? `NOTE: PASSED, but NOT fully verified — ${degradedLegs.join('; ')}` : null,
1041
1080
  ].filter(Boolean).join('\n');
1042
1081
  // Persist the attempt so the distribution can be reported from real runs.
@@ -1063,7 +1102,19 @@ async function verifyFix({
1063
1102
  });
1064
1103
  }
1065
1104
 
1066
- return { ok, verifiedFull, degradedLegs, rescan, lint, tests, testedPrePatch: _testedPrePatch, honesty, poc: pocLeg, durations, summary };
1105
+ // X-201: the one verification record, ADDITIVE. `ok` and every field above stay exactly as they were; the record
1106
+ // says what was actually established (a static re-scan is not an exploit oracle, so without a PoC leg it is
1107
+ // `not-run`, and nothing here can reach `confirmed`/`refuted`: that takes a trusted oracle adapter).
1108
+ const emitted = (0,_verification_emit_js__WEBPACK_IMPORTED_MODULE_7__/* .emitVerification */ .T)('fix-verify', { rescan, lint, tests, poc: pocLeg }, {
1109
+ originalFindingStableId, files, scanRoot, finding: poc?.finding,
1110
+ });
1111
+ const verificationRecord = emitted.ok ? emitted.record : null;
1112
+
1113
+ return {
1114
+ ok, verifiedFull, degradedLegs, rescan, lint, tests, testedPrePatch: _testedPrePatch, honesty, poc: pocLeg, durations, summary, verificationRecord,
1115
+ // additive, present only when patch-negative verification was requested (X-204)
1116
+ ...(pn ? { patchNegative: pn, ...(pnActive ? { fixStatus: pn.verifiedFix ? 'verified-fix' : 'not-verified-fix' } : {}) } : {}),
1117
+ };
1067
1118
  }
1068
1119
 
1069
1120
  __webpack_async_result__();