auditor-lambda 0.2.6 → 0.2.9

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 (125) hide show
  1. package/README.md +29 -7
  2. package/audit-code-wrapper-lib.mjs +1605 -330
  3. package/dist/adapters/eslint.js +9 -5
  4. package/dist/cli.d.ts +42 -1
  5. package/dist/cli.js +192 -80
  6. package/dist/coverage.d.ts +2 -2
  7. package/dist/coverage.js +5 -5
  8. package/dist/extractors/bucketing.d.ts +4 -0
  9. package/dist/extractors/bucketing.js +6 -2
  10. package/dist/extractors/disposition.d.ts +4 -0
  11. package/dist/extractors/disposition.js +15 -2
  12. package/dist/extractors/fileInventory.js +24 -28
  13. package/dist/extractors/flows.d.ts +5 -0
  14. package/dist/extractors/flows.js +25 -39
  15. package/dist/extractors/pathPatterns.d.ts +13 -3
  16. package/dist/extractors/pathPatterns.js +116 -53
  17. package/dist/extractors/risk.js +7 -1
  18. package/dist/extractors/surfaces.d.ts +4 -0
  19. package/dist/extractors/surfaces.js +11 -11
  20. package/dist/index.d.ts +1 -1
  21. package/dist/index.js +2 -1
  22. package/dist/io/artifacts.d.ts +59 -44
  23. package/dist/io/artifacts.js +80 -120
  24. package/dist/io/json.d.ts +2 -0
  25. package/dist/io/json.js +65 -19
  26. package/dist/io/runArtifacts.d.ts +2 -1
  27. package/dist/io/runArtifacts.js +44 -7
  28. package/dist/mcp/server.d.ts +1 -0
  29. package/dist/mcp/server.js +579 -0
  30. package/dist/orchestrator/advance.js +84 -56
  31. package/dist/orchestrator/dependencyMap.js +9 -13
  32. package/dist/orchestrator/executors.js +7 -2
  33. package/dist/orchestrator/flowCoverage.js +11 -5
  34. package/dist/orchestrator/flowPlanning.d.ts +7 -2
  35. package/dist/orchestrator/flowPlanning.js +46 -21
  36. package/dist/orchestrator/flowRequeue.js +29 -9
  37. package/dist/orchestrator/internalExecutors.d.ts +2 -1
  38. package/dist/orchestrator/internalExecutors.js +130 -69
  39. package/dist/orchestrator/planning.js +25 -3
  40. package/dist/orchestrator/requeue.js +20 -5
  41. package/dist/orchestrator/resultIngestion.js +5 -6
  42. package/dist/orchestrator/runtimeValidation.d.ts +7 -2
  43. package/dist/orchestrator/runtimeValidation.js +61 -49
  44. package/dist/orchestrator/runtimeValidationUpdate.js +2 -4
  45. package/dist/orchestrator/state.js +18 -13
  46. package/dist/orchestrator/taskBuilder.d.ts +4 -2
  47. package/dist/orchestrator/taskBuilder.js +153 -52
  48. package/dist/orchestrator/trivialAudit.js +8 -5
  49. package/dist/orchestrator/unitBuilder.d.ts +3 -1
  50. package/dist/orchestrator/unitBuilder.js +24 -16
  51. package/dist/prompts/renderWorkerPrompt.d.ts +1 -1
  52. package/dist/prompts/renderWorkerPrompt.js +19 -10
  53. package/dist/providers/claudeCodeProvider.d.ts +4 -1
  54. package/dist/providers/claudeCodeProvider.js +8 -5
  55. package/dist/providers/localSubprocessProvider.d.ts +4 -0
  56. package/dist/providers/localSubprocessProvider.js +7 -2
  57. package/dist/providers/spawnLoggedCommand.d.ts +9 -1
  58. package/dist/providers/spawnLoggedCommand.js +77 -29
  59. package/dist/reporting/mergeFindings.js +0 -11
  60. package/dist/reporting/synthesis.d.ts +26 -21
  61. package/dist/reporting/synthesis.js +97 -61
  62. package/dist/reporting/workBlocks.d.ts +12 -3
  63. package/dist/reporting/workBlocks.js +124 -70
  64. package/dist/supervisor/operatorHandoff.js +48 -18
  65. package/dist/supervisor/runLedger.d.ts +1 -1
  66. package/dist/supervisor/runLedger.js +112 -5
  67. package/dist/supervisor/sessionConfig.js +10 -10
  68. package/dist/types/externalAnalyzer.d.ts +3 -0
  69. package/dist/types/flowCoverage.d.ts +5 -1
  70. package/dist/types/flowCoverage.js +5 -1
  71. package/dist/types/flows.d.ts +6 -0
  72. package/dist/types/flows.js +1 -1
  73. package/dist/types/runLedger.d.ts +5 -1
  74. package/dist/types/runLedger.js +6 -1
  75. package/dist/types/runtimeValidation.d.ts +13 -3
  76. package/dist/types/runtimeValidation.js +16 -1
  77. package/dist/types/sessionConfig.d.ts +15 -2
  78. package/dist/types/sessionConfig.js +15 -1
  79. package/dist/types/surfaces.d.ts +4 -1
  80. package/dist/types/surfaces.js +1 -1
  81. package/dist/types/workerSession.d.ts +9 -0
  82. package/dist/types/workerSession.js +5 -1
  83. package/dist/types.d.ts +4 -7
  84. package/dist/validation/artifacts.d.ts +1 -1
  85. package/dist/validation/artifacts.js +33 -20
  86. package/dist/validation/auditResults.d.ts +2 -2
  87. package/dist/validation/auditResults.js +71 -114
  88. package/dist/validation/basic.d.ts +9 -1
  89. package/dist/validation/basic.js +40 -3
  90. package/dist/validation/sessionConfig.d.ts +4 -2
  91. package/dist/validation/sessionConfig.js +62 -15
  92. package/docs/agent-integrations.md +67 -38
  93. package/docs/artifacts.md +16 -56
  94. package/docs/bootstrap-install.md +60 -30
  95. package/docs/contract.md +22 -205
  96. package/docs/next-steps.md +76 -44
  97. package/docs/packaging.md +27 -3
  98. package/docs/product-direction.md +22 -0
  99. package/docs/production-launch-bar.md +4 -2
  100. package/docs/production-readiness.md +9 -5
  101. package/docs/releasing.md +98 -0
  102. package/docs/remediation-baseline.md +75 -0
  103. package/docs/run-flow.md +23 -11
  104. package/docs/session-config.md +50 -5
  105. package/docs/supervisor.md +7 -0
  106. package/docs/workflow-refactor-brief.md +177 -0
  107. package/package.json +4 -1
  108. package/schemas/audit_result.schema.json +8 -7
  109. package/schemas/audit_task.schema.json +3 -1
  110. package/schemas/coverage_matrix.schema.json +3 -3
  111. package/schemas/critical_flows.schema.json +6 -2
  112. package/schemas/file_disposition.schema.json +2 -2
  113. package/schemas/finding.schema.json +9 -4
  114. package/schemas/flow_coverage.schema.json +2 -2
  115. package/schemas/repo_manifest.schema.json +4 -4
  116. package/schemas/risk_register.schema.json +2 -2
  117. package/schemas/runtime_validation_report.schema.json +3 -3
  118. package/schemas/runtime_validation_tasks.schema.json +8 -2
  119. package/schemas/surface_manifest.schema.json +6 -3
  120. package/schemas/unit_manifest.schema.json +3 -2
  121. package/skills/audit-code/SKILL.md +16 -2
  122. package/skills/audit-code/audit-code.prompt.md +5 -8
  123. package/schemas/merged_findings.schema.json +0 -19
  124. package/schemas/root_cause_clusters.schema.json +0 -28
  125. package/schemas/synthesis_report.schema.json +0 -61
@@ -1,3 +1,4 @@
1
+ import { spawn } from "node:child_process";
1
2
  import { buildFileDisposition } from "../extractors/disposition.js";
2
3
  import { buildGraphBundle } from "../extractors/graph.js";
3
4
  import { buildCriticalFlowManifest } from "../extractors/flows.js";
@@ -5,28 +6,50 @@ import { buildRiskRegister } from "../extractors/risk.js";
5
6
  import { buildSurfaceManifest } from "../extractors/surfaces.js";
6
7
  import { initializeCoverageFromPlan } from "./planning.js";
7
8
  import { buildFlowCoverage } from "./flowCoverage.js";
8
- import { buildFlowAwareTaskAugmentations } from "./flowPlanning.js";
9
9
  import { buildRequeuePayload } from "./requeueCommand.js";
10
- import { buildRuntimeValidationTasks, buildPlaceholderRuntimeValidationReport, mergeRuntimeValidationReport, } from "./runtimeValidation.js";
11
- import { buildSynthesisReport } from "../reporting/synthesis.js";
12
- import { buildChunkedAuditTasks, buildExternalSignalTasks, } from "./taskBuilder.js";
10
+ import { buildRuntimeValidationTasks, discoverRuntimeValidationCommand, mergeRuntimeValidationReport, } from "./runtimeValidation.js";
11
+ import { buildAuditReportModel, renderAuditReportMarkdown, } from "../reporting/synthesis.js";
12
+ import { buildChunkedAuditTasks, } from "./taskBuilder.js";
13
13
  import { buildUnitManifest } from "./unitBuilder.js";
14
14
  import { buildRepoManifestFromFs } from "../extractors/fsIntake.js";
15
15
  import { loadIgnoreFile } from "../extractors/ignore.js";
16
16
  import { ingestAuditResults, updateAuditTaskStatuses, } from "./resultIngestion.js";
17
17
  import { updateRuntimeValidationReport } from "./runtimeValidationUpdate.js";
18
18
  import { autoCompleteTrivialCoverage } from "./trivialAudit.js";
19
- function buildSynthesisArtifacts(synthesisReport) {
20
- return {
21
- synthesis_report: synthesisReport,
22
- merged_findings: { findings: synthesisReport.merged_findings },
23
- root_cause_clusters: { clusters: synthesisReport.root_cause_clusters },
24
- };
25
- }
26
- function preserveOrPlaceholder(tasks, existing) {
27
- return existing
28
- ? mergeRuntimeValidationReport(tasks, existing)
29
- : buildPlaceholderRuntimeValidationReport(tasks);
19
+ async function runCommand(command, cwd) {
20
+ return await new Promise((resolve) => {
21
+ const child = spawn(command[0], command.slice(1), {
22
+ cwd,
23
+ env: process.env,
24
+ stdio: ["ignore", "pipe", "pipe"],
25
+ });
26
+ let stdout = "";
27
+ let stderr = "";
28
+ child.stdout.on("data", (chunk) => {
29
+ stdout += String(chunk);
30
+ });
31
+ child.stderr.on("data", (chunk) => {
32
+ stderr += String(chunk);
33
+ });
34
+ child.on("error", (error) => {
35
+ resolve({
36
+ status: "inconclusive",
37
+ summary: `Failed to execute ${command.join(" ")}: ${error.message}`,
38
+ evidence: [],
39
+ });
40
+ });
41
+ child.on("exit", (code) => {
42
+ const output = `${stdout}\n${stderr}`.trim();
43
+ const evidence = output.length > 0 ? output.split(/\r?\n/).slice(-10) : [];
44
+ resolve({
45
+ status: code === 0 ? "confirmed" : "not_confirmed",
46
+ summary: code === 0
47
+ ? `Deterministic runtime command succeeded: ${command.join(" ")}`
48
+ : `Deterministic runtime command failed with exit code ${code}: ${command.join(" ")}`,
49
+ evidence,
50
+ });
51
+ });
52
+ });
30
53
  }
31
54
  export async function runIntakeExecutor(bundle, root) {
32
55
  const ignore = await loadIgnoreFile(root);
@@ -54,8 +77,8 @@ export function runStructureExecutor(bundle) {
54
77
  const disposition = bundle.file_disposition ?? buildFileDisposition(bundle.repo_manifest);
55
78
  const unitManifest = buildUnitManifest(bundle.repo_manifest, disposition);
56
79
  const surfaceManifest = buildSurfaceManifest(bundle.repo_manifest, disposition);
57
- const criticalFlows = buildCriticalFlowManifest(bundle.repo_manifest, surfaceManifest, disposition);
58
80
  const graphBundle = buildGraphBundle(bundle.repo_manifest, disposition);
81
+ const criticalFlows = buildCriticalFlowManifest(bundle.repo_manifest, surfaceManifest, disposition);
59
82
  const riskRegister = buildRiskRegister(unitManifest, criticalFlows, externalAnalyzerResults);
60
83
  return {
61
84
  updated: {
@@ -75,10 +98,13 @@ export function runStructureExecutor(bundle) {
75
98
  "critical_flows.json",
76
99
  "risk_register.json",
77
100
  ],
78
- progress_summary: `Built structure artifacts for ${unitManifest.units.length} units and ${criticalFlows.flows.length} critical flows.`,
101
+ progress_summary: `Built structure artifacts for ${unitManifest.units.length} units and ${criticalFlows.flows.length} critical flows.` +
102
+ (criticalFlows.fallback_required
103
+ ? " Deterministic flow inference did not fully meet the confidence bar."
104
+ : ""),
79
105
  };
80
106
  }
81
- export function runPlanningExecutor(bundle, lineIndex = {}) {
107
+ export async function runPlanningExecutor(bundle, root, lineIndex = {}) {
82
108
  if (!bundle.repo_manifest) {
83
109
  throw new Error("Cannot run planning executor without repo_manifest");
84
110
  }
@@ -91,16 +117,23 @@ export function runPlanningExecutor(bundle, lineIndex = {}) {
91
117
  }
92
118
  const externalAnalyzerResults = bundle.external_analyzer_results;
93
119
  const coverage = initializeCoverageFromPlan(bundle.repo_manifest, bundle.unit_manifest, bundle.file_disposition, externalAnalyzerResults);
94
- const autoSkippedTrivialFiles = autoCompleteTrivialCoverage(coverage, lineIndex, externalAnalyzerResults);
120
+ const skippedTrivialPaths = autoCompleteTrivialCoverage(coverage, lineIndex, externalAnalyzerResults);
95
121
  const flowCoverage = buildFlowCoverage(bundle.critical_flows, coverage);
96
- const runtimeValidationTasks = buildRuntimeValidationTasks(bundle.unit_manifest, bundle.critical_flows, flowCoverage);
97
- const runtimeValidationReport = preserveOrPlaceholder(runtimeValidationTasks, bundle.runtime_validation_report);
98
- const baseTasks = buildChunkedAuditTasks(bundle.unit_manifest, lineIndex, {
122
+ const runtimeCommand = await discoverRuntimeValidationCommand(root);
123
+ const runtimeValidationTasks = buildRuntimeValidationTasks({
124
+ unitManifest: bundle.unit_manifest,
125
+ criticalFlows: bundle.critical_flows,
126
+ flowCoverage,
127
+ command: runtimeCommand,
128
+ });
129
+ const runtimeValidationReport = runtimeValidationTasks.tasks.length > 0
130
+ ? mergeRuntimeValidationReport(runtimeValidationTasks, bundle.runtime_validation_report)
131
+ : undefined;
132
+ const auditTasks = buildChunkedAuditTasks(coverage, lineIndex, {
99
133
  external_analyzer_results: externalAnalyzerResults,
134
+ critical_flows: bundle.critical_flows,
100
135
  });
101
- const analyzerTasks = buildExternalSignalTasks(coverage, lineIndex, externalAnalyzerResults);
102
- const flowTasks = buildFlowAwareTaskAugmentations([...baseTasks, ...analyzerTasks], bundle.critical_flows, lineIndex);
103
- const auditTasks = [...baseTasks, ...analyzerTasks, ...flowTasks].map((task) => ({
136
+ const taggedAuditTasks = auditTasks.map((task) => ({
104
137
  ...task,
105
138
  status: task.status ?? "pending",
106
139
  }));
@@ -112,24 +145,25 @@ export function runPlanningExecutor(bundle, lineIndex = {}) {
112
145
  flow_coverage: flowCoverage,
113
146
  runtime_validation_tasks: runtimeValidationTasks,
114
147
  runtime_validation_report: runtimeValidationReport,
115
- audit_tasks: auditTasks,
148
+ audit_tasks: taggedAuditTasks,
116
149
  requeue_tasks: requeuePayload.tasks,
150
+ audit_report: undefined,
117
151
  },
118
152
  artifacts_written: [
119
153
  "coverage_matrix.json",
120
154
  "flow_coverage.json",
121
155
  "runtime_validation_tasks.json",
122
- "runtime_validation_report.json",
156
+ ...(runtimeValidationReport ? ["runtime_validation_report.json"] : []),
123
157
  "audit_tasks.json",
124
158
  "requeue_tasks.json",
125
159
  ],
126
- progress_summary: `Built planning artifacts; generated ${auditTasks.length} tasks and ${requeuePayload.task_count} requeue tasks.` +
127
- (autoSkippedTrivialFiles.length > 0
128
- ? ` Auto-completed ${autoSkippedTrivialFiles.length} trivial file${autoSkippedTrivialFiles.length === 1 ? "" : "s"} without dispatch.`
160
+ progress_summary: `Built planning artifacts; generated ${taggedAuditTasks.length} review blocks and ${requeuePayload.task_count} requeue tasks.` +
161
+ (skippedTrivialPaths.length > 0
162
+ ? ` Skipped ${skippedTrivialPaths.length} trivial path${skippedTrivialPaths.length === 1 ? "" : "s"} from semantic review.`
129
163
  : "") +
130
- (externalAnalyzerResults?.results.length
131
- ? ` External analyzer signals influenced lenses and produced ${analyzerTasks.length} dedicated follow-up task(s).`
132
- : ""),
164
+ (runtimeCommand
165
+ ? ` Runtime validation will use: ${runtimeCommand.join(" ")}.`
166
+ : " No deterministic runtime validation command was discovered."),
133
167
  };
134
168
  }
135
169
  export function runResultIngestionExecutor(bundle, results) {
@@ -140,84 +174,110 @@ export function runResultIngestionExecutor(bundle, results) {
140
174
  const flowCoverage = bundle.critical_flows
141
175
  ? buildFlowCoverage(bundle.critical_flows, updatedCoverageMatrix)
142
176
  : bundle.flow_coverage;
143
- const runtimeValidationTasks = bundle.unit_manifest
144
- ? buildRuntimeValidationTasks(bundle.unit_manifest, bundle.critical_flows, flowCoverage)
145
- : bundle.runtime_validation_tasks;
146
- const runtimeValidationReport = runtimeValidationTasks
147
- ? preserveOrPlaceholder(runtimeValidationTasks, bundle.runtime_validation_report)
148
- : bundle.runtime_validation_report;
149
177
  const requeuePayload = buildRequeuePayload(updatedCoverageMatrix, bundle.critical_flows, flowCoverage, bundle.external_analyzer_results);
150
178
  const mergedResults = [...(bundle.audit_results ?? []), ...results];
151
179
  const updatedAuditTasks = updateAuditTaskStatuses(bundle.audit_tasks, mergedResults);
152
- const synthesisReport = buildSynthesisReport(mergedResults, runtimeValidationReport, bundle.external_analyzer_results);
153
- const synthesisArtifacts = buildSynthesisArtifacts(synthesisReport);
154
180
  return {
155
181
  updated: {
156
182
  ...bundle,
157
183
  coverage_matrix: updatedCoverageMatrix,
158
184
  flow_coverage: flowCoverage,
159
- runtime_validation_tasks: runtimeValidationTasks,
160
- runtime_validation_report: runtimeValidationReport,
161
185
  audit_results: mergedResults,
162
186
  audit_tasks: updatedAuditTasks,
163
187
  requeue_tasks: requeuePayload.tasks,
164
- ...synthesisArtifacts,
188
+ audit_report: undefined,
165
189
  },
166
190
  artifacts_written: [
167
191
  "coverage_matrix.json",
168
192
  "flow_coverage.json",
169
- "runtime_validation_tasks.json",
170
- "runtime_validation_report.json",
171
193
  "audit_results.jsonl",
172
194
  "audit_tasks.json",
173
195
  "requeue_tasks.json",
174
- "merged_findings.json",
175
- "root_cause_clusters.json",
176
- "synthesis_report.json",
177
196
  ],
178
197
  progress_summary: `Ingested ${results.length} audit result entries and refreshed dependent artifacts.`,
179
198
  };
180
199
  }
200
+ export async function runRuntimeValidationExecutor(bundle, root) {
201
+ if (!bundle.runtime_validation_tasks) {
202
+ throw new Error("Cannot execute runtime validation without runtime_validation_tasks");
203
+ }
204
+ const existing = bundle.runtime_validation_report ?? { results: [] };
205
+ const byTaskId = new Map(existing.results.map((result) => [result.task_id, result]));
206
+ const byCommand = new Map();
207
+ for (const task of bundle.runtime_validation_tasks.tasks) {
208
+ const prior = byTaskId.get(task.id);
209
+ if (prior &&
210
+ ["confirmed", "not_confirmed", "inconclusive", "not_required"].includes(prior.status)) {
211
+ continue;
212
+ }
213
+ if (!task.command || task.command.length === 0) {
214
+ byTaskId.set(task.id, {
215
+ task_id: task.id,
216
+ status: "not_required",
217
+ summary: `No deterministic runtime command was available for ${task.id}.`,
218
+ evidence: [],
219
+ notes: ["Runtime validation was not planned for this task."],
220
+ });
221
+ continue;
222
+ }
223
+ const signature = task.command.join("\0");
224
+ const outcome = byCommand.get(signature) ?? (await runCommand(task.command, root));
225
+ byCommand.set(signature, outcome);
226
+ byTaskId.set(task.id, {
227
+ task_id: task.id,
228
+ status: outcome.status,
229
+ summary: outcome.summary,
230
+ evidence: outcome.evidence,
231
+ notes: [`Target paths: ${task.target_paths.join(", ")}`],
232
+ });
233
+ }
234
+ return {
235
+ updated: {
236
+ ...bundle,
237
+ runtime_validation_report: {
238
+ results: [...byTaskId.values()].sort((a, b) => a.task_id.localeCompare(b.task_id)),
239
+ },
240
+ audit_report: undefined,
241
+ },
242
+ artifacts_written: ["runtime_validation_report.json"],
243
+ progress_summary: `Executed deterministic runtime validation for ${bundle.runtime_validation_tasks.tasks.length} task(s).`,
244
+ };
245
+ }
181
246
  export function runRuntimeValidationUpdateExecutor(bundle, updates) {
182
247
  if (!bundle.runtime_validation_tasks) {
183
248
  throw new Error("Cannot update runtime validation without runtime_validation_tasks");
184
249
  }
185
- const existingReport = bundle.runtime_validation_report ??
186
- buildPlaceholderRuntimeValidationReport(bundle.runtime_validation_tasks);
250
+ const existingReport = bundle.runtime_validation_report ?? { results: [] };
187
251
  const mergedReport = updateRuntimeValidationReport(bundle.runtime_validation_tasks, existingReport, updates);
188
- const synthesisReport = buildSynthesisReport(bundle.audit_results ?? [], mergedReport, bundle.external_analyzer_results);
189
- const synthesisArtifacts = buildSynthesisArtifacts(synthesisReport);
190
252
  return {
191
253
  updated: {
192
254
  ...bundle,
193
255
  runtime_validation_report: mergedReport,
194
- ...synthesisArtifacts,
256
+ audit_report: undefined,
195
257
  },
196
- artifacts_written: [
197
- "runtime_validation_report.json",
198
- "merged_findings.json",
199
- "root_cause_clusters.json",
200
- "synthesis_report.json",
201
- ],
258
+ artifacts_written: ["runtime_validation_report.json"],
202
259
  progress_summary: `Merged ${updates.results.length} runtime validation updates.`,
203
260
  };
204
261
  }
205
262
  export function runSynthesisExecutor(bundle, results) {
206
263
  const finalResults = results ?? bundle.audit_results ?? [];
207
- const synthesisReport = buildSynthesisReport(finalResults, bundle.runtime_validation_report, bundle.external_analyzer_results);
208
- const synthesisArtifacts = buildSynthesisArtifacts(synthesisReport);
264
+ const model = buildAuditReportModel({
265
+ results: finalResults,
266
+ unitManifest: bundle.unit_manifest,
267
+ graphBundle: bundle.graph_bundle,
268
+ criticalFlows: bundle.critical_flows,
269
+ coverageMatrix: bundle.coverage_matrix,
270
+ runtimeValidationReport: bundle.runtime_validation_report,
271
+ externalAnalyzerResults: bundle.external_analyzer_results,
272
+ });
209
273
  return {
210
274
  updated: {
211
275
  ...bundle,
212
276
  audit_results: finalResults,
213
- ...synthesisArtifacts,
277
+ audit_report: renderAuditReportMarkdown(model),
214
278
  },
215
- artifacts_written: [
216
- "merged_findings.json",
217
- "root_cause_clusters.json",
218
- "synthesis_report.json",
219
- ],
220
- progress_summary: `Refreshed synthesis for ${finalResults.length} audit result entries.`,
279
+ artifacts_written: ["audit-report.md"],
280
+ progress_summary: `Rendered deterministic audit report for ${finalResults.length} audit result entries.`,
221
281
  };
222
282
  }
223
283
  export function runExternalAnalyzerImportExecutor(bundle, externalResults) {
@@ -226,6 +286,7 @@ export function runExternalAnalyzerImportExecutor(bundle, externalResults) {
226
286
  updated: {
227
287
  ...bundle,
228
288
  external_analyzer_results: externalResults,
289
+ audit_report: undefined,
229
290
  },
230
291
  artifacts_written: ["external_analyzer_results.json"],
231
292
  progress_summary: summary,
@@ -1,5 +1,6 @@
1
1
  import { applyUnitCoverage, createCoverageMatrix, markExcludedPath, } from "../coverage.js";
2
2
  import { isAuditExcludedStatus } from "../extractors/disposition.js";
3
+ import { deriveRequiredLensesForPath } from "./unitBuilder.js";
3
4
  const CATEGORY_LENS_TABLE = [
4
5
  [["security", "secret"], ["security", "correctness"]],
5
6
  [["dependency", "vuln"], ["security", "config_deployment"]],
@@ -21,8 +22,17 @@ function applyAnalyzerCoverage(coverage, externalAnalyzerResults) {
21
22
  if (!externalAnalyzerResults) {
22
23
  return;
23
24
  }
24
- for (const result of externalAnalyzerResults.results) {
25
- const record = coverage.files.find((file) => file.path === result.path);
25
+ const coverageByPath = new Map(coverage.files.map((file) => [file.path, file]));
26
+ const results = Array.isArray(externalAnalyzerResults.results)
27
+ ? externalAnalyzerResults.results
28
+ : [];
29
+ for (const result of results) {
30
+ if (!result ||
31
+ typeof result.path !== "string" ||
32
+ typeof result.category !== "string") {
33
+ continue;
34
+ }
35
+ const record = coverageByPath.get(result.path);
26
36
  if (!record || record.audit_status === "excluded") {
27
37
  continue;
28
38
  }
@@ -44,9 +54,21 @@ export function initializeCoverageFromPlan(repoManifest, unitManifest, dispositi
44
54
  markExcludedPath(coverage, file.path, status);
45
55
  }
46
56
  }
57
+ const unitIdsByPath = new Map();
47
58
  for (const unit of unitManifest.units) {
48
59
  for (const path of unit.files) {
49
- applyUnitCoverage(coverage, path, unit.unit_id, unit.required_lenses);
60
+ const existing = unitIdsByPath.get(path) ?? [];
61
+ if (!existing.includes(unit.unit_id)) {
62
+ existing.push(unit.unit_id);
63
+ }
64
+ unitIdsByPath.set(path, existing);
65
+ }
66
+ }
67
+ for (const file of repoManifest.files) {
68
+ const unitIds = unitIdsByPath.get(file.path) ?? [];
69
+ const requiredLenses = deriveRequiredLensesForPath(file.path);
70
+ for (const unitId of unitIds) {
71
+ applyUnitCoverage(coverage, file.path, unitId, requiredLenses);
50
72
  }
51
73
  }
52
74
  applyAnalyzerCoverage(coverage, externalAnalyzerResults);
@@ -1,11 +1,26 @@
1
1
  import { buildRequeueTargets } from "../coverage.js";
2
- function taskPriority(hasExternalSignal) {
3
- return hasExternalSignal ? "high" : "medium";
2
+ function taskPriority(hasExternalSignal, lens) {
3
+ if (hasExternalSignal)
4
+ return "high";
5
+ if (lens === "security" || lens === "data_integrity" || lens === "reliability") {
6
+ return "medium";
7
+ }
8
+ return "low";
9
+ }
10
+ function getExternalSignalPaths(externalAnalyzerResults) {
11
+ const results = Array.isArray(externalAnalyzerResults?.results)
12
+ ? externalAnalyzerResults.results
13
+ : [];
14
+ return new Set(results
15
+ .map((item) => item && typeof item.path === "string" && item.path.length > 0
16
+ ? item.path
17
+ : null)
18
+ .filter((path) => path !== null));
4
19
  }
5
20
  export function buildRequeueTasks(matrix, externalAnalyzerResults) {
6
21
  const targets = buildRequeueTargets(matrix);
7
22
  const tasks = [];
8
- const externalPaths = new Set((externalAnalyzerResults?.results ?? []).map((item) => item.path));
23
+ const externalPaths = getExternalSignalPaths(externalAnalyzerResults);
9
24
  for (const target of targets) {
10
25
  for (const lens of target.missing_lenses) {
11
26
  const hasExternalSignal = externalPaths.has(target.path);
@@ -15,8 +30,8 @@ export function buildRequeueTasks(matrix, externalAnalyzerResults) {
15
30
  pass_id: `requeue:${lens}`,
16
31
  lens,
17
32
  file_paths: [target.path],
18
- rationale: `Requeue ${target.path} because the ${lens} lens is still missing.${hasExternalSignal ? " External analyzer signals make this follow-up higher priority." : ""}`,
19
- priority: taskPriority(hasExternalSignal),
33
+ rationale: `Mandatory audit coverage is still missing for ${target.path} under the ${lens} lens.`,
34
+ priority: taskPriority(hasExternalSignal, lens),
20
35
  tags: hasExternalSignal ? ["external_analyzer_signal"] : [],
21
36
  status: "pending",
22
37
  });
@@ -1,15 +1,14 @@
1
- import { applyReviewedRanges } from "../coverage.js";
1
+ import { applyFileCoverage } from "../coverage.js";
2
2
  export function ingestAuditResults(coverageMatrix, results) {
3
3
  const matrix = JSON.parse(JSON.stringify(coverageMatrix));
4
- const reviewedRanges = results.flatMap((result) => result.reviewed_ranges.map((range) => ({
5
- path: range.path,
6
- start: range.start,
7
- end: range.end,
4
+ const fileCoverage = results.flatMap((result) => result.file_coverage.map((coverage) => ({
5
+ path: coverage.path,
6
+ total_lines: coverage.total_lines,
8
7
  pass_id: result.pass_id,
9
8
  lens: result.lens,
10
9
  agent_role: result.agent_role,
11
10
  })));
12
- applyReviewedRanges(matrix, reviewedRanges);
11
+ applyFileCoverage(matrix, fileCoverage);
13
12
  return matrix;
14
13
  }
15
14
  export function updateAuditTaskStatuses(tasks, results) {
@@ -2,6 +2,11 @@ import type { UnitManifest } from "../types.js";
2
2
  import type { FlowCoverageManifest } from "../types/flowCoverage.js";
3
3
  import type { CriticalFlowManifest } from "../types/flows.js";
4
4
  import type { RuntimeValidationReport, RuntimeValidationTaskManifest } from "../types/runtimeValidation.js";
5
- export declare function buildRuntimeValidationTasks(unitManifest: UnitManifest, criticalFlows?: CriticalFlowManifest, flowCoverage?: FlowCoverageManifest): RuntimeValidationTaskManifest;
6
- export declare function buildPlaceholderRuntimeValidationReport(tasks: RuntimeValidationTaskManifest): RuntimeValidationReport;
5
+ export declare function discoverRuntimeValidationCommand(root: string): Promise<string[] | undefined>;
6
+ export declare function buildRuntimeValidationTasks(params: {
7
+ unitManifest: UnitManifest;
8
+ criticalFlows?: CriticalFlowManifest;
9
+ flowCoverage?: FlowCoverageManifest;
10
+ command?: string[];
11
+ }): RuntimeValidationTaskManifest;
7
12
  export declare function mergeRuntimeValidationReport(tasks: RuntimeValidationTaskManifest, existing?: RuntimeValidationReport): RuntimeValidationReport;
@@ -1,23 +1,59 @@
1
+ import { access, readFile } from "node:fs/promises";
1
2
  function checksForFlow(requiredLenses) {
2
3
  const checks = [];
3
4
  if (requiredLenses.includes("security")) {
4
5
  checks.push("Exercise malformed or unauthorized inputs against the flow.");
5
6
  }
6
7
  if (requiredLenses.includes("reliability")) {
7
- checks.push("Exercise retries, repeated submissions, or partial failure behavior.");
8
+ checks.push("Exercise retries or repeated submissions.");
8
9
  }
9
10
  if (requiredLenses.includes("correctness")) {
10
- checks.push("Exercise representative success and edge-case paths end to end.");
11
+ checks.push("Exercise representative success and edge-case behavior.");
11
12
  }
12
13
  if (requiredLenses.includes("data_integrity")) {
13
- checks.push("Verify state transitions and persistence invariants after execution.");
14
+ checks.push("Verify state transitions and persistence invariants.");
14
15
  }
15
16
  return checks;
16
17
  }
17
- export function buildRuntimeValidationTasks(unitManifest, criticalFlows, flowCoverage) {
18
+ async function exists(path) {
19
+ try {
20
+ await access(path);
21
+ return true;
22
+ }
23
+ catch {
24
+ return false;
25
+ }
26
+ }
27
+ export async function discoverRuntimeValidationCommand(root) {
28
+ const packageJsonPath = `${root}/package.json`;
29
+ if (await exists(packageJsonPath)) {
30
+ try {
31
+ const packageJson = JSON.parse(await readFile(packageJsonPath, "utf8"));
32
+ const testScript = packageJson.scripts?.test?.trim();
33
+ if (testScript &&
34
+ !/no test specified/i.test(testScript)) {
35
+ return ["npm", "test"];
36
+ }
37
+ }
38
+ catch {
39
+ // ignore unreadable package.json for runtime discovery
40
+ }
41
+ }
42
+ if (await exists(`${root}/go.mod`)) {
43
+ return ["go", "test", "./..."];
44
+ }
45
+ if (await exists(`${root}/pyproject.toml`) || await exists(`${root}/pytest.ini`)) {
46
+ return ["python", "-m", "pytest"];
47
+ }
48
+ return undefined;
49
+ }
50
+ export function buildRuntimeValidationTasks(params) {
51
+ if (!params.command) {
52
+ return { tasks: [] };
53
+ }
18
54
  const tasks = [];
19
55
  const seen = new Set();
20
- const highRiskUnits = unitManifest.units.filter((unit) => (unit.risk_score ?? 0) >= 5 ||
56
+ const highRiskUnits = params.unitManifest.units.filter((unit) => (unit.risk_score ?? 0) >= 5 ||
21
57
  unit.required_lenses.includes("security") ||
22
58
  unit.required_lenses.includes("data_integrity"));
23
59
  for (const unit of highRiskUnits) {
@@ -31,16 +67,17 @@ export function buildRuntimeValidationTasks(unitManifest, criticalFlows, flowCov
31
67
  target_paths: unit.files,
32
68
  reason: `Unit ${unit.unit_id} is high risk or touches sensitive concerns.`,
33
69
  priority: (unit.risk_score ?? 0) >= 7 ? "high" : "medium",
70
+ command: params.command,
34
71
  suggested_checks: [
35
- "Run representative happy-path execution.",
36
- "Run malformed-input or failure-path execution where feasible.",
72
+ "Run the deterministic runtime command for the repository.",
73
+ "Confirm the affected unit does not regress under the command output.",
37
74
  ],
38
75
  source_artifacts: ["unit_manifest.json", "risk_register.json"],
39
76
  });
40
77
  }
41
- if (criticalFlows && flowCoverage) {
42
- const flowMap = new Map(criticalFlows.flows.map((flow) => [flow.id, flow]));
43
- for (const record of flowCoverage.flows) {
78
+ if (params.criticalFlows && params.flowCoverage) {
79
+ const flowMap = new Map(params.criticalFlows.flows.map((flow) => [flow.id, flow]));
80
+ for (const record of params.flowCoverage.flows) {
44
81
  if (record.status === "complete") {
45
82
  continue;
46
83
  }
@@ -56,53 +93,28 @@ export function buildRuntimeValidationTasks(unitManifest, criticalFlows, flowCov
56
93
  id,
57
94
  kind: "critical-flow-check",
58
95
  target_paths: flow.paths,
59
- reason: `Critical flow ${record.flow_id} is still ${record.status} and should receive runtime validation.`,
96
+ reason: `Critical flow ${record.flow_id} is still ${record.status} and needs deterministic runtime validation.`,
60
97
  priority: record.status === "pending" ? "high" : "medium",
98
+ command: params.command,
61
99
  suggested_checks: checksForFlow(record.required_lenses),
62
100
  source_artifacts: ["critical_flows.json", "flow_coverage.json"],
63
101
  });
64
102
  }
65
103
  }
66
- const RUNTIME_TASK_CAP = 100;
67
- if (tasks.length > RUNTIME_TASK_CAP) {
68
- process.stderr.write(`[runtime-validation] generated ${tasks.length} tasks which exceeds the cap of ${RUNTIME_TASK_CAP}; truncating to avoid runaway expansion\n`);
69
- tasks.splice(RUNTIME_TASK_CAP);
70
- }
71
104
  return { tasks };
72
105
  }
73
- export function buildPlaceholderRuntimeValidationReport(tasks) {
74
- return {
75
- results: tasks.tasks.map((task) => ({
76
- task_id: task.id,
77
- status: "pending",
78
- summary: `No runtime evidence recorded yet for ${task.id}.`,
79
- evidence: [],
80
- notes: ["Placeholder entry generated from runtime validation task list."],
81
- })),
82
- };
83
- }
84
106
  export function mergeRuntimeValidationReport(tasks, existing) {
85
107
  const existingMap = new Map((existing?.results ?? []).map((result) => [result.task_id, result]));
86
- const mergedResults = tasks.tasks.map((task) => {
87
- const prior = existingMap.get(task.id);
88
- if (prior) {
89
- return {
90
- ...prior,
91
- notes: [
92
- ...new Set([
93
- ...(prior.notes ?? []),
94
- "Preserved across runtime validation refresh.",
95
- ]),
96
- ],
97
- };
98
- }
99
- return {
100
- task_id: task.id,
101
- status: "pending",
102
- summary: `No runtime evidence recorded yet for ${task.id}.`,
103
- evidence: [],
104
- notes: ["Placeholder entry generated from runtime validation task list."],
105
- };
106
- });
107
- return { results: mergedResults };
108
+ return {
109
+ results: tasks.tasks.map((task) => {
110
+ const prior = existingMap.get(task.id);
111
+ return (prior ?? {
112
+ task_id: task.id,
113
+ status: "pending",
114
+ summary: `Deterministic runtime validation has not executed yet for ${task.id}.`,
115
+ evidence: [],
116
+ notes: [],
117
+ });
118
+ }),
119
+ };
108
120
  }
@@ -38,11 +38,9 @@ export function updateRuntimeValidationReport(tasks, existing, updates) {
38
38
  merged.set(task.id, {
39
39
  task_id: task.id,
40
40
  status: "pending",
41
- summary: `No runtime evidence recorded yet for ${task.id}.`,
41
+ summary: `Deterministic runtime validation has not executed yet for ${task.id}.`,
42
42
  evidence: [],
43
- notes: [
44
- "Placeholder entry generated from runtime validation task list.",
45
- ],
43
+ notes: [],
46
44
  });
47
45
  }
48
46
  }