@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
@@ -111,6 +111,55 @@ export function aggregateCorpus(detail) {
111
111
  };
112
112
  }
113
113
 
114
+ /**
115
+ * Real-code evaluation gates (programme QA-001/QA-003). Takes the committed gate
116
+ * report written by `scripts/evaluation.mjs gates` (or nothing) and returns the
117
+ * section the scorecard publishes. It can only RELAY a status: a synthetic
118
+ * protocol is forced to `unmeasured`, and an absent report is `unmeasured` with
119
+ * the reason, never an empty pass. Pure.
120
+ */
121
+ export function summarizeMeasurement(provenance, independent) {
122
+ const p = provenance || {};
123
+ const clean = p.worktreeClean === true;
124
+ const hist = independent && independent.engineVersion && independent.engineVersion !== p.engineVersion;
125
+ return {
126
+ engineVersion: p.engineVersion || null, commit: p.commit || null, bundleSha256: p.bundleSha256 || null,
127
+ cleanMeasurement: clean,
128
+ identity: clean
129
+ ? 'the commit and bundle below identify exactly the tree that was measured'
130
+ : p.worktreeClean === false ? 'the worktree was dirty: the commit below does NOT identify what was measured, so this is not a clean measurement' : 'cleanliness of the measured tree was not recorded',
131
+ currentEngineIndependentAccuracy: 'unmeasured',
132
+ currentEngineIndependentReason: 'no adjudicated real-code population has been run against this engine; the independent record in this document, if any, describes an older engine',
133
+ historicalIndependentRecord: hist
134
+ ? { engineVersion: independent.engineVersion, measuredAt: independent.measuredAt || null, usage: 'historical record only; not a measurement of the engine above and not combined with the corpus figures' }
135
+ : null,
136
+ };
137
+ }
138
+
139
+ export function summarizeEvaluationGates(report) {
140
+ if (!report || typeof report !== 'object') {
141
+ return {
142
+ measuredThisRun: false, status: 'unmeasured', synthetic: null, gates: [],
143
+ reason: 'no frozen real-code evaluation protocol and no sealed adjudicated population exist yet; no real-code gate has been evaluated',
144
+ };
145
+ }
146
+ const gates = Array.isArray(report.gates) ? report.gates.map((g) => ({ id: g.id, status: g.status, threshold: g.threshold ?? null, measured: g.measured ?? null, reason: g.reason || null })) : [];
147
+ const synthetic = report.synthetic !== false;
148
+ const counts = {};
149
+ for (const g of gates) counts[g.status] = (counts[g.status] || 0) + 1;
150
+ return {
151
+ measuredThisRun: false,
152
+ source: 'bench/independent/evaluation-gates.json',
153
+ protocolHash: report.protocolHash || null,
154
+ synthetic,
155
+ // A synthetic protocol can exercise the machinery; it can never publish a gate result.
156
+ status: synthetic ? 'unmeasured' : (report.overall || 'unmeasured'),
157
+ reason: synthetic ? 'the recorded protocol is synthetic; its results are not real-code evidence' : (report.population?.reason || null),
158
+ gates: synthetic ? [] : gates,
159
+ gateCounts: synthetic ? {} : counts,
160
+ };
161
+ }
162
+
114
163
  /**
115
164
  * Build the machine-readable scorecard model. `inputs`:
116
165
  * provenance { engineVersion, bundleSha256, commit, nodeVersion, generatedAt,
@@ -227,6 +276,10 @@ export function buildScorecard(inputs) {
227
276
  source: 'bench/independent/RESULT.json',
228
277
  measuredAt: committed.independent.measuredAt || null,
229
278
  engineVersion: committed.independent.engineVersion || null,
279
+ // QA-008.AC01: this record belongs to the engine it names. When that is not the engine this scorecard measured, it is a
280
+ // HISTORICAL record: kept, dated, labelled, and never combined with the curated-corpus figures into one accuracy claim.
281
+ historical: !!committed.independent.engineVersion && committed.independent.engineVersion !== (inputs.provenance || {}).engineVersion,
282
+ comparableToCurrentEngine: !!committed.independent.engineVersion && committed.independent.engineVersion === (inputs.provenance || {}).engineVersion,
230
283
  population: committed.independent.population || null,
231
284
  overall: committed.independent.overall || null,
232
285
  wide: committed.independent.wide || null,
@@ -293,6 +346,10 @@ export function buildScorecard(inputs) {
293
346
  // frameworks" from "this scorecard predates the metric" the same way
294
347
  // every other section here distinguishes absence from zero.
295
348
  complianceMappingCoverage: inputs.complianceMappingCoverage || [],
349
+ // QA-001/QA-003: the real-code gates registered in the evaluation protocol. Relayed, never computed here.
350
+ evaluationGates: summarizeEvaluationGates(inputs.evaluation),
351
+ // QA-008.AC01: what this scorecard measured, stated once. `clean` is what lets the commit and bundle identify the measured tree.
352
+ measurement: summarizeMeasurement(inputs.provenance, committed.independent),
296
353
  };
297
354
  }
298
355
 
@@ -344,6 +401,10 @@ export function renderScorecardMarkdown(m) {
344
401
  if (p.worktreeClean !== undefined) {
345
402
  L.push(`| Worktree at measurement time | ${p.worktreeClean ? 'clean' : 'DIRTY — the commit above does not fully describe what was measured'} |`);
346
403
  }
404
+ if (m.measurement) {
405
+ L.push(`| Measurement identity | ${m.measurement.cleanMeasurement ? 'clean measurement: the commit and bundle above identify the measured tree' : 'NOT a clean measurement: the commit and bundle above do not identify the measured tree'} |`);
406
+ L.push('| Independent accuracy of THIS engine | unmeasured (no adjudicated real-code population has been run; see the historical record below, if present) |');
407
+ }
347
408
  L.push(`| Node | ${p.nodeVersion || 'unknown'} |`);
348
409
  L.push(`| Corpus entries | ${c.totalEntries} (${c.scoredEntries} scored) |`);
349
410
  // FR-901: "Published results identify engine version, corpus version,
@@ -674,8 +735,17 @@ export function renderScorecardMarkdown(m) {
674
735
 
675
736
  const ind = m.committedInputs.independent;
676
737
  if (ind && ind.overall) {
677
- L.push('## Independent evaluation population — the number that matters');
738
+ const hist = ind.historical === true;
739
+ L.push(hist
740
+ ? `## Independent evaluation population: historical record (engine ${ind.engineVersion}, ${ind.measuredAt || 'undated'})`
741
+ : '## Independent evaluation population — the number that matters');
678
742
  L.push('');
743
+ if (hist) {
744
+ L.push(`**This is a historical record of engine ${ind.engineVersion}, measured ${ind.measuredAt || 'on an unrecorded date'}.** It is not a measurement of the`);
745
+ L.push(`engine this scorecard describes (${p.engineVersion || 'unknown'}), it is a different population from the curated corpus above, and the two are`);
746
+ L.push('never combined into one accuracy figure. The current engine has no independent figure: it is **unmeasured**.');
747
+ L.push('');
748
+ }
679
749
  L.push('Everything above is a **regression net**: its fixtures and its labels are both');
680
750
  L.push('written here, which is why its detection rate sits at the ceiling by');
681
751
  L.push('construction. `bench/independent/` is the other instrument — real upstream code');
@@ -715,9 +785,14 @@ export function renderScorecardMarkdown(m) {
715
785
  L.push('class at all, a question with a much easier yes. It is kept because it is the');
716
786
  L.push('only way to tell whether a change moved the engine or moved the benchmark.');
717
787
  L.push('');
718
- L.push('Against ~100% on the curated corpus above. **That gap is the most useful number');
719
- L.push('in this document**, and publishing it is the point of the exercise. The figure');
720
- L.push('went DOWN when the benchmark was corrected, and is published that way.');
788
+ if (hist) {
789
+ L.push(`This record is kept, dated and labelled because it is the last independent measurement the project made. It describes engine ${ind.engineVersion} only.`);
790
+ L.push('It does not describe the engine above, and the curated-corpus rates earlier in this document are a different population that must not be read beside it as one claim.');
791
+ } else {
792
+ L.push('Against ~100% on the curated corpus above. **That gap is the most useful number');
793
+ L.push('in this document**, and publishing it is the point of the exercise. The figure');
794
+ L.push('went DOWN when the benchmark was corrected, and is published that way.');
795
+ }
721
796
  L.push('');
722
797
  // FR-904 (assurance-hardening PRD): "rule authors cannot optimize
723
798
  // against the full scored population." T0.7's held-out slice is a
@@ -771,6 +846,22 @@ export function renderScorecardMarkdown(m) {
771
846
  }
772
847
  }
773
848
  }
849
+ const eg = m.evaluationGates || summarizeEvaluationGates(null);
850
+ L.push('## Real-code evaluation gates');
851
+ L.push('');
852
+ L.push(`Status: **${eg.status}**${eg.reason ? ` (${eg.reason})` : ''}.`);
853
+ L.push('');
854
+ L.push('The gates (per-language F1, micro and macro F1, pooled precision and recall, completion) are registered');
855
+ L.push('in a frozen protocol before any result is observed, and can read `pass` only on an independently');
856
+ L.push('adjudicated sealed population that meets the registered minimums. `insufficient-population` and');
857
+ L.push('`unmeasured` are honest blockers, not failures and not passes.');
858
+ if (eg.gates.length) {
859
+ L.push('');
860
+ L.push('| Gate | Status | Threshold | Measured |');
861
+ L.push('| --- | --- | --- | --- |');
862
+ for (const g of eg.gates) L.push(`| ${g.id} | ${g.status} | ${g.threshold ?? 'n/a'} | ${g.measured ?? 'n/a'} |`);
863
+ }
864
+ L.push('');
774
865
  L.push('## Committed artifacts referenced (not re-run by this command)');
775
866
  L.push('');
776
867
  const cb = m.committedInputs.corpusBaseline;
@@ -0,0 +1,218 @@
1
+ // The recommendation mappings and the capability inventory that baseline capture
2
+ // (CORE-001) records. Pure data. Every path is relative to the repository root and
3
+ // is VERIFIED against the checkout at capture time: a path that does not exist is
4
+ // reported as a problem, never carried as if it did.
5
+ //
6
+ // Status vocabulary (one per capability, never combined):
7
+ // implemented the capability exists, has a source path and a test or artifact,
8
+ // and no gap against the differentiation PRD is known.
9
+ // partial it exists and is tested, and `gap` names exactly what the PRD
10
+ // still needs on top of it.
11
+ // unsupported the PRD calls for it and the checkout does not provide it; `source`
12
+ // is the existing extension point it would attach to, `evidence` the
13
+ // test that covers that neighbour, and `gap` says what is absent.
14
+ // unmeasured it exists but no current-revision measurement of it is recorded;
15
+ // `evidence` is the artifact that exists and `gap` says why it is not a
16
+ // current measurement.
17
+ //
18
+ // This is a statement about what was inspected, not a quality score. Moving an
19
+ // entry to a stronger status needs the new source and evidence paths to land first.
20
+
21
+ export const RECOMMENDATION_MAPPINGS = Object.freeze([
22
+ {
23
+ n: 1, title: 'Refresh real-code evaluation and repair measured misses', priority: 'P0', slice: 'QA-001..QA-008',
24
+ extensionPoints: ['bench/independent', 'scanner/src/posture/accuracy-scorecard.js', 'scripts/scorecard.mjs', 'docs/scorecard.json'],
25
+ },
26
+ {
27
+ n: 2, title: 'Unify verification and expand trusted runtime oracles', priority: 'P0', slice: 'X-201..X-208',
28
+ extensionPoints: ['scanner/src/posture/fix-verify.js', 'scanner/src/posture/execution-proof.js', 'scanner/src/posture/verifier.js', 'scanner/src/sandbox/index.js', 'scanner/src/posture/autopilot.js', 'scanner/src/mcp/tools.js'],
29
+ },
30
+ {
31
+ n: 3, title: 'Add a deployment-aware Code Boundaries graph', priority: 'P1', slice: 'X-301..X-308',
32
+ extensionPoints: ['scanner/src/lineage/runtime-observation.js', 'scanner/src/lineage/observation-adapters.js', 'scanner/src/lineage/observation-correlation.js', 'scanner/src/lineage/cross-repo-link.js', 'scanner/src/lineage/federation-loader.js', 'scanner/src/lineage/drift-policy.js'],
33
+ },
34
+ {
35
+ n: 4, title: 'Execute tenant and business invariants', priority: 'P1', slice: 'X-401..X-408',
36
+ extensionPoints: ['scanner/src/posture/business-logic.js', 'scanner/src/posture/logic-claims.js', 'scanner/src/posture/specification-mining.js', 'scanner/src/discovery'],
37
+ },
38
+ {
39
+ n: 5, title: 'Enforce coding-agent capabilities', priority: 'P1', slice: 'X-501..X-508',
40
+ extensionPoints: ['hooks/pre-bash-guard.js', 'hooks/pre-edit-bodyguard.js', 'hooks/dispatch-pre-tool.js', 'scanner/src/egress/policy.js', 'scanner/src/egress/redact.js', 'scanner/src/egress/audit.js', 'scanner/src/sandbox/index.js', 'scanner/src/mcp/server.js'],
41
+ },
42
+ {
43
+ n: 6, title: 'Calibrate model routing against outcomes', priority: 'P2', slice: 'X-601..X-608',
44
+ extensionPoints: ['scanner/src/posture/model-routing.js', 'scanner/src/posture/model-trust.js', 'scanner/src/posture/cache-economics.js', 'scanner/src/posture/provider-catalog.js'],
45
+ },
46
+ {
47
+ n: 7, title: 'Deliver portable release assurance and resumable portfolios', priority: 'P2', slice: 'X-701..X-708',
48
+ extensionPoints: ['scanner/src/posture/fleet.js', 'scanner/src/posture/scan-checkpoint.js', 'scanner/src/posture/attestation.js', 'scanner/src/posture/evidence-bundle.js', 'scanner/src/posture/integrity.js', 'scanner/src/posture/retention-policy.js'],
49
+ },
50
+ ]);
51
+
52
+ const t = (p) => ({ kind: 'test', path: p });
53
+ const a = (p) => ({ kind: 'artifact', path: p });
54
+
55
+ export const CAPABILITY_INVENTORY = Object.freeze([
56
+ {
57
+ id: 'poc-replay', workstream: 2, title: 'Proof-of-concept generation and confined replay',
58
+ status: 'partial',
59
+ source: ['scanner/src/posture/poc-generator.js', 'scanner/src/posture/poc-inprocess.js', 'scanner/src/posture/execution-proof.js', 'scanner/src/posture/proof-tier.js'],
60
+ entryPoints: [{ path: 'scanner/src/posture/execution-proof.js', symbol: 'proveFinding' }, { path: 'scanner/src/posture/proof-tier.js', symbol: 'attachProofTier' }],
61
+ evidence: [t('scanner/test/poc-generator.test.js'), t('scanner/test/execution-proof.test.js'), t('scanner/test/proof-artifact.test.js')],
62
+ gap: 'replay is JavaScript/taint oriented and records a proof tier on the finding; there is no class-specific oracle adapter, no patched-negative replay, and no single verification record',
63
+ prd: ['X-201', 'X-202', 'X-203', 'X-204', 'X-205'],
64
+ },
65
+ {
66
+ id: 'fix-verification', workstream: 2, title: 'Fix verification (rescan, lint, tests, honesty gate, PoC re-check)',
67
+ status: 'partial',
68
+ source: ['scanner/src/posture/fix-verify.js', 'scanner/src/posture/fix-verify-loop.js', 'scanner/src/fix/apply-fix-service.js', 'scanner/src/posture/fix-honesty-gate.js'],
69
+ entryPoints: [{ path: 'scanner/src/posture/fix-verify.js', symbol: 'verifyFix' }, { path: 'scanner/src/fix/apply-fix-service.js', symbol: 'applyVerifiedFix' }],
70
+ evidence: [t('scanner/test/fix-verify-loop.test.js'), t('scanner/test/fix-verify-tests.test.js'), t('scanner/test/apply-fix-service.test.js'), t('scanner/test/fix-honesty-gate.test.js')],
71
+ gap: 'results are per-surface shapes, not one versioned record; original-positive, patched-negative and functional-regression evidence are not bound together by digest',
72
+ prd: ['X-201', 'X-204', 'X-206'],
73
+ },
74
+ {
75
+ id: 'verifier-separation', workstream: 2, title: 'Independent verifier and verification separation',
76
+ status: 'partial',
77
+ source: ['scanner/src/posture/verifier.js', 'scanner/src/posture/verification-separation.js', 'scanner/src/posture/verifier-target.js', 'scanner/src/posture/verifier-ephemeral.js'],
78
+ entryPoints: [],
79
+ evidence: [t('scanner/test/verifier.test.js'), t('scanner/test/verifier-independence.test.js'), t('scanner/test/verification-separation.test.js')],
80
+ gap: 'separation is enforced for the existing verifier path; key and label isolation for the new oracle workers is the CORE-003 trust-boundary work',
81
+ prd: ['CORE-003', 'X-202'],
82
+ },
83
+ {
84
+ id: 'sandbox-confinement', workstream: 2, title: 'Confinement sandbox (namespace, userspace and disabled backends)',
85
+ status: 'partial',
86
+ source: ['scanner/src/sandbox/index.js', 'scanner/src/sandbox/capabilities.js', 'scanner/src/sandbox/limits.js', 'scanner/src/sandbox/backend-namespace.js', 'scanner/src/sandbox/backend-userspace.js', 'scanner/src/sandbox/backend-disabled.js'],
87
+ entryPoints: [{ path: 'scanner/src/sandbox/index.js', symbol: 'runConfined' }],
88
+ evidence: [t('scanner/test/sandbox.test.js'), t('scanner/test/sandbox-escape.test.js')],
89
+ gap: 'isolation is probed per backend; descendant-process cleanup, read confinement and per-backend active probes are the CORE-003 work, and enforcement is only advertised on Linux',
90
+ prd: ['CORE-003', 'X-502', 'X-503'],
91
+ },
92
+ {
93
+ id: 'runtime-observation-imports', workstream: 3, title: 'Runtime observation imports and correlation',
94
+ status: 'partial',
95
+ source: ['scanner/src/lineage/runtime-observation.js', 'scanner/src/lineage/observation-adapters.js', 'scanner/src/lineage/observation-store.js', 'scanner/src/lineage/observation-correlation.js', 'scanner/src/posture/telemetry-ingest.js'],
96
+ entryPoints: [{ path: 'scanner/src/lineage/runtime-observation.js', symbol: 'validateRuntimeObservation' }, { path: 'scanner/src/lineage/observation-store.js', symbol: 'persistObservationImport' }],
97
+ evidence: [t('scanner/test/lineage/runtime-observation.test.js'), t('scanner/test/lineage/observation-adapters.test.js'), t('scanner/test/lineage/observation-store.test.js'), t('scanner/test/lineage/observation-correlation.test.js')],
98
+ gap: 'one adapter (native-jsonl) is implemented; observations corroborate lineage edges but do not yet bind to vulnerability hypotheses, and freshness and sampling are not modelled as path states',
99
+ prd: ['X-302', 'X-303', 'X-305'],
100
+ },
101
+ {
102
+ id: 'cross-repo-federation-drift', workstream: 3, title: 'Cross-repository links, federation and drift policy',
103
+ status: 'implemented',
104
+ source: ['scanner/src/lineage/cross-repo-link.js', 'scanner/src/lineage/federation-loader.js', 'scanner/src/lineage/drift-policy.js', 'scanner/src/lineage/graph-diff.js'],
105
+ entryPoints: [{ path: 'scanner/src/lineage/cross-repo-link.js', symbol: 'validateCrossRepoLink' }],
106
+ evidence: [t('scanner/test/lineage/cross-repo-link.test.js'), t('scanner/test/lineage/federation-loader.test.js'), t('scanner/test/lineage/drift-policy.test.js')],
107
+ gap: null,
108
+ prd: ['X-304', 'X-306'],
109
+ },
110
+ {
111
+ id: 'business-logic-claims', workstream: 4, title: 'Business-logic detection, logic claims and specification mining',
112
+ status: 'partial',
113
+ source: ['scanner/src/posture/business-logic.js', 'scanner/src/posture/logic-claims.js', 'scanner/src/posture/specification-mining.js'],
114
+ entryPoints: [],
115
+ evidence: [t('scanner/test/business-logic.test.js'), t('scanner/test/logic-claims.test.js'), t('scanner/test/phase3-v3.test.js')],
116
+ gap: 'claims are advisory findings; there are no declarative approved invariants and no bounded stateful scenario execution',
117
+ prd: ['X-401', 'X-402', 'X-403', 'X-404'],
118
+ },
119
+ {
120
+ id: 'stateful-invariant-execution', workstream: 4, title: 'Approved invariants, stateful scenarios, state oracles and sequence shrinking',
121
+ status: 'unsupported',
122
+ source: ['scanner/src/posture/logic-claims.js', 'scanner/src/discovery'],
123
+ entryPoints: [],
124
+ evidence: [t('scanner/test/logic-claims.test.js')],
125
+ gap: 'no executable invariant contract, approval state, scenario generator, durable-effect oracle or minimizer exists in the checkout',
126
+ prd: ['X-401', 'X-403', 'X-404', 'X-405'],
127
+ },
128
+ {
129
+ id: 'egress-policy-redaction-audit', workstream: 5, title: 'Central egress policy, outbound redaction and tamper-evident audit',
130
+ status: 'implemented',
131
+ source: ['scanner/src/egress/policy.js', 'scanner/src/egress/redact.js', 'scanner/src/egress/audit.js'],
132
+ entryPoints: [{ path: 'scanner/src/egress/policy.js', symbol: 'evaluateEgress' }, { path: 'scanner/src/egress/redact.js', symbol: 'redactPayload' }, { path: 'scanner/src/egress/audit.js', symbol: 'recordEgressCall' }],
133
+ evidence: [t('scanner/test/egress-policy.test.js'), t('scanner/test/egress-redact.test.js'), t('scanner/test/egress-audit.test.js'), t('scanner/test/egress-policy-completeness.test.js')],
134
+ gap: null,
135
+ prd: ['CORE-004', 'X-504'],
136
+ },
137
+ {
138
+ id: 'agent-hooks', workstream: 5, title: 'Pre-edit, pre-bash and dispatch hooks',
139
+ status: 'partial',
140
+ source: ['hooks/pre-bash-guard.js', 'hooks/pre-edit-bodyguard.js', 'hooks/dispatch-pre-tool.js', 'hooks/hooks.json'],
141
+ entryPoints: [],
142
+ evidence: [t('scanner/test/pre-bash-guard.test.js'), t('scanner/test/bodyguard.test.js'), t('scanner/test/dispatch-pre-tool.test.js')],
143
+ gap: 'hooks explain and advise at the prompt layer; no runner mediates filesystem, command or network access, so a hook response is not an enforcement receipt',
144
+ prd: ['X-501', 'X-502', 'X-505', 'X-507'],
145
+ },
146
+ {
147
+ id: 'mcp-server', workstream: 2, title: 'MCP server tools (including the write-gated fix tools)',
148
+ status: 'partial',
149
+ source: ['scanner/src/mcp/server.js', 'scanner/src/mcp/tools.js', 'scanner/src/mcp/validate.js', 'scanner/src/mcp/audit.js'],
150
+ entryPoints: [],
151
+ evidence: [t('scanner/test/mcp.test.js'), t('scanner/test/mcp-audit.test.js'), t('scanner/test/mcp-protocol-smoke.test.js')],
152
+ gap: 'tool results are not yet emitted as the unified verification record',
153
+ prd: ['X-206'],
154
+ },
155
+ {
156
+ id: 'model-routing-and-trust', workstream: 6, title: 'Model routing, measured trust, cache economics and provider catalog',
157
+ status: 'partial',
158
+ source: ['scanner/src/posture/model-routing.js', 'scanner/src/posture/model-trust.js', 'scanner/src/posture/cache-economics.js', 'scanner/src/posture/provider-catalog.js'],
159
+ entryPoints: [{ path: 'scanner/src/posture/model-trust.js', symbol: 'createTrustLedger' }, { path: 'scanner/src/posture/model-routing.js', symbol: 'routeModelWithTrust' }],
160
+ evidence: [t('scanner/test/model-routing.test.js'), t('scanner/test/model-trust.test.js'), t('scanner/test/cache-economics.test.js'), t('scanner/test/providers.test.js'), a('bench/router-replay/baseline.json')],
161
+ gap: 'trust is a per-key miss-rate ledger; there are no adjudicated task strata, calibrated quality intervals, shadow validation or drift circuit breakers',
162
+ prd: ['X-601', 'X-603', 'X-604', 'X-605'],
163
+ },
164
+ {
165
+ id: 'fleet-checkpoints', workstream: 7, title: 'Fleet runs and scan checkpoints',
166
+ status: 'partial',
167
+ source: ['scanner/src/posture/fleet.js', 'scanner/src/posture/scan-checkpoint.js', 'scripts/fleet.mjs'],
168
+ entryPoints: [{ path: 'scanner/src/posture/scan-checkpoint.js', symbol: 'openCheckpoint' }],
169
+ evidence: [t('scanner/test/fleet.test.js'), t('scanner/test/scan-checkpoint.test.js')],
170
+ gap: 'checkpoints resume a single scan; there are no durable leased work units, dependency-hash invalidation or portfolio budgets',
171
+ prd: ['X-704', 'X-705', 'X-706'],
172
+ },
173
+ {
174
+ id: 'attestation-and-evidence-bundles', workstream: 7, title: 'Run attestation, signed per-finding evidence bundles, integrity and retention',
175
+ status: 'partial',
176
+ source: ['scanner/src/posture/attestation.js', 'scanner/src/posture/evidence-bundle.js', 'scanner/src/posture/integrity.js', 'scanner/src/posture/retention-policy.js'],
177
+ entryPoints: [{ path: 'scanner/src/posture/evidence-bundle.js', symbol: 'signEvidenceBundle' }, { path: 'scanner/src/posture/attestation.js', symbol: 'computeRunAttestation' }],
178
+ evidence: [t('scanner/test/attestation.test.js'), t('scanner/test/evidence-bundle.test.js'), t('scanner/test/retention-policy.test.js'), t('scanner/test/verify-attestation-cli.test.js')],
179
+ gap: 'bundles are per finding with a local signer; there is no release assurance manifest, portable package or explicit trust-root policy',
180
+ prd: ['X-701', 'X-702', 'X-703', 'CORE-003'],
181
+ },
182
+ {
183
+ id: 'accuracy-scorecard', workstream: 1, title: 'Published accuracy scorecard and corpus replay',
184
+ status: 'implemented',
185
+ source: ['scanner/src/posture/accuracy-scorecard.js', 'scripts/scorecard.mjs'],
186
+ entryPoints: [],
187
+ evidence: [t('scanner/test/accuracy-scorecard.test.js'), t('scanner/test/scorecard.test.js'), a('docs/scorecard.json')],
188
+ gap: null,
189
+ prd: ['QA-004'],
190
+ },
191
+ {
192
+ id: 'independent-accuracy-current-engine', workstream: 1, title: 'Current-engine accuracy on independent real code',
193
+ status: 'unmeasured',
194
+ source: ['bench/independent/runner.mjs', 'bench/independent/manifest.json'],
195
+ entryPoints: [],
196
+ evidence: [a('docs/scorecard.json'), a('docs/INDEPENDENT_POPULATION_ROOT_CAUSE.md')],
197
+ gap: 'the recorded independent result belongs to an older engine revision; no current-engine adjudicated measurement exists in the checkout',
198
+ prd: ['QA-001', 'QA-002', 'QA-003'],
199
+ },
200
+ {
201
+ id: 'loop-controller', workstream: 'foundation', title: 'Supervised background implementation controller (Haskell/Nix profile)',
202
+ status: 'partial',
203
+ source: ['scripts/loop-engineering/run.mjs', 'scripts/loop-engineering/profiles/haskell-nix.json'],
204
+ entryPoints: [],
205
+ evidence: [t('scripts/loop-engineering/test/loop-manifest.test.js'), t('scripts/loop-engineering/test/loop-watchdog.test.js'), t('scripts/loop-engineering/test/loop-recovery.test.js')],
206
+ gap: 'only the Haskell/Nix profile exists; the assurance-differentiation profile and its protected acceptance suites are not present',
207
+ prd: ['LOOP-001', 'LOOP-002', 'LOOP-003'],
208
+ },
209
+ {
210
+ id: 'lineage-graph', workstream: 3, title: 'Data Flow Explorer lineage graph (DataFlowGraph v1)',
211
+ status: 'implemented',
212
+ source: ['scanner/src/lineage/graph-builder.js', 'scanner/src/lineage/ids.js', 'scanner/src/lineage/schema.js', 'scanner/src/lineage/dataflow-graph.schema.json'],
213
+ entryPoints: [{ path: 'scanner/src/lineage/ids.js', symbol: 'graphId' }],
214
+ evidence: [t('scanner/test/lineage/schema.test.js'), t('scanner/test/lineage/ids.test.js')],
215
+ gap: null,
216
+ prd: ['X-301'],
217
+ },
218
+ ]);