auditor-lambda 0.7.0 → 0.9.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 (125) hide show
  1. package/README.md +0 -21
  2. package/audit-code-wrapper-lib.mjs +149 -129
  3. package/dist/adapters/normalizeExternal.js +6 -3
  4. package/dist/cli/args.d.ts +0 -1
  5. package/dist/cli/args.js +0 -6
  6. package/dist/cli/auditStep.js +7 -1
  7. package/dist/cli/dispatch.js +3 -2
  8. package/dist/cli/lineIndex.js +4 -1
  9. package/dist/cli/mergeAndIngestCommand.d.ts +1 -0
  10. package/dist/cli/mergeAndIngestCommand.js +219 -0
  11. package/dist/cli/nextStepCommand.js +5 -1
  12. package/dist/cli/runToCompletion.d.ts +9 -0
  13. package/dist/cli/runToCompletion.js +655 -480
  14. package/dist/cli/statusCommand.d.ts +1 -0
  15. package/dist/cli/statusCommand.js +113 -0
  16. package/dist/cli/submitPacketCommand.d.ts +1 -0
  17. package/dist/cli/submitPacketCommand.js +155 -0
  18. package/dist/cli/workerResult.d.ts +1 -1
  19. package/dist/cli/workerRunCommand.d.ts +1 -0
  20. package/dist/cli/workerRunCommand.js +88 -0
  21. package/dist/cli.d.ts +0 -1
  22. package/dist/cli.js +14 -565
  23. package/dist/extractors/analyzers/sql.js +4 -1
  24. package/dist/extractors/analyzers/treeSitter.js +29 -15
  25. package/dist/extractors/analyzers/typescript.js +10 -8
  26. package/dist/extractors/designAssessment.js +43 -24
  27. package/dist/extractors/graph.js +151 -75
  28. package/dist/extractors/pathPatterns.js +17 -5
  29. package/dist/io/artifacts.d.ts +3 -1
  30. package/dist/io/artifacts.js +18 -2
  31. package/dist/io/runArtifactTypes.d.ts +18 -0
  32. package/dist/io/runArtifactTypes.js +1 -0
  33. package/dist/io/runArtifacts.d.ts +2 -18
  34. package/dist/io/runArtifacts.js +14 -3
  35. package/dist/mcp/server.js +9 -0
  36. package/dist/orchestrator/advance.js +38 -22
  37. package/dist/orchestrator/artifactFreshness.js +14 -4
  38. package/dist/orchestrator/autoFixExecutor.d.ts +2 -2
  39. package/dist/orchestrator/autoFixExecutor.js +26 -8
  40. package/dist/orchestrator/dependencyMap.d.ts +1 -1
  41. package/dist/orchestrator/dependencyMap.js +7 -1
  42. package/dist/orchestrator/executorResult.d.ts +12 -0
  43. package/dist/orchestrator/executorResult.js +1 -0
  44. package/dist/orchestrator/fileAnchors.js +14 -3
  45. package/dist/orchestrator/fileIntegrity.d.ts +1 -0
  46. package/dist/orchestrator/fileIntegrity.js +12 -3
  47. package/dist/orchestrator/flowCoverage.js +1 -0
  48. package/dist/orchestrator/flowRequeue.js +4 -1
  49. package/dist/orchestrator/graphEnrichmentExecutor.d.ts +1 -1
  50. package/dist/orchestrator/graphEnrichmentExecutor.js +3 -1
  51. package/dist/orchestrator/ingestionExecutors.d.ts +11 -0
  52. package/dist/orchestrator/ingestionExecutors.js +237 -0
  53. package/dist/orchestrator/intakeExecutors.d.ts +3 -0
  54. package/dist/orchestrator/intakeExecutors.js +25 -0
  55. package/dist/orchestrator/planningExecutors.d.ts +4 -0
  56. package/dist/orchestrator/planningExecutors.js +95 -0
  57. package/dist/orchestrator/reviewPacketGraph.d.ts +31 -0
  58. package/dist/orchestrator/reviewPacketGraph.js +691 -0
  59. package/dist/orchestrator/reviewPackets.d.ts +2 -15
  60. package/dist/orchestrator/reviewPackets.js +3 -685
  61. package/dist/orchestrator/runtimeCommand.d.ts +11 -0
  62. package/dist/orchestrator/runtimeCommand.js +71 -0
  63. package/dist/orchestrator/scope.js +1 -1
  64. package/dist/orchestrator/selectiveDeepening/conflict.d.ts +8 -0
  65. package/dist/orchestrator/selectiveDeepening/conflict.js +71 -0
  66. package/dist/orchestrator/selectiveDeepening/findingFollowup.d.ts +10 -0
  67. package/dist/orchestrator/selectiveDeepening/findingFollowup.js +52 -0
  68. package/dist/orchestrator/selectiveDeepening/highRiskClean.d.ts +7 -0
  69. package/dist/orchestrator/selectiveDeepening/highRiskClean.js +44 -0
  70. package/dist/orchestrator/selectiveDeepening/index.d.ts +18 -0
  71. package/dist/orchestrator/selectiveDeepening/index.js +128 -0
  72. package/dist/orchestrator/selectiveDeepening/lensVerification.d.ts +12 -0
  73. package/dist/orchestrator/selectiveDeepening/lensVerification.js +242 -0
  74. package/dist/orchestrator/selectiveDeepening/runtimeValidation.d.ts +13 -0
  75. package/dist/orchestrator/selectiveDeepening/runtimeValidation.js +57 -0
  76. package/dist/orchestrator/selectiveDeepening/shared.d.ts +45 -0
  77. package/dist/orchestrator/selectiveDeepening/shared.js +128 -0
  78. package/dist/orchestrator/selectiveDeepening/stewardFollowup.d.ts +6 -0
  79. package/dist/orchestrator/selectiveDeepening/stewardFollowup.js +72 -0
  80. package/dist/orchestrator/selectiveDeepening.d.ts +2 -20
  81. package/dist/orchestrator/selectiveDeepening.js +6 -760
  82. package/dist/orchestrator/staleness.js +3 -3
  83. package/dist/orchestrator/structureExecutors.d.ts +5 -0
  84. package/dist/orchestrator/structureExecutors.js +94 -0
  85. package/dist/orchestrator/syntaxResolutionExecutor.d.ts +1 -1
  86. package/dist/orchestrator/synthesisExecutors.d.ts +12 -0
  87. package/dist/orchestrator/synthesisExecutors.js +90 -0
  88. package/dist/orchestrator/taskBuilder.d.ts +2 -2
  89. package/dist/orchestrator/taskBuilder.js +101 -82
  90. package/dist/providers/index.d.ts +7 -0
  91. package/dist/providers/index.js +14 -95
  92. package/dist/quota/discoveredLimits.d.ts +1 -0
  93. package/dist/quota/discoveredLimits.js +7 -1
  94. package/dist/quota/index.d.ts +0 -2
  95. package/dist/quota/index.js +1 -2
  96. package/dist/reporting/workBlocks.js +7 -4
  97. package/dist/types/reviewPlanning.d.ts +23 -16
  98. package/dist/validation/auditResults.js +97 -95
  99. package/dist/validation/sessionConfig.d.ts +2 -2
  100. package/dist/validation/sessionConfig.js +14 -7
  101. package/docs/development.md +35 -139
  102. package/docs/history.md +26 -0
  103. package/docs/product.md +41 -108
  104. package/package.json +3 -2
  105. package/schemas/audit_findings.schema.json +6 -5
  106. package/schemas/critical_flows.schema.json +3 -2
  107. package/schemas/dispatch_quota.schema.json +3 -1
  108. package/schemas/external_analyzer_results.schema.json +2 -2
  109. package/schemas/graph_bundle.schema.json +1 -1
  110. package/schemas/repo_manifest.schema.json +1 -1
  111. package/schemas/review_packets.schema.json +1 -1
  112. package/schemas/step_contract.schema.json +80 -0
  113. package/scripts/postinstall.mjs +19 -2
  114. package/skills/audit-code/opencode-command-template.txt +3 -3
  115. package/dist/orchestrator/internalExecutors.d.ts +0 -34
  116. package/dist/orchestrator/internalExecutors.js +0 -581
  117. package/dist/providers/localSubprocessProvider.d.ts +0 -9
  118. package/dist/providers/localSubprocessProvider.js +0 -18
  119. package/dist/providers/subprocessTemplateProvider.d.ts +0 -8
  120. package/dist/providers/subprocessTemplateProvider.js +0 -59
  121. package/dist/providers/vscodeTaskProvider.d.ts +0 -7
  122. package/dist/providers/vscodeTaskProvider.js +0 -14
  123. package/dist/quota/probe.d.ts +0 -10
  124. package/dist/quota/probe.js +0 -18
  125. package/docs/handoff.md +0 -204
@@ -1,581 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import { buildFileDisposition, isAuditExcludedStatus, } from "../extractors/disposition.js";
3
- import { buildGraphBundle, buildGraphBundleFromFs, } from "../extractors/graph.js";
4
- import { buildCriticalFlowManifest } from "../extractors/flows.js";
5
- import { buildRiskRegister } from "../extractors/risk.js";
6
- import { buildSurfaceManifest } from "../extractors/surfaces.js";
7
- import { initializeCoverageFromPlan } from "./planning.js";
8
- import { applyScopeToCoverage, fullAuditScope } from "./scope.js";
9
- import { buildFlowCoverage } from "./flowCoverage.js";
10
- import { buildRequeuePayload } from "./requeueCommand.js";
11
- import { buildRuntimeValidationTasks, discoverRuntimeValidationCommand, mergeRuntimeValidationReport, } from "./runtimeValidation.js";
12
- import { applyNarrative, buildAuditFindingsReport, buildAuditReportModel, renderAuditReportMarkdown, } from "../reporting/synthesis.js";
13
- import { buildChunkedAuditTasks, } from "./taskBuilder.js";
14
- import { buildAuditPlanMetrics, buildReviewPackets, sizeIndexFromManifest, } from "./reviewPackets.js";
15
- import { buildUnitManifest } from "./unitBuilder.js";
16
- import { buildRepoManifestFromFs } from "../extractors/fsIntake.js";
17
- import { loadIgnoreFile } from "../extractors/ignore.js";
18
- import { ingestAuditResults, updateAuditTaskStatuses, } from "./resultIngestion.js";
19
- import { buildDesignAssessment } from "../extractors/designAssessment.js";
20
- import { buildSelectiveDeepeningTasks } from "./selectiveDeepening.js";
21
- import { updateRuntimeValidationReport } from "./runtimeValidationUpdate.js";
22
- import { autoCompleteTrivialCoverage } from "./trivialAudit.js";
23
- function lineIndexFromTasks(tasks) {
24
- return Object.fromEntries((tasks ?? []).flatMap((task) => Object.entries(task.file_line_counts ?? {})));
25
- }
26
- function appendSelectiveDeepeningTasks(params) {
27
- if (!params.bundle.audit_tasks) {
28
- return { bundle: params.bundle, taskCount: 0, artifacts: [] };
29
- }
30
- const lineIndex = lineIndexFromTasks(params.bundle.audit_tasks);
31
- const sizeIndex = sizeIndexFromManifest(params.bundle.repo_manifest);
32
- const selectiveDeepeningTasks = buildSelectiveDeepeningTasks({
33
- existingTasks: params.bundle.audit_tasks,
34
- results: params.results,
35
- lineIndex,
36
- runtimeValidationTasks: params.bundle.runtime_validation_tasks,
37
- runtimeValidationReport: params.runtimeValidationReport ?? params.bundle.runtime_validation_report,
38
- externalAnalyzerResults: params.bundle.external_analyzer_results,
39
- });
40
- if (selectiveDeepeningTasks.length === 0) {
41
- return { bundle: params.bundle, taskCount: 0, artifacts: [] };
42
- }
43
- const auditTasks = [...params.bundle.audit_tasks, ...selectiveDeepeningTasks];
44
- return {
45
- bundle: {
46
- ...params.bundle,
47
- audit_tasks: auditTasks,
48
- audit_plan_metrics: buildAuditPlanMetrics(auditTasks, {
49
- graphBundle: params.bundle.graph_bundle,
50
- lineIndex,
51
- sizeIndex,
52
- }),
53
- review_packets: buildReviewPackets(auditTasks, {
54
- graphBundle: params.bundle.graph_bundle,
55
- lineIndex,
56
- sizeIndex,
57
- }),
58
- },
59
- taskCount: selectiveDeepeningTasks.length,
60
- artifacts: ["audit_tasks.json", "audit_plan_metrics.json", "review_packets.json"],
61
- };
62
- }
63
- function resolveOpentokenWrap(resolved, platform = process.platform) {
64
- if (platform === "win32") {
65
- const shell = process.env.ComSpec ?? "cmd.exe";
66
- const inner = [resolved.command, ...resolved.args]
67
- .map((v) => (/^[A-Za-z0-9_./:=@+-]+$/.test(v) ? v : `"${v.replace(/(["^&|<>%])/g, "^$1")}"`))
68
- .join(" ");
69
- return { command: shell, args: ["/d", "/s", "/c", `opentoken wrap ${inner}`] };
70
- }
71
- return { command: "opentoken", args: ["wrap", resolved.command, ...resolved.args] };
72
- }
73
- async function runCommand(command, cwd, options = {}) {
74
- let spawnCommand = resolveRuntimeValidationSpawnCommand(command);
75
- if (options.opentoken) {
76
- spawnCommand = resolveOpentokenWrap(spawnCommand);
77
- }
78
- const displayCommand = command.join(" ");
79
- return await new Promise((resolve) => {
80
- const child = spawn(spawnCommand.command, spawnCommand.args, {
81
- cwd,
82
- env: process.env,
83
- stdio: ["ignore", "pipe", "pipe"],
84
- });
85
- let stdout = "";
86
- let stderr = "";
87
- child.stdout.on("data", (chunk) => {
88
- stdout += String(chunk);
89
- });
90
- child.stderr.on("data", (chunk) => {
91
- stderr += String(chunk);
92
- });
93
- child.on("error", (error) => {
94
- resolve({
95
- status: "inconclusive",
96
- summary: `Failed to execute ${displayCommand}: ${error.message}`,
97
- evidence: [],
98
- });
99
- });
100
- child.on("exit", (code) => {
101
- const output = `${stdout}\n${stderr}`.trim();
102
- const evidence = output.length > 0 ? output.split(/\r?\n/).slice(-10) : [];
103
- resolve({
104
- status: code === 0 ? "confirmed" : "not_confirmed",
105
- summary: code === 0
106
- ? `Deterministic runtime command succeeded: ${displayCommand}`
107
- : `Deterministic runtime command failed with exit code ${code}: ${displayCommand}`,
108
- evidence,
109
- });
110
- });
111
- });
112
- }
113
- export function resolveRuntimeValidationSpawnCommand(command, platform = process.platform, shellCommand = process.env.ComSpec ?? "cmd.exe") {
114
- const [executable, ...args] = command;
115
- if (!executable) {
116
- return { command: "", args: [] };
117
- }
118
- if (platform !== "win32") {
119
- return { command: executable, args };
120
- }
121
- const packageManager = executable.replace(/\.(cmd|bat)$/i, "").toLowerCase();
122
- if (["npm", "npx", "pnpm", "yarn"].includes(packageManager)) {
123
- return {
124
- command: shellCommand,
125
- args: ["/d", "/s", "/c", command.map(quoteCmdArg).join(" ")],
126
- };
127
- }
128
- return { command: executable, args };
129
- }
130
- function quoteCmdArg(value) {
131
- if (/^[A-Za-z0-9_./:=+-]+$/.test(value)) {
132
- return value;
133
- }
134
- return `"${value.replace(/(["^&|<>%])/g, "^$1")}"`;
135
- }
136
- export async function runIntakeExecutor(bundle, root) {
137
- const ignore = await loadIgnoreFile(root);
138
- const repoManifest = await buildRepoManifestFromFs({
139
- root,
140
- ignore,
141
- hash_files: true,
142
- });
143
- const disposition = buildFileDisposition(repoManifest);
144
- const auditableCount = disposition.files.filter((file) => !isAuditExcludedStatus(file.status)).length;
145
- if (auditableCount === 0) {
146
- throw new Error(`No auditable files found in ${root}. The repository may be empty, generated-only, documentation-only, or filtered by .auditorignore.`);
147
- }
148
- return {
149
- updated: {
150
- ...bundle,
151
- repo_manifest: repoManifest,
152
- file_disposition: disposition,
153
- },
154
- artifacts_written: ["repo_manifest.json", "file_disposition.json"],
155
- progress_summary: `Created intake artifacts for ${repoManifest.files.length} files.`,
156
- };
157
- }
158
- export async function runStructureExecutor(bundle, root) {
159
- if (!bundle.repo_manifest) {
160
- throw new Error("Cannot run structure executor without repo_manifest");
161
- }
162
- const externalAnalyzerResults = bundle.external_analyzer_results;
163
- const disposition = bundle.file_disposition ?? buildFileDisposition(bundle.repo_manifest);
164
- const unitManifest = buildUnitManifest(bundle.repo_manifest, disposition);
165
- const graphBundle = root
166
- ? await buildGraphBundleFromFs(bundle.repo_manifest, root, disposition, {
167
- externalAnalyzerResults,
168
- })
169
- : buildGraphBundle(bundle.repo_manifest, disposition, {
170
- externalAnalyzerResults,
171
- });
172
- const surfaceManifest = buildSurfaceManifest(bundle.repo_manifest, disposition, { graphBundle });
173
- const criticalFlows = buildCriticalFlowManifest(bundle.repo_manifest, surfaceManifest, disposition);
174
- const riskRegister = buildRiskRegister(unitManifest, criticalFlows, externalAnalyzerResults);
175
- return {
176
- updated: {
177
- ...bundle,
178
- file_disposition: disposition,
179
- unit_manifest: unitManifest,
180
- surface_manifest: surfaceManifest,
181
- graph_bundle: graphBundle,
182
- critical_flows: criticalFlows,
183
- risk_register: riskRegister,
184
- },
185
- artifacts_written: [
186
- "file_disposition.json",
187
- "unit_manifest.json",
188
- "surface_manifest.json",
189
- "graph_bundle.json",
190
- "critical_flows.json",
191
- "risk_register.json",
192
- ],
193
- progress_summary: `Built structure artifacts for ${unitManifest.units.length} units and ${criticalFlows.flows.length} critical flows.` +
194
- (criticalFlows.fallback_required
195
- ? " Deterministic flow inference did not fully meet the confidence bar."
196
- : ""),
197
- };
198
- }
199
- export function runDesignAssessmentExecutor(bundle) {
200
- if (!bundle.unit_manifest ||
201
- !bundle.graph_bundle ||
202
- !bundle.critical_flows ||
203
- !bundle.risk_register) {
204
- throw new Error("Cannot run design assessment executor without structure artifacts");
205
- }
206
- const designAssessment = buildDesignAssessment({
207
- unitManifest: bundle.unit_manifest,
208
- graphBundle: bundle.graph_bundle,
209
- criticalFlows: bundle.critical_flows,
210
- riskRegister: bundle.risk_register,
211
- });
212
- const previous = bundle.design_assessment;
213
- if (previous?.reviewed) {
214
- designAssessment.reviewed = true;
215
- designAssessment.review_findings = previous.review_findings ?? [];
216
- }
217
- return {
218
- updated: {
219
- ...bundle,
220
- design_assessment: designAssessment,
221
- },
222
- artifacts_written: ["design_assessment.json"],
223
- progress_summary: `Design assessment complete: ${designAssessment.findings.length} structural finding(s).`,
224
- };
225
- }
226
- export function runDesignReviewAutoComplete(bundle) {
227
- const existing = bundle.design_assessment;
228
- if (!existing) {
229
- throw new Error("Cannot auto-complete design review without design_assessment artifact");
230
- }
231
- const updated = {
232
- ...existing,
233
- reviewed: true,
234
- review_findings: existing.review_findings ?? [],
235
- };
236
- return {
237
- updated: {
238
- ...bundle,
239
- design_assessment: updated,
240
- },
241
- artifacts_written: ["design_assessment.json"],
242
- progress_summary: "Design review auto-completed (host-agent review available via next-step).",
243
- };
244
- }
245
- export async function runPlanningExecutor(bundle, root, lineIndex = {}, sizeIndex, scope) {
246
- if (!bundle.repo_manifest) {
247
- throw new Error("Cannot run planning executor without repo_manifest");
248
- }
249
- const resolvedSizeIndex = sizeIndex ?? sizeIndexFromManifest(bundle.repo_manifest);
250
- if (!bundle.file_disposition ||
251
- !bundle.unit_manifest ||
252
- !bundle.surface_manifest ||
253
- !bundle.critical_flows ||
254
- !bundle.risk_register) {
255
- throw new Error("Cannot run planning executor without current structure artifacts");
256
- }
257
- const resolvedScope = scope ?? fullAuditScope();
258
- const externalAnalyzerResults = bundle.external_analyzer_results;
259
- const coverage = initializeCoverageFromPlan(bundle.repo_manifest, bundle.unit_manifest, bundle.file_disposition, externalAnalyzerResults);
260
- const skippedTrivialPaths = autoCompleteTrivialCoverage(coverage, lineIndex, externalAnalyzerResults);
261
- // Delta scope: only seed + expanded files stay pending; the rest inherit prior
262
- // completion or are excluded from this run. Full scope is a no-op.
263
- applyScopeToCoverage(coverage, resolvedScope, bundle.coverage_matrix);
264
- const flowCoverage = buildFlowCoverage(bundle.critical_flows, coverage);
265
- const runtimeCommand = await discoverRuntimeValidationCommand(root);
266
- const runtimeValidationTasks = buildRuntimeValidationTasks({
267
- unitManifest: bundle.unit_manifest,
268
- criticalFlows: bundle.critical_flows,
269
- flowCoverage,
270
- command: runtimeCommand,
271
- });
272
- const runtimeValidationReport = runtimeValidationTasks.tasks.length > 0
273
- ? mergeRuntimeValidationReport(runtimeValidationTasks, bundle.runtime_validation_report)
274
- : undefined;
275
- const auditTasks = buildChunkedAuditTasks(coverage, lineIndex, {
276
- external_analyzer_results: externalAnalyzerResults,
277
- critical_flows: bundle.critical_flows,
278
- });
279
- const taggedAuditTasks = auditTasks.map((task) => ({
280
- ...task,
281
- status: task.status ?? "pending",
282
- }));
283
- const reviewPackets = buildReviewPackets(taggedAuditTasks, {
284
- graphBundle: bundle.graph_bundle,
285
- lineIndex,
286
- sizeIndex: resolvedSizeIndex,
287
- });
288
- const auditPlanMetrics = buildAuditPlanMetrics(taggedAuditTasks, {
289
- graphBundle: bundle.graph_bundle,
290
- lineIndex,
291
- sizeIndex: resolvedSizeIndex,
292
- });
293
- const requeuePayload = buildRequeuePayload(coverage, bundle.critical_flows, flowCoverage, externalAnalyzerResults);
294
- const scopeSummary = resolvedScope.mode === "delta"
295
- ? ` Delta scope since ${resolvedScope.since}: ${resolvedScope.seed_files.length} changed file(s) + ${resolvedScope.expanded_files.length} graph neighbour(s) queued; a full audit is advised before release.`
296
- : "";
297
- return {
298
- updated: {
299
- ...bundle,
300
- scope: resolvedScope,
301
- coverage_matrix: coverage,
302
- flow_coverage: flowCoverage,
303
- runtime_validation_tasks: runtimeValidationTasks,
304
- runtime_validation_report: runtimeValidationReport,
305
- audit_tasks: taggedAuditTasks,
306
- audit_plan_metrics: auditPlanMetrics,
307
- review_packets: reviewPackets,
308
- requeue_tasks: requeuePayload.tasks,
309
- audit_report: undefined,
310
- },
311
- artifacts_written: [
312
- "scope.json",
313
- "coverage_matrix.json",
314
- "flow_coverage.json",
315
- "runtime_validation_tasks.json",
316
- ...(runtimeValidationReport ? ["runtime_validation_report.json"] : []),
317
- "audit_tasks.json",
318
- "audit_plan_metrics.json",
319
- "review_packets.json",
320
- "requeue_tasks.json",
321
- ],
322
- progress_summary: `Built planning artifacts; generated ${taggedAuditTasks.length} review tasks in ${reviewPackets.length} packet(s) and ${requeuePayload.task_count} requeue tasks.` +
323
- scopeSummary +
324
- (skippedTrivialPaths.length > 0
325
- ? ` Skipped ${skippedTrivialPaths.length} trivial path${skippedTrivialPaths.length === 1 ? "" : "s"} from semantic review.`
326
- : "") +
327
- (runtimeCommand
328
- ? ` Runtime validation will use: ${runtimeCommand.join(" ")}.`
329
- : " No deterministic runtime validation command was discovered."),
330
- };
331
- }
332
- export function runResultIngestionExecutor(bundle, results) {
333
- if (!bundle.coverage_matrix) {
334
- throw new Error("Cannot ingest results without coverage_matrix");
335
- }
336
- const updatedCoverageMatrix = ingestAuditResults(bundle.coverage_matrix, results);
337
- const flowCoverage = bundle.critical_flows
338
- ? buildFlowCoverage(bundle.critical_flows, updatedCoverageMatrix)
339
- : bundle.flow_coverage;
340
- const runtimeCommand = bundle.runtime_validation_tasks?.tasks.find((task) => task.command && task.command.length > 0)?.command;
341
- const runtimeValidationTasks = bundle.unit_manifest && flowCoverage
342
- ? buildRuntimeValidationTasks({
343
- unitManifest: bundle.unit_manifest,
344
- criticalFlows: bundle.critical_flows,
345
- flowCoverage,
346
- command: runtimeCommand,
347
- })
348
- : bundle.runtime_validation_tasks;
349
- const runtimeValidationReport = runtimeValidationTasks
350
- ? mergeRuntimeValidationReport(runtimeValidationTasks, bundle.runtime_validation_report)
351
- : bundle.runtime_validation_report;
352
- const mergedResults = [...(bundle.audit_results ?? []), ...results];
353
- const completedAuditTasks = updateAuditTaskStatuses(bundle.audit_tasks, mergedResults);
354
- const baseUpdatedBundle = {
355
- ...bundle,
356
- coverage_matrix: updatedCoverageMatrix,
357
- flow_coverage: flowCoverage,
358
- runtime_validation_tasks: runtimeValidationTasks,
359
- runtime_validation_report: runtimeValidationReport,
360
- audit_results: mergedResults,
361
- audit_tasks: completedAuditTasks,
362
- audit_report: undefined,
363
- };
364
- const selectiveDeepening = appendSelectiveDeepeningTasks({
365
- bundle: baseUpdatedBundle,
366
- results: mergedResults,
367
- runtimeValidationReport,
368
- });
369
- const requeuePayload = buildRequeuePayload(updatedCoverageMatrix, selectiveDeepening.bundle.critical_flows, selectiveDeepening.bundle.flow_coverage, selectiveDeepening.bundle.external_analyzer_results);
370
- const finalBundle = {
371
- ...selectiveDeepening.bundle,
372
- requeue_tasks: requeuePayload.tasks,
373
- };
374
- return {
375
- updated: finalBundle,
376
- artifacts_written: [
377
- "coverage_matrix.json",
378
- "flow_coverage.json",
379
- ...(runtimeValidationTasks ? ["runtime_validation_tasks.json"] : []),
380
- ...(runtimeValidationReport ? ["runtime_validation_report.json"] : []),
381
- "audit_results.jsonl",
382
- "audit_tasks.json",
383
- ...selectiveDeepening.artifacts.filter((artifact) => artifact !== "audit_tasks.json"),
384
- "requeue_tasks.json",
385
- ],
386
- progress_summary: `Ingested ${results.length} audit result entries and refreshed dependent artifacts.` +
387
- (selectiveDeepening.taskCount > 0
388
- ? ` Added ${selectiveDeepening.taskCount} selective deepening task(s).`
389
- : ""),
390
- };
391
- }
392
- export async function runRuntimeValidationExecutor(bundle, root, options = {}) {
393
- if (!bundle.runtime_validation_tasks) {
394
- throw new Error("Cannot execute runtime validation without runtime_validation_tasks");
395
- }
396
- const existing = bundle.runtime_validation_report ?? { results: [] };
397
- const byTaskId = new Map(existing.results.map((result) => [result.task_id, result]));
398
- const byCommand = new Map();
399
- for (const task of bundle.runtime_validation_tasks.tasks) {
400
- const prior = byTaskId.get(task.id);
401
- if (prior &&
402
- ["confirmed", "not_confirmed", "inconclusive", "not_required"].includes(prior.status)) {
403
- continue;
404
- }
405
- if (!task.command || task.command.length === 0) {
406
- byTaskId.set(task.id, {
407
- task_id: task.id,
408
- status: "not_required",
409
- summary: `No deterministic runtime command was available for ${task.id}.`,
410
- evidence: [],
411
- notes: ["Runtime validation was not planned for this task."],
412
- });
413
- continue;
414
- }
415
- const signature = task.command.join("\0");
416
- const outcome = byCommand.get(signature) ?? (await runCommand(task.command, root, { opentoken: options.opentoken }));
417
- byCommand.set(signature, outcome);
418
- byTaskId.set(task.id, {
419
- task_id: task.id,
420
- status: outcome.status,
421
- summary: outcome.summary,
422
- evidence: outcome.evidence,
423
- notes: [`Target paths: ${task.target_paths.join(", ")}`],
424
- });
425
- }
426
- const runtimeValidationReport = {
427
- results: [...byTaskId.values()].sort((a, b) => a.task_id.localeCompare(b.task_id)),
428
- };
429
- const baseUpdatedBundle = {
430
- ...bundle,
431
- runtime_validation_report: runtimeValidationReport,
432
- audit_report: undefined,
433
- };
434
- const selectiveDeepening = appendSelectiveDeepeningTasks({
435
- bundle: baseUpdatedBundle,
436
- results: bundle.audit_results ?? [],
437
- runtimeValidationReport,
438
- });
439
- return {
440
- updated: selectiveDeepening.bundle,
441
- artifacts_written: [
442
- "runtime_validation_report.json",
443
- ...selectiveDeepening.artifacts,
444
- ],
445
- progress_summary: `Executed deterministic runtime validation for ${bundle.runtime_validation_tasks.tasks.length} task(s).` +
446
- (selectiveDeepening.taskCount > 0
447
- ? ` Added ${selectiveDeepening.taskCount} selective deepening task(s).`
448
- : ""),
449
- };
450
- }
451
- export function runRuntimeValidationUpdateExecutor(bundle, updates) {
452
- if (!bundle.runtime_validation_tasks) {
453
- throw new Error("Cannot update runtime validation without runtime_validation_tasks");
454
- }
455
- const existingReport = bundle.runtime_validation_report ?? { results: [] };
456
- const mergedReport = updateRuntimeValidationReport(bundle.runtime_validation_tasks, existingReport, updates);
457
- const baseUpdatedBundle = {
458
- ...bundle,
459
- runtime_validation_report: mergedReport,
460
- audit_report: undefined,
461
- };
462
- const selectiveDeepening = appendSelectiveDeepeningTasks({
463
- bundle: baseUpdatedBundle,
464
- results: bundle.audit_results ?? [],
465
- runtimeValidationReport: mergedReport,
466
- });
467
- return {
468
- updated: selectiveDeepening.bundle,
469
- artifacts_written: [
470
- "runtime_validation_report.json",
471
- ...selectiveDeepening.artifacts,
472
- ],
473
- progress_summary: `Merged ${updates.results.length} runtime validation updates.` +
474
- (selectiveDeepening.taskCount > 0
475
- ? ` Added ${selectiveDeepening.taskCount} selective deepening task(s).`
476
- : ""),
477
- };
478
- }
479
- function buildBaseFindingsReport(bundle, results) {
480
- return buildAuditFindingsReport(buildAuditReportModel({
481
- results,
482
- unitManifest: bundle.unit_manifest,
483
- graphBundle: bundle.graph_bundle,
484
- criticalFlows: bundle.critical_flows,
485
- coverageMatrix: bundle.coverage_matrix,
486
- runtimeValidationReport: bundle.runtime_validation_report,
487
- externalAnalyzerResults: bundle.external_analyzer_results,
488
- designAssessment: bundle.design_assessment,
489
- }));
490
- }
491
- export function runSynthesisExecutor(bundle, results) {
492
- const finalResults = results ?? bundle.audit_results ?? [];
493
- // Emit the canonical machine contract and render the human report from it.
494
- // No narrative yet — that is layered by the synthesis-narrative obligation.
495
- const findings = buildBaseFindingsReport(bundle, finalResults);
496
- return {
497
- updated: {
498
- ...bundle,
499
- audit_results: finalResults,
500
- audit_findings: findings,
501
- audit_report: renderAuditReportMarkdown(findings, { scope: bundle.scope }),
502
- },
503
- artifacts_written: ["audit-findings.json", "audit-report.md"],
504
- progress_summary: `Rendered deterministic audit report and canonical findings for ${finalResults.length} audit result entries.`,
505
- };
506
- }
507
- /**
508
- * Resolve the optional synthesis-narrative obligation. When a host/provider
509
- * narrative is supplied it is merged into the canonical findings report and the
510
- * human report is re-rendered with themes/executive-summary/top-risks; without
511
- * one the narrative is recorded as omitted and the deterministic report stands.
512
- */
513
- export function runSynthesisNarrativeExecutor(bundle, narrative) {
514
- const baseReport = bundle.audit_findings ??
515
- buildBaseFindingsReport(bundle, bundle.audit_results ?? []);
516
- const needsBaseWrite = !bundle.audit_findings;
517
- const hasNarrative = Boolean(narrative &&
518
- ((narrative.themes?.length ?? 0) > 0 ||
519
- (narrative.executive_summary?.trim().length ?? 0) > 0 ||
520
- (narrative.top_risks?.length ?? 0) > 0));
521
- if (!hasNarrative) {
522
- const record = {
523
- status: "omitted",
524
- theme_count: 0,
525
- executive_summary_present: false,
526
- top_risk_count: 0,
527
- };
528
- return {
529
- updated: {
530
- ...bundle,
531
- audit_findings: baseReport,
532
- synthesis_narrative: record,
533
- },
534
- artifacts_written: needsBaseWrite
535
- ? ["audit-findings.json", "synthesis-narrative.json"]
536
- : ["synthesis-narrative.json"],
537
- progress_summary: "Synthesis narrative omitted; deterministic findings report retained.",
538
- };
539
- }
540
- const enriched = applyNarrative(baseReport, narrative);
541
- const record = {
542
- status: "applied",
543
- theme_count: enriched.themes?.length ?? 0,
544
- executive_summary_present: (enriched.executive_summary?.trim().length ?? 0) > 0,
545
- top_risk_count: enriched.top_risks?.length ?? 0,
546
- };
547
- return {
548
- updated: {
549
- ...bundle,
550
- audit_findings: enriched,
551
- audit_report: renderAuditReportMarkdown(enriched, { scope: bundle.scope }),
552
- synthesis_narrative: record,
553
- },
554
- artifacts_written: [
555
- "audit-findings.json",
556
- "audit-report.md",
557
- "synthesis-narrative.json",
558
- ],
559
- progress_summary: `Synthesis narrative applied: ${record.theme_count} theme(s), ${record.top_risk_count} top risk(s).`,
560
- };
561
- }
562
- export function runExternalAnalyzerImportExecutor(bundle, externalResults) {
563
- const summary = `Imported ${externalResults.results.length} normalized findings from ${externalResults.tool}.`;
564
- return {
565
- updated: {
566
- ...bundle,
567
- external_analyzer_results: externalResults,
568
- coverage_matrix: undefined,
569
- flow_coverage: undefined,
570
- runtime_validation_tasks: undefined,
571
- runtime_validation_report: undefined,
572
- audit_tasks: undefined,
573
- audit_plan_metrics: undefined,
574
- review_packets: undefined,
575
- requeue_tasks: undefined,
576
- audit_report: undefined,
577
- },
578
- artifacts_written: ["external_analyzer_results.json"],
579
- progress_summary: summary,
580
- };
581
- }
@@ -1,9 +0,0 @@
1
- import type { FreshSessionProvider, LaunchFreshSessionInput } from "@audit-tools/shared";
2
- import { spawnLoggedCommand } from "@audit-tools/shared";
3
- export declare const MISSING_WORKER_COMMAND_MESSAGE = "local-subprocess provider requires task.worker_command.";
4
- export declare class LocalSubprocessProvider implements FreshSessionProvider {
5
- name: string;
6
- private readonly launchCommand;
7
- constructor(launchCommand?: typeof spawnLoggedCommand);
8
- launch(input: LaunchFreshSessionInput): Promise<import("@audit-tools/shared").LaunchFreshSessionResult>;
9
- }
@@ -1,18 +0,0 @@
1
- import { readJsonFile } from "@audit-tools/shared";
2
- import { spawnLoggedCommand, applyWorkerTaskLaunchSettings } from "@audit-tools/shared";
3
- export const MISSING_WORKER_COMMAND_MESSAGE = "local-subprocess provider requires task.worker_command.";
4
- export class LocalSubprocessProvider {
5
- name = "local-subprocess";
6
- launchCommand;
7
- constructor(launchCommand = spawnLoggedCommand) {
8
- this.launchCommand = launchCommand;
9
- }
10
- async launch(input) {
11
- const task = await readJsonFile(input.taskPath);
12
- if (!task.worker_command?.length) {
13
- throw new Error(MISSING_WORKER_COMMAND_MESSAGE);
14
- }
15
- const [command, ...args] = task.worker_command;
16
- return await this.launchCommand(command, args, applyWorkerTaskLaunchSettings(input, task));
17
- }
18
- }
@@ -1,8 +0,0 @@
1
- import type { FreshSessionProvider, LaunchFreshSessionInput, SubprocessTemplateConfig, OpenTokenConfig } from "@audit-tools/shared";
2
- export declare class SubprocessTemplateProvider implements FreshSessionProvider {
3
- name: string;
4
- private readonly config;
5
- private readonly opentoken;
6
- constructor(config: SubprocessTemplateConfig, name?: string, opentoken?: OpenTokenConfig);
7
- launch(input: LaunchFreshSessionInput): Promise<import("@audit-tools/shared").LaunchFreshSessionResult>;
8
- }
@@ -1,59 +0,0 @@
1
- import { readJsonFile } from "@audit-tools/shared";
2
- import { spawnLoggedCommand, shellQuote, applyWorkerTaskLaunchSettings, } from "@audit-tools/shared";
3
- function applyTemplate(template, input, task, context) {
4
- const workerCommandShell = task.worker_command
5
- .map((arg) => shellQuote(arg))
6
- .join(" ");
7
- const workerCommandJson = JSON.stringify(task.worker_command);
8
- const values = {
9
- repoRoot: input.repoRoot,
10
- runId: input.runId,
11
- obligationId: input.obligationId ?? "",
12
- promptPath: input.promptPath,
13
- taskPath: input.taskPath,
14
- resultPath: input.resultPath,
15
- stdoutPath: input.stdoutPath,
16
- stderrPath: input.stderrPath,
17
- workerCommandShell,
18
- workerCommandJson,
19
- uiMode: input.uiMode,
20
- timeoutMs: String(input.timeoutMs),
21
- };
22
- const wholePlaceholder = template.match(/^\{([A-Za-z0-9_]+)\}$/);
23
- return template.replace(/\{([A-Za-z0-9_]+)\}/g, (match, key) => {
24
- if (!(key in values)) {
25
- console.warn(`applyTemplate: unknown placeholder ${match} ` +
26
- `provider=${context.providerName} runId=${input.runId} ` +
27
- `obligationId=${input.obligationId ?? ""} taskPath=${input.taskPath} ` +
28
- `entryIndex=${context.entryIndex}`);
29
- }
30
- const value = values[key] ?? "";
31
- return wholePlaceholder || key.endsWith("Shell") ? value : shellQuote(value);
32
- });
33
- }
34
- export class SubprocessTemplateProvider {
35
- name;
36
- config;
37
- opentoken;
38
- constructor(config, name = "subprocess-template", opentoken = {}) {
39
- this.config = config;
40
- this.name = name;
41
- this.opentoken = opentoken;
42
- }
43
- async launch(input) {
44
- const task = await readJsonFile(input.taskPath);
45
- if (!this.config.command_template.length) {
46
- throw new Error(`${this.name} provider requires a non-empty command_template.`);
47
- }
48
- const launchInput = applyWorkerTaskLaunchSettings(input, task);
49
- const rendered = this.config.command_template.map((entry, entryIndex) => applyTemplate(entry, launchInput, task, {
50
- providerName: this.name,
51
- entryIndex,
52
- }));
53
- const [command, ...args] = rendered;
54
- return await spawnLoggedCommand(command, args, launchInput, this.config.env, {
55
- opentoken: this.opentoken.enabled,
56
- opentokenCommand: this.opentoken.command,
57
- });
58
- }
59
- }