auditor-lambda 0.3.3 → 0.3.5

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 (47) hide show
  1. package/README.md +6 -1
  2. package/audit-code-wrapper-lib.mjs +87 -7
  3. package/dist/cli.js +517 -91
  4. package/dist/extractors/graph.d.ts +5 -1
  5. package/dist/extractors/graph.js +223 -3
  6. package/dist/extractors/pathPatterns.d.ts +3 -2
  7. package/dist/extractors/pathPatterns.js +97 -24
  8. package/dist/io/artifacts.d.ts +5 -0
  9. package/dist/io/artifacts.js +2 -0
  10. package/dist/orchestrator/advance.js +1 -1
  11. package/dist/orchestrator/dependencyMap.js +18 -0
  12. package/dist/orchestrator/fileAnchors.d.ts +32 -0
  13. package/dist/orchestrator/fileAnchors.js +217 -0
  14. package/dist/orchestrator/internalExecutors.d.ts +1 -1
  15. package/dist/orchestrator/internalExecutors.js +120 -33
  16. package/dist/orchestrator/reviewPackets.d.ts +14 -0
  17. package/dist/orchestrator/reviewPackets.js +310 -0
  18. package/dist/orchestrator/selectiveDeepening.d.ts +14 -0
  19. package/dist/orchestrator/selectiveDeepening.js +392 -0
  20. package/dist/orchestrator/state.js +6 -1
  21. package/dist/orchestrator/taskBuilder.d.ts +16 -0
  22. package/dist/orchestrator/taskBuilder.js +68 -11
  23. package/dist/prompts/renderWorkerPrompt.js +2 -1
  24. package/dist/providers/claudeCodeProvider.js +3 -1
  25. package/dist/providers/index.js +2 -1
  26. package/dist/supervisor/operatorHandoff.js +22 -11
  27. package/dist/types/graph.d.ts +1 -0
  28. package/dist/types/reviewPlanning.d.ts +41 -0
  29. package/dist/types/reviewPlanning.js +1 -0
  30. package/dist/types/sessionConfig.d.ts +1 -0
  31. package/dist/validation/artifacts.js +13 -0
  32. package/dist/validation/auditResults.js +50 -2
  33. package/dist/validation/sessionConfig.js +5 -0
  34. package/docs/agent-integrations.md +4 -1
  35. package/docs/bootstrap-install.md +3 -0
  36. package/docs/contract.md +3 -0
  37. package/docs/dispatch-implementation-plan.md +220 -489
  38. package/docs/next-steps.md +13 -8
  39. package/docs/product-direction.md +5 -3
  40. package/docs/run-flow.md +25 -30
  41. package/docs/session-config.md +15 -4
  42. package/docs/supervisor.md +5 -3
  43. package/docs/workflow-refactor-brief.md +114 -176
  44. package/package.json +1 -1
  45. package/schemas/finding.schema.json +1 -15
  46. package/schemas/graph_bundle.schema.json +16 -0
  47. package/skills/audit-code/audit-code.prompt.md +11 -6
@@ -0,0 +1,217 @@
1
+ const MAX_ANCHORS = 160;
2
+ const KEYWORD_PATTERN = /\b(auth|token|password|secret|permission|role|sql|query|exec|spawn|eval|deserialize|encrypt|decrypt|cache|retry|timeout|transaction|lock|race|TODO|FIXME)\b/i;
3
+ const SYMBOL_PATTERNS = [
4
+ {
5
+ kind: "import",
6
+ pattern: /^\s*import\s+(?:type\s+)?(?:[^"'()]*?\s+from\s+)?["']([^"']+)["']/,
7
+ label: "import",
8
+ },
9
+ {
10
+ kind: "symbol",
11
+ pattern: /^\s*(?:export\s+)?(?:async\s+)?function\s+([A-Za-z_$][\w$]*)\b/,
12
+ label: "function",
13
+ },
14
+ {
15
+ kind: "symbol",
16
+ pattern: /^\s*(?:export\s+)?class\s+([A-Za-z_$][\w$]*)\b/,
17
+ label: "class",
18
+ },
19
+ {
20
+ kind: "symbol",
21
+ pattern: /^\s*(?:export\s+)?interface\s+([A-Za-z_$][\w$]*)\b/,
22
+ label: "interface",
23
+ },
24
+ {
25
+ kind: "symbol",
26
+ pattern: /^\s*(?:export\s+)?type\s+([A-Za-z_$][\w$]*)\b/,
27
+ label: "type",
28
+ },
29
+ {
30
+ kind: "symbol",
31
+ pattern: /^\s*(?:export\s+)?(?:const|let|var)\s+([A-Za-z_$][\w$]*)\b/,
32
+ label: "binding",
33
+ },
34
+ {
35
+ kind: "export",
36
+ pattern: /^\s*export\s+(?:type\s+)?(?:[^"'()]*?\s+from\s+["']([^"']+)["']|(?:default\s+)?(?:async\s+)?(?:function|class|const|let|var|interface|type)\s+([A-Za-z_$][\w$-]*))/,
37
+ label: "export",
38
+ },
39
+ {
40
+ kind: "symbol",
41
+ pattern: /^\s*(?:export\s+)?def\s+([A-Za-z_][\w]*)\b/,
42
+ label: "function",
43
+ },
44
+ {
45
+ kind: "symbol",
46
+ pattern: /^\s*(?:export\s+)?func\s+(?:\([^)]+\)\s*)?([A-Za-z_][\w]*)\b/,
47
+ label: "function",
48
+ },
49
+ {
50
+ kind: "symbol",
51
+ pattern: /^\s*(?:pub\s+)?fn\s+([A-Za-z_][\w]*)\b/,
52
+ label: "function",
53
+ },
54
+ {
55
+ kind: "route",
56
+ pattern: /\b(?:app|router|server)\s*\.\s*(get|post|put|patch|delete|use)\s*\(/i,
57
+ label: "route",
58
+ },
59
+ {
60
+ kind: "route",
61
+ pattern: /^\s*@(?:Get|Post|Put|Patch|Delete|Route|Controller)\b/,
62
+ label: "route",
63
+ },
64
+ ];
65
+ function normalizePath(path) {
66
+ return path.replace(/\\/g, "/").replace(/^\.\//, "");
67
+ }
68
+ function truncate(value, maxLength) {
69
+ const normalized = value.replace(/\s+/g, " ").trim();
70
+ return normalized.length > maxLength
71
+ ? `${normalized.slice(0, maxLength - 3)}...`
72
+ : normalized;
73
+ }
74
+ function addAnchor(anchors, seen, anchor) {
75
+ const key = `${anchor.kind}\0${anchor.line ?? ""}\0${anchor.name}\0${anchor.detail ?? ""}`;
76
+ if (seen.has(key)) {
77
+ return;
78
+ }
79
+ seen.add(key);
80
+ anchors.push(anchor);
81
+ }
82
+ function collectGraphEdges(graphBundle, path) {
83
+ if (!graphBundle?.graphs) {
84
+ return [];
85
+ }
86
+ const normalizedPath = normalizePath(path).toLowerCase();
87
+ const edges = [];
88
+ for (const key of ["imports", "calls", "references"]) {
89
+ const raw = graphBundle.graphs[key];
90
+ if (!Array.isArray(raw)) {
91
+ continue;
92
+ }
93
+ for (const item of raw) {
94
+ const record = item;
95
+ if (item &&
96
+ typeof item === "object" &&
97
+ !Array.isArray(item) &&
98
+ typeof record.from === "string" &&
99
+ typeof record.to === "string") {
100
+ const from = normalizePath(record.from).toLowerCase();
101
+ const to = normalizePath(record.to).toLowerCase();
102
+ if (from === normalizedPath || to === normalizedPath) {
103
+ edges.push({
104
+ from: record.from,
105
+ to: record.to,
106
+ kind: typeof record.kind === "string" ? record.kind : key,
107
+ });
108
+ }
109
+ }
110
+ }
111
+ }
112
+ return edges.sort((a, b) => (a.kind ?? "").localeCompare(b.kind ?? "") ||
113
+ a.from.localeCompare(b.from) ||
114
+ a.to.localeCompare(b.to));
115
+ }
116
+ export function buildFileAnchorSummary(params) {
117
+ const anchors = [];
118
+ const seen = new Set();
119
+ const path = normalizePath(params.path);
120
+ const lines = params.content.split(/\r?\n/);
121
+ let symbolCount = 0;
122
+ let routeCount = 0;
123
+ let keywordCount = 0;
124
+ addAnchor(anchors, seen, {
125
+ kind: "boundary",
126
+ name: "file_start",
127
+ line: 1,
128
+ detail: "Start of isolated large-file review boundary.",
129
+ });
130
+ if (params.totalLines > 1) {
131
+ addAnchor(anchors, seen, {
132
+ kind: "boundary",
133
+ name: "file_end",
134
+ line: params.totalLines,
135
+ detail: "End of isolated large-file review boundary.",
136
+ });
137
+ }
138
+ lines.forEach((line, index) => {
139
+ const lineNumber = index + 1;
140
+ for (const { kind, pattern, label } of SYMBOL_PATTERNS) {
141
+ const match = line.match(pattern);
142
+ if (!match) {
143
+ continue;
144
+ }
145
+ const name = match.slice(1).find((value) => value && value.trim().length > 0) ?? label;
146
+ if (kind === "route") {
147
+ routeCount += 1;
148
+ }
149
+ else if (kind === "symbol") {
150
+ symbolCount += 1;
151
+ }
152
+ addAnchor(anchors, seen, {
153
+ kind,
154
+ name: truncate(name, 80),
155
+ line: lineNumber,
156
+ detail: truncate(`${label}: ${line}`, 180),
157
+ });
158
+ break;
159
+ }
160
+ if (KEYWORD_PATTERN.test(line)) {
161
+ keywordCount += 1;
162
+ addAnchor(anchors, seen, {
163
+ kind: "keyword",
164
+ name: truncate(line.match(KEYWORD_PATTERN)?.[1] ?? "keyword", 80),
165
+ line: lineNumber,
166
+ detail: truncate(line, 180),
167
+ });
168
+ }
169
+ });
170
+ const graphEdges = collectGraphEdges(params.graphBundle, path);
171
+ for (const edge of graphEdges) {
172
+ addAnchor(anchors, seen, {
173
+ kind: "graph",
174
+ name: edge.kind ?? "edge",
175
+ detail: normalizePath(edge.from).toLowerCase() === path.toLowerCase()
176
+ ? `outbound: ${edge.to}`
177
+ : `inbound: ${edge.from}`,
178
+ });
179
+ }
180
+ const analyzerSignals = (params.externalAnalyzerResults?.results ?? [])
181
+ .filter((result) => normalizePath(result.path).toLowerCase() === path.toLowerCase())
182
+ .sort((a, b) => (a.line_start ?? 0) - (b.line_start ?? 0) ||
183
+ a.id.localeCompare(b.id));
184
+ for (const signal of analyzerSignals) {
185
+ addAnchor(anchors, seen, {
186
+ kind: "analyzer_signal",
187
+ name: truncate(signal.rule ?? signal.category, 80),
188
+ line: signal.line_start,
189
+ detail: truncate(signal.summary, 180),
190
+ });
191
+ }
192
+ const sorted = anchors.sort((a, b) => (a.line ?? Number.MAX_SAFE_INTEGER) - (b.line ?? Number.MAX_SAFE_INTEGER) ||
193
+ a.kind.localeCompare(b.kind) ||
194
+ a.name.localeCompare(b.name));
195
+ const boundedAnchors = sorted.slice(0, MAX_ANCHORS);
196
+ return {
197
+ contract_version: "audit-code-file-anchors/v1alpha1",
198
+ path,
199
+ total_lines: params.totalLines,
200
+ review_mode: "isolated_large_file",
201
+ scope_basis: [
202
+ "single assigned file",
203
+ "single review packet",
204
+ "mechanically extracted symbols, routes, graph edges, keywords, and analyzer signals",
205
+ "backend-owned submit-packet result write path",
206
+ ],
207
+ anchors: boundedAnchors,
208
+ omitted_anchor_count: Math.max(0, sorted.length - boundedAnchors.length),
209
+ counts: {
210
+ symbols: symbolCount,
211
+ routes: routeCount,
212
+ keywords: keywordCount,
213
+ graph_edges: graphEdges.length,
214
+ analyzer_signals: analyzerSignals.length,
215
+ },
216
+ };
217
+ }
@@ -8,7 +8,7 @@ export interface ExecutorRunResult {
8
8
  progress_summary: string;
9
9
  }
10
10
  export declare function runIntakeExecutor(bundle: ArtifactBundle, root: string): Promise<ExecutorRunResult>;
11
- export declare function runStructureExecutor(bundle: ArtifactBundle): ExecutorRunResult;
11
+ export declare function runStructureExecutor(bundle: ArtifactBundle, root?: string): Promise<ExecutorRunResult>;
12
12
  export declare function runPlanningExecutor(bundle: ArtifactBundle, root: string, lineIndex?: Record<string, number>): Promise<ExecutorRunResult>;
13
13
  export declare function runResultIngestionExecutor(bundle: ArtifactBundle, results: AuditResult[]): ExecutorRunResult;
14
14
  export declare function runRuntimeValidationExecutor(bundle: ArtifactBundle, root: string): Promise<ExecutorRunResult>;
@@ -1,6 +1,6 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import { buildFileDisposition } from "../extractors/disposition.js";
3
- import { buildGraphBundle } from "../extractors/graph.js";
3
+ import { buildGraphBundle, buildGraphBundleFromFs, } from "../extractors/graph.js";
4
4
  import { buildCriticalFlowManifest } from "../extractors/flows.js";
5
5
  import { buildRiskRegister } from "../extractors/risk.js";
6
6
  import { buildSurfaceManifest } from "../extractors/surfaces.js";
@@ -10,12 +10,50 @@ import { buildRequeuePayload } from "./requeueCommand.js";
10
10
  import { buildRuntimeValidationTasks, discoverRuntimeValidationCommand, mergeRuntimeValidationReport, } from "./runtimeValidation.js";
11
11
  import { buildAuditReportModel, renderAuditReportMarkdown, } from "../reporting/synthesis.js";
12
12
  import { buildChunkedAuditTasks, } from "./taskBuilder.js";
13
+ import { buildAuditPlanMetrics, buildReviewPackets, } from "./reviewPackets.js";
13
14
  import { buildUnitManifest } from "./unitBuilder.js";
14
15
  import { buildRepoManifestFromFs } from "../extractors/fsIntake.js";
15
16
  import { loadIgnoreFile } from "../extractors/ignore.js";
16
17
  import { ingestAuditResults, updateAuditTaskStatuses, } from "./resultIngestion.js";
18
+ import { buildSelectiveDeepeningTasks } from "./selectiveDeepening.js";
17
19
  import { updateRuntimeValidationReport } from "./runtimeValidationUpdate.js";
18
20
  import { autoCompleteTrivialCoverage } from "./trivialAudit.js";
21
+ function lineIndexFromTasks(tasks) {
22
+ return Object.fromEntries((tasks ?? []).flatMap((task) => Object.entries(task.file_line_counts ?? {})));
23
+ }
24
+ function appendSelectiveDeepeningTasks(params) {
25
+ if (!params.bundle.audit_tasks) {
26
+ return { bundle: params.bundle, taskCount: 0, artifacts: [] };
27
+ }
28
+ const lineIndex = lineIndexFromTasks(params.bundle.audit_tasks);
29
+ const selectiveDeepeningTasks = buildSelectiveDeepeningTasks({
30
+ existingTasks: params.bundle.audit_tasks,
31
+ results: params.results,
32
+ lineIndex,
33
+ runtimeValidationTasks: params.bundle.runtime_validation_tasks,
34
+ runtimeValidationReport: params.runtimeValidationReport ?? params.bundle.runtime_validation_report,
35
+ });
36
+ if (selectiveDeepeningTasks.length === 0) {
37
+ return { bundle: params.bundle, taskCount: 0, artifacts: [] };
38
+ }
39
+ const auditTasks = [...params.bundle.audit_tasks, ...selectiveDeepeningTasks];
40
+ return {
41
+ bundle: {
42
+ ...params.bundle,
43
+ audit_tasks: auditTasks,
44
+ audit_plan_metrics: buildAuditPlanMetrics(auditTasks, {
45
+ graphBundle: params.bundle.graph_bundle,
46
+ lineIndex,
47
+ }),
48
+ review_packets: buildReviewPackets(auditTasks, {
49
+ graphBundle: params.bundle.graph_bundle,
50
+ lineIndex,
51
+ }),
52
+ },
53
+ taskCount: selectiveDeepeningTasks.length,
54
+ artifacts: ["audit_tasks.json", "audit_plan_metrics.json", "review_packets.json"],
55
+ };
56
+ }
19
57
  async function runCommand(command, cwd) {
20
58
  return await new Promise((resolve) => {
21
59
  const child = spawn(command[0], command.slice(1), {
@@ -69,7 +107,7 @@ export async function runIntakeExecutor(bundle, root) {
69
107
  progress_summary: `Created intake artifacts for ${repoManifest.files.length} files.`,
70
108
  };
71
109
  }
72
- export function runStructureExecutor(bundle) {
110
+ export async function runStructureExecutor(bundle, root) {
73
111
  if (!bundle.repo_manifest) {
74
112
  throw new Error("Cannot run structure executor without repo_manifest");
75
113
  }
@@ -77,7 +115,9 @@ export function runStructureExecutor(bundle) {
77
115
  const disposition = bundle.file_disposition ?? buildFileDisposition(bundle.repo_manifest);
78
116
  const unitManifest = buildUnitManifest(bundle.repo_manifest, disposition);
79
117
  const surfaceManifest = buildSurfaceManifest(bundle.repo_manifest, disposition);
80
- const graphBundle = buildGraphBundle(bundle.repo_manifest, disposition);
118
+ const graphBundle = root
119
+ ? await buildGraphBundleFromFs(bundle.repo_manifest, root, disposition)
120
+ : buildGraphBundle(bundle.repo_manifest, disposition);
81
121
  const criticalFlows = buildCriticalFlowManifest(bundle.repo_manifest, surfaceManifest, disposition);
82
122
  const riskRegister = buildRiskRegister(unitManifest, criticalFlows, externalAnalyzerResults);
83
123
  return {
@@ -137,6 +177,14 @@ export async function runPlanningExecutor(bundle, root, lineIndex = {}) {
137
177
  ...task,
138
178
  status: task.status ?? "pending",
139
179
  }));
180
+ const reviewPackets = buildReviewPackets(taggedAuditTasks, {
181
+ graphBundle: bundle.graph_bundle,
182
+ lineIndex,
183
+ });
184
+ const auditPlanMetrics = buildAuditPlanMetrics(taggedAuditTasks, {
185
+ graphBundle: bundle.graph_bundle,
186
+ lineIndex,
187
+ });
140
188
  const requeuePayload = buildRequeuePayload(coverage, bundle.critical_flows, flowCoverage, externalAnalyzerResults);
141
189
  return {
142
190
  updated: {
@@ -146,6 +194,8 @@ export async function runPlanningExecutor(bundle, root, lineIndex = {}) {
146
194
  runtime_validation_tasks: runtimeValidationTasks,
147
195
  runtime_validation_report: runtimeValidationReport,
148
196
  audit_tasks: taggedAuditTasks,
197
+ audit_plan_metrics: auditPlanMetrics,
198
+ review_packets: reviewPackets,
149
199
  requeue_tasks: requeuePayload.tasks,
150
200
  audit_report: undefined,
151
201
  },
@@ -155,9 +205,11 @@ export async function runPlanningExecutor(bundle, root, lineIndex = {}) {
155
205
  "runtime_validation_tasks.json",
156
206
  ...(runtimeValidationReport ? ["runtime_validation_report.json"] : []),
157
207
  "audit_tasks.json",
208
+ "audit_plan_metrics.json",
209
+ "review_packets.json",
158
210
  "requeue_tasks.json",
159
211
  ],
160
- progress_summary: `Built planning artifacts; generated ${taggedAuditTasks.length} review blocks and ${requeuePayload.task_count} requeue tasks.` +
212
+ progress_summary: `Built planning artifacts; generated ${taggedAuditTasks.length} review tasks in ${reviewPackets.length} packet(s) and ${requeuePayload.task_count} requeue tasks.` +
161
213
  (skippedTrivialPaths.length > 0
162
214
  ? ` Skipped ${skippedTrivialPaths.length} trivial path${skippedTrivialPaths.length === 1 ? "" : "s"} from semantic review.`
163
215
  : "") +
@@ -188,19 +240,25 @@ export function runResultIngestionExecutor(bundle, results) {
188
240
  : bundle.runtime_validation_report;
189
241
  const requeuePayload = buildRequeuePayload(updatedCoverageMatrix, bundle.critical_flows, flowCoverage, bundle.external_analyzer_results);
190
242
  const mergedResults = [...(bundle.audit_results ?? []), ...results];
191
- const updatedAuditTasks = updateAuditTaskStatuses(bundle.audit_tasks, mergedResults);
243
+ const completedAuditTasks = updateAuditTaskStatuses(bundle.audit_tasks, mergedResults);
244
+ const baseUpdatedBundle = {
245
+ ...bundle,
246
+ coverage_matrix: updatedCoverageMatrix,
247
+ flow_coverage: flowCoverage,
248
+ runtime_validation_tasks: runtimeValidationTasks,
249
+ runtime_validation_report: runtimeValidationReport,
250
+ audit_results: mergedResults,
251
+ audit_tasks: completedAuditTasks,
252
+ requeue_tasks: requeuePayload.tasks,
253
+ audit_report: undefined,
254
+ };
255
+ const selectiveDeepening = appendSelectiveDeepeningTasks({
256
+ bundle: baseUpdatedBundle,
257
+ results: mergedResults,
258
+ runtimeValidationReport,
259
+ });
192
260
  return {
193
- updated: {
194
- ...bundle,
195
- coverage_matrix: updatedCoverageMatrix,
196
- flow_coverage: flowCoverage,
197
- runtime_validation_tasks: runtimeValidationTasks,
198
- runtime_validation_report: runtimeValidationReport,
199
- audit_results: mergedResults,
200
- audit_tasks: updatedAuditTasks,
201
- requeue_tasks: requeuePayload.tasks,
202
- audit_report: undefined,
203
- },
261
+ updated: selectiveDeepening.bundle,
204
262
  artifacts_written: [
205
263
  "coverage_matrix.json",
206
264
  "flow_coverage.json",
@@ -208,9 +266,13 @@ export function runResultIngestionExecutor(bundle, results) {
208
266
  ...(runtimeValidationReport ? ["runtime_validation_report.json"] : []),
209
267
  "audit_results.jsonl",
210
268
  "audit_tasks.json",
269
+ ...selectiveDeepening.artifacts.filter((artifact) => artifact !== "audit_tasks.json"),
211
270
  "requeue_tasks.json",
212
271
  ],
213
- progress_summary: `Ingested ${results.length} audit result entries and refreshed dependent artifacts.`,
272
+ progress_summary: `Ingested ${results.length} audit result entries and refreshed dependent artifacts.` +
273
+ (selectiveDeepening.taskCount > 0
274
+ ? ` Added ${selectiveDeepening.taskCount} selective deepening task(s).`
275
+ : ""),
214
276
  };
215
277
  }
216
278
  export async function runRuntimeValidationExecutor(bundle, root) {
@@ -247,16 +309,29 @@ export async function runRuntimeValidationExecutor(bundle, root) {
247
309
  notes: [`Target paths: ${task.target_paths.join(", ")}`],
248
310
  });
249
311
  }
312
+ const runtimeValidationReport = {
313
+ results: [...byTaskId.values()].sort((a, b) => a.task_id.localeCompare(b.task_id)),
314
+ };
315
+ const baseUpdatedBundle = {
316
+ ...bundle,
317
+ runtime_validation_report: runtimeValidationReport,
318
+ audit_report: undefined,
319
+ };
320
+ const selectiveDeepening = appendSelectiveDeepeningTasks({
321
+ bundle: baseUpdatedBundle,
322
+ results: bundle.audit_results ?? [],
323
+ runtimeValidationReport,
324
+ });
250
325
  return {
251
- updated: {
252
- ...bundle,
253
- runtime_validation_report: {
254
- results: [...byTaskId.values()].sort((a, b) => a.task_id.localeCompare(b.task_id)),
255
- },
256
- audit_report: undefined,
257
- },
258
- artifacts_written: ["runtime_validation_report.json"],
259
- progress_summary: `Executed deterministic runtime validation for ${bundle.runtime_validation_tasks.tasks.length} task(s).`,
326
+ updated: selectiveDeepening.bundle,
327
+ artifacts_written: [
328
+ "runtime_validation_report.json",
329
+ ...selectiveDeepening.artifacts,
330
+ ],
331
+ progress_summary: `Executed deterministic runtime validation for ${bundle.runtime_validation_tasks.tasks.length} task(s).` +
332
+ (selectiveDeepening.taskCount > 0
333
+ ? ` Added ${selectiveDeepening.taskCount} selective deepening task(s).`
334
+ : ""),
260
335
  };
261
336
  }
262
337
  export function runRuntimeValidationUpdateExecutor(bundle, updates) {
@@ -265,14 +340,26 @@ export function runRuntimeValidationUpdateExecutor(bundle, updates) {
265
340
  }
266
341
  const existingReport = bundle.runtime_validation_report ?? { results: [] };
267
342
  const mergedReport = updateRuntimeValidationReport(bundle.runtime_validation_tasks, existingReport, updates);
343
+ const baseUpdatedBundle = {
344
+ ...bundle,
345
+ runtime_validation_report: mergedReport,
346
+ audit_report: undefined,
347
+ };
348
+ const selectiveDeepening = appendSelectiveDeepeningTasks({
349
+ bundle: baseUpdatedBundle,
350
+ results: bundle.audit_results ?? [],
351
+ runtimeValidationReport: mergedReport,
352
+ });
268
353
  return {
269
- updated: {
270
- ...bundle,
271
- runtime_validation_report: mergedReport,
272
- audit_report: undefined,
273
- },
274
- artifacts_written: ["runtime_validation_report.json"],
275
- progress_summary: `Merged ${updates.results.length} runtime validation updates.`,
354
+ updated: selectiveDeepening.bundle,
355
+ artifacts_written: [
356
+ "runtime_validation_report.json",
357
+ ...selectiveDeepening.artifacts,
358
+ ],
359
+ progress_summary: `Merged ${updates.results.length} runtime validation updates.` +
360
+ (selectiveDeepening.taskCount > 0
361
+ ? ` Added ${selectiveDeepening.taskCount} selective deepening task(s).`
362
+ : ""),
276
363
  };
277
364
  }
278
365
  export function runSynthesisExecutor(bundle, results) {
@@ -0,0 +1,14 @@
1
+ import type { AuditTask } from "../types.js";
2
+ import type { AuditPlanMetrics, ReviewPacket } from "../types/reviewPlanning.js";
3
+ import type { GraphBundle } from "../types/graph.js";
4
+ export interface BuildReviewPacketOptions {
5
+ graphBundle?: GraphBundle;
6
+ lineIndex?: Record<string, number>;
7
+ maxTasksPerPacket?: number;
8
+ targetPacketLines?: number;
9
+ }
10
+ export declare function buildReviewPackets(tasks: AuditTask[], options?: BuildReviewPacketOptions): ReviewPacket[];
11
+ export declare function orderTasksForPacketReview(tasks: AuditTask[], options?: BuildReviewPacketOptions): AuditTask[];
12
+ export declare function buildAuditPlanMetrics(tasks: AuditTask[], options?: BuildReviewPacketOptions & {
13
+ generatedAt?: Date;
14
+ }): AuditPlanMetrics;