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,9 +1,22 @@
1
1
  import { decideNextStep } from "./nextStep.js";
2
2
  import { deriveAuditState } from "./state.js";
3
3
  import { computeArtifactMetadata } from "./artifactMetadata.js";
4
- import { runIntakeExecutor, runStructureExecutor, runPlanningExecutor, runResultIngestionExecutor, runRuntimeValidationUpdateExecutor, runSynthesisExecutor, runExternalAnalyzerImportExecutor, } from "./internalExecutors.js";
4
+ import { runIntakeExecutor, runStructureExecutor, runPlanningExecutor, runResultIngestionExecutor, runRuntimeValidationExecutor, runRuntimeValidationUpdateExecutor, runSynthesisExecutor, runExternalAnalyzerImportExecutor, } from "./internalExecutors.js";
5
5
  import { runAutoFixExecutor } from "./autoFixExecutor.js";
6
6
  import { runSyntaxResolutionExecutor } from "./syntaxResolutionExecutor.js";
7
+ function cloneState(state) {
8
+ return {
9
+ ...state,
10
+ blockers: [...(state.blockers ?? [])],
11
+ obligations: state.obligations.map((obligation) => ({ ...obligation })),
12
+ };
13
+ }
14
+ function formatExecutorFailure(selectedExecutor, selectedObligation, error) {
15
+ const detail = error instanceof Error ? error.message : String(error ?? "unknown error");
16
+ return new Error(`advanceAudit ${selectedExecutor} failed while resolving ${selectedObligation ?? "the current obligation"}: ${detail}`, {
17
+ cause: error instanceof Error ? error : undefined,
18
+ });
19
+ }
7
20
  export async function advanceAudit(bundle, options = {}) {
8
21
  const decision = decideNextStep(bundle);
9
22
  const forcedExecutor = options.preferredExecutor ?? null;
@@ -12,9 +25,12 @@ export async function advanceAudit(bundle, options = {}) {
12
25
  ? `forced:${forcedExecutor}`
13
26
  : decision.selected_obligation;
14
27
  if (!selectedExecutor) {
15
- const state = deriveAuditState(bundle);
16
- // Do not overwrite last_executor when no executor was selected — preserve prior value
17
- state.last_obligation = selectedObligation ?? undefined;
28
+ const state = cloneState(decision.state);
29
+ state.last_executor = bundle.audit_state?.last_executor ?? state.last_executor;
30
+ state.last_obligation =
31
+ selectedObligation ??
32
+ bundle.audit_state?.last_obligation ??
33
+ state.last_obligation;
18
34
  return {
19
35
  audit_state: state,
20
36
  selected_obligation: selectedObligation,
@@ -27,58 +43,70 @@ export async function advanceAudit(bundle, options = {}) {
27
43
  };
28
44
  }
29
45
  let run;
30
- switch (selectedExecutor) {
31
- case "intake_executor":
32
- if (!options.root)
33
- throw new Error("advanceAudit intake_executor requires root");
34
- run = await runIntakeExecutor(bundle, options.root);
35
- break;
36
- case "structure_executor":
37
- run = runStructureExecutor(bundle);
38
- break;
39
- case "planning_executor":
40
- run = runPlanningExecutor(bundle, options.lineIndex ?? {});
41
- break;
42
- case "result_ingestion_executor":
43
- run = runResultIngestionExecutor(bundle, options.auditResults ?? bundle.audit_results ?? []);
44
- break;
45
- case "synthesis_executor":
46
- run = runSynthesisExecutor(bundle, options.auditResults);
47
- break;
48
- case "runtime_validation_update_executor":
49
- if (!options.runtimeValidationUpdates)
50
- throw new Error("advanceAudit runtime_validation_update_executor requires runtimeValidationUpdates");
51
- run = runRuntimeValidationUpdateExecutor(bundle, options.runtimeValidationUpdates);
52
- break;
53
- case "external_analyzer_import_executor":
54
- if (!options.externalAnalyzerResults)
55
- throw new Error("advanceAudit external_analyzer_import_executor requires externalAnalyzerResults");
56
- run = runExternalAnalyzerImportExecutor(bundle, options.externalAnalyzerResults);
57
- break;
58
- case "auto_fix_executor":
59
- if (!options.root)
60
- throw new Error("advanceAudit auto_fix_executor requires root");
61
- run = runAutoFixExecutor(bundle, options.root);
62
- break;
63
- case "syntax_resolution_executor":
64
- if (!options.root)
65
- throw new Error("advanceAudit syntax_resolution_executor requires root");
66
- run = runSyntaxResolutionExecutor(bundle, options.root);
67
- break;
68
- default:
69
- const state = deriveAuditState(bundle);
70
- state.last_executor = selectedExecutor;
71
- state.last_obligation = selectedObligation ?? undefined;
72
- return {
73
- audit_state: state,
74
- selected_obligation: selectedObligation,
75
- selected_executor: selectedExecutor,
76
- progress_made: false,
77
- artifacts_written: ["audit_state.json"],
78
- progress_summary: `Executor ${selectedExecutor} is selected but not yet dispatched through advance-audit.`,
79
- next_likely_step: selectedObligation,
80
- updated_bundle: { ...bundle, audit_state: state },
81
- };
46
+ try {
47
+ switch (selectedExecutor) {
48
+ case "intake_executor":
49
+ if (!options.root)
50
+ throw new Error("advanceAudit intake_executor requires root");
51
+ run = await runIntakeExecutor(bundle, options.root);
52
+ break;
53
+ case "structure_executor":
54
+ run = runStructureExecutor(bundle);
55
+ break;
56
+ case "planning_executor":
57
+ if (!options.root)
58
+ throw new Error("advanceAudit planning_executor requires root");
59
+ run = await runPlanningExecutor(bundle, options.root, options.lineIndex ?? {});
60
+ break;
61
+ case "result_ingestion_executor":
62
+ run = runResultIngestionExecutor(bundle, options.auditResults ?? bundle.audit_results ?? []);
63
+ break;
64
+ case "runtime_validation_executor":
65
+ if (!options.root)
66
+ throw new Error("advanceAudit runtime_validation_executor requires root");
67
+ run = await runRuntimeValidationExecutor(bundle, options.root);
68
+ break;
69
+ case "synthesis_executor":
70
+ run = runSynthesisExecutor(bundle, options.auditResults);
71
+ break;
72
+ case "runtime_validation_update_executor":
73
+ if (!options.runtimeValidationUpdates)
74
+ throw new Error("advanceAudit runtime_validation_update_executor requires runtimeValidationUpdates");
75
+ run = runRuntimeValidationUpdateExecutor(bundle, options.runtimeValidationUpdates);
76
+ break;
77
+ case "external_analyzer_import_executor":
78
+ if (!options.externalAnalyzerResults)
79
+ throw new Error("advanceAudit external_analyzer_import_executor requires externalAnalyzerResults");
80
+ run = runExternalAnalyzerImportExecutor(bundle, options.externalAnalyzerResults);
81
+ break;
82
+ case "auto_fix_executor":
83
+ if (!options.root)
84
+ throw new Error("advanceAudit auto_fix_executor requires root");
85
+ run = runAutoFixExecutor(bundle, options.root);
86
+ break;
87
+ case "syntax_resolution_executor":
88
+ if (!options.root)
89
+ throw new Error("advanceAudit syntax_resolution_executor requires root");
90
+ run = runSyntaxResolutionExecutor(bundle, options.root);
91
+ break;
92
+ default:
93
+ const state = deriveAuditState(bundle);
94
+ state.last_executor = selectedExecutor;
95
+ state.last_obligation = selectedObligation ?? undefined;
96
+ return {
97
+ audit_state: state,
98
+ selected_obligation: selectedObligation,
99
+ selected_executor: selectedExecutor,
100
+ progress_made: false,
101
+ artifacts_written: ["audit_state.json"],
102
+ progress_summary: `Executor ${selectedExecutor} is selected but not yet dispatched through advance-audit.`,
103
+ next_likely_step: selectedObligation,
104
+ updated_bundle: { ...bundle, audit_state: state },
105
+ };
106
+ }
107
+ }
108
+ catch (error) {
109
+ throw formatExecutorFailure(selectedExecutor, selectedObligation, error);
82
110
  }
83
111
  const metadata = computeArtifactMetadata(run.updated, bundle.artifact_metadata);
84
112
  const metadataBundle = { ...run.updated, artifact_metadata: metadata };
@@ -12,7 +12,7 @@ export const ARTIFACT_DEPENDENCY_MAP = {
12
12
  "requeue_tasks.json",
13
13
  "runtime_validation_tasks.json",
14
14
  "runtime_validation_report.json",
15
- "synthesis_report.json",
15
+ "audit-report.md",
16
16
  ],
17
17
  "file_disposition.json": [
18
18
  "unit_manifest.json",
@@ -26,7 +26,7 @@ export const ARTIFACT_DEPENDENCY_MAP = {
26
26
  "requeue_tasks.json",
27
27
  "runtime_validation_tasks.json",
28
28
  "runtime_validation_report.json",
29
- "synthesis_report.json",
29
+ "audit-report.md",
30
30
  ],
31
31
  "unit_manifest.json": [
32
32
  "risk_register.json",
@@ -34,13 +34,13 @@ export const ARTIFACT_DEPENDENCY_MAP = {
34
34
  "audit_tasks.json",
35
35
  "runtime_validation_tasks.json",
36
36
  "requeue_tasks.json",
37
- "synthesis_report.json",
37
+ "audit-report.md",
38
38
  ],
39
39
  "surface_manifest.json": [
40
40
  "critical_flows.json",
41
41
  "risk_register.json",
42
42
  "runtime_validation_tasks.json",
43
- "synthesis_report.json",
43
+ "audit-report.md",
44
44
  ],
45
45
  "critical_flows.json": [
46
46
  "flow_coverage.json",
@@ -49,7 +49,7 @@ export const ARTIFACT_DEPENDENCY_MAP = {
49
49
  "requeue_tasks.json",
50
50
  "runtime_validation_tasks.json",
51
51
  "runtime_validation_report.json",
52
- "synthesis_report.json",
52
+ "audit-report.md",
53
53
  ],
54
54
  "audit_results.jsonl": [
55
55
  "coverage_matrix.json",
@@ -57,26 +57,22 @@ export const ARTIFACT_DEPENDENCY_MAP = {
57
57
  "requeue_tasks.json",
58
58
  "runtime_validation_tasks.json",
59
59
  "runtime_validation_report.json",
60
- "merged_findings.json",
61
- "root_cause_clusters.json",
62
- "synthesis_report.json",
60
+ "audit-report.md",
63
61
  ],
64
62
  "coverage_matrix.json": [
65
63
  "flow_coverage.json",
66
64
  "requeue_tasks.json",
67
65
  "runtime_validation_tasks.json",
68
66
  "runtime_validation_report.json",
69
- "synthesis_report.json",
67
+ "audit-report.md",
70
68
  ],
71
69
  "flow_coverage.json": [
72
70
  "requeue_tasks.json",
73
71
  "runtime_validation_tasks.json",
74
72
  "runtime_validation_report.json",
75
- "synthesis_report.json",
73
+ "audit-report.md",
76
74
  ],
77
75
  "runtime_validation_report.json": [
78
- "merged_findings.json",
79
- "root_cause_clusters.json",
80
- "synthesis_report.json",
76
+ "audit-report.md",
81
77
  ],
82
78
  };
@@ -20,14 +20,19 @@ export const EXECUTOR_REGISTRY = [
20
20
  description: "Ingest available audit result artifacts and refresh dependent coverage artifacts.",
21
21
  },
22
22
  {
23
- id: "runtime_validation_update_executor",
23
+ id: "runtime_validation_executor",
24
24
  obligation_ids: ["runtime_validation_current"],
25
25
  description: "Merge runtime validation evidence updates when provided.",
26
26
  },
27
+ {
28
+ id: "runtime_validation_update_executor",
29
+ obligation_ids: [],
30
+ description: "Merge imported runtime validation evidence updates.",
31
+ },
27
32
  {
28
33
  id: "synthesis_executor",
29
34
  obligation_ids: ["synthesis_current"],
30
- description: "Refresh merged findings, clusters, and synthesis outputs.",
35
+ description: "Render the final deterministic Markdown audit report.",
31
36
  },
32
37
  {
33
38
  id: "external_analyzer_import_executor",
@@ -10,11 +10,17 @@ function lensSetForFlow(concerns) {
10
10
  return concerns.filter((concern) => allowed.includes(concern));
11
11
  }
12
12
  export function buildFlowCoverage(criticalFlows, coverageMatrix) {
13
+ const coverageByPath = new Map(coverageMatrix.files.map((file) => [file.path, file]));
13
14
  const flows = criticalFlows.flows.map((flow) => {
14
- const required = lensSetForFlow(flow.concerns);
15
+ const flowPaths = Array.isArray(flow.paths)
16
+ ? flow.paths.filter((path) => typeof path === "string")
17
+ : [];
18
+ const required = lensSetForFlow(Array.isArray(flow.concerns)
19
+ ? flow.concerns.filter((concern) => typeof concern === "string")
20
+ : []);
15
21
  const completed = new Set();
16
- for (const path of flow.paths) {
17
- const record = coverageMatrix.files.find((file) => file.path === path);
22
+ for (const path of flowPaths) {
23
+ const record = coverageByPath.get(path);
18
24
  if (!record || record.audit_status === "excluded") {
19
25
  continue;
20
26
  }
@@ -33,11 +39,11 @@ export function buildFlowCoverage(criticalFlows, coverageMatrix) {
33
39
  : "pending";
34
40
  return {
35
41
  flow_id: flow.id,
36
- paths: flow.paths,
42
+ paths: flowPaths,
37
43
  required_lenses: required,
38
44
  completed_lenses,
39
45
  status,
40
- notes: [`Derived from ${flow.paths.length} path(s).`],
46
+ notes: [`Derived from ${flowPaths.length} path(s).`],
41
47
  };
42
48
  });
43
49
  return { flows };
@@ -1,3 +1,8 @@
1
- import type { AuditTask } from "../types.js";
1
+ import type { Lens } from "../types.js";
2
2
  import type { CriticalFlowManifest } from "../types/flows.js";
3
- export declare function buildFlowAwareTaskAugmentations(existingTasks: AuditTask[], criticalFlows: CriticalFlowManifest, _lineIndex: Record<string, number>): AuditTask[];
3
+ export interface FlowReviewBlock {
4
+ flow_id: string;
5
+ lens: Lens;
6
+ file_paths: string[];
7
+ }
8
+ export declare function claimFlowReviewBlocks(criticalFlows: CriticalFlowManifest, pendingByLens: Map<Lens, Set<string>>, assigned: Set<string>): FlowReviewBlock[];
@@ -3,33 +3,58 @@ const DEFAULT_FLOW_LENS_PRIORITY = [
3
3
  "reliability",
4
4
  "correctness",
5
5
  ];
6
- export function buildFlowAwareTaskAugmentations(existingTasks, criticalFlows, _lineIndex) {
7
- const seenTaskIds = new Set(existingTasks.map((task) => task.task_id));
8
- // Signature: lens + sorted file list, so duplicate (flow, lens) combos across
9
- // different flow groupings are still deduplicated.
10
- const existingSignatures = new Set(existingTasks.map((t) => `${t.lens}|${[...t.file_paths].sort().join(",")}`));
11
- const extraTasks = [];
6
+ function lensPathKey(lens, path) {
7
+ return `${lens}:${path}`;
8
+ }
9
+ function flowLensPriority(lens) {
10
+ const index = DEFAULT_FLOW_LENS_PRIORITY.indexOf(lens);
11
+ return index >= 0 ? index : DEFAULT_FLOW_LENS_PRIORITY.length;
12
+ }
13
+ export function claimFlowReviewBlocks(criticalFlows, pendingByLens, assigned) {
14
+ const candidates = [];
12
15
  for (const flow of criticalFlows.flows) {
13
- const desiredLenses = flow.concerns.filter((concern) => DEFAULT_FLOW_LENS_PRIORITY.includes(concern));
16
+ const flowPaths = [...new Set(flow.paths)].sort((a, b) => a.localeCompare(b));
17
+ const desiredLenses = flow.concerns
18
+ .filter((concern) => DEFAULT_FLOW_LENS_PRIORITY.includes(concern))
19
+ .sort((a, b) => flowLensPriority(a) - flowLensPriority(b));
14
20
  for (const lens of desiredLenses) {
15
- // One task per (flow, lens) with all flow paths together so the agent
16
- // can trace data across file boundaries in a single pass.
17
- const taskId = `flow:${flow.id}:${lens}`;
18
- const signature = `${lens}|${[...flow.paths].sort().join(",")}`;
19
- if (seenTaskIds.has(taskId) || existingSignatures.has(signature)) {
21
+ const pendingPaths = pendingByLens.get(lens);
22
+ if (!pendingPaths || pendingPaths.size === 0) {
23
+ continue;
24
+ }
25
+ const filePaths = flowPaths.filter((path) => pendingPaths.has(path));
26
+ if (filePaths.length === 0) {
20
27
  continue;
21
28
  }
22
- extraTasks.push({
23
- task_id: taskId,
24
- unit_id: `flow:${flow.id}`,
25
- pass_id: `flow-pass:${lens}`,
29
+ candidates.push({
30
+ flow_id: flow.id,
26
31
  lens,
27
- file_paths: [...flow.paths],
28
- rationale: `Flow-aware audit for critical flow "${flow.id}" (${flow.paths.length} file${flow.paths.length === 1 ? "" : "s"}) under the ${lens} lens.`,
32
+ file_paths: filePaths,
29
33
  });
30
- seenTaskIds.add(taskId);
31
- existingSignatures.add(signature);
32
34
  }
33
35
  }
34
- return extraTasks;
36
+ candidates.sort((a, b) => {
37
+ const sizeDelta = b.file_paths.length - a.file_paths.length;
38
+ if (sizeDelta !== 0)
39
+ return sizeDelta;
40
+ const lensDelta = flowLensPriority(a.lens) - flowLensPriority(b.lens);
41
+ if (lensDelta !== 0)
42
+ return lensDelta;
43
+ return a.flow_id.localeCompare(b.flow_id);
44
+ });
45
+ const blocks = [];
46
+ for (const candidate of candidates) {
47
+ const unclaimedPaths = candidate.file_paths.filter((path) => !assigned.has(lensPathKey(candidate.lens, path)));
48
+ if (unclaimedPaths.length === 0) {
49
+ continue;
50
+ }
51
+ for (const path of unclaimedPaths) {
52
+ assigned.add(lensPathKey(candidate.lens, path));
53
+ }
54
+ blocks.push({
55
+ ...candidate,
56
+ file_paths: unclaimedPaths,
57
+ });
58
+ }
59
+ return blocks;
35
60
  }
@@ -10,7 +10,17 @@ function isLens(value) {
10
10
  "tests",
11
11
  "operability",
12
12
  "config_deployment",
13
- ].includes(value);
13
+ ].includes(String(value));
14
+ }
15
+ function getExternalSignalPaths(externalAnalyzerResults) {
16
+ const results = Array.isArray(externalAnalyzerResults?.results)
17
+ ? externalAnalyzerResults.results
18
+ : [];
19
+ return new Set(results
20
+ .map((item) => item && typeof item.path === "string" && item.path.length > 0
21
+ ? item.path
22
+ : null)
23
+ .filter((path) => path !== null));
14
24
  }
15
25
  function taskPriority(hasExternalSignal, lens) {
16
26
  if (hasExternalSignal &&
@@ -19,8 +29,8 @@ function taskPriority(hasExternalSignal, lens) {
19
29
  }
20
30
  return hasExternalSignal ? "medium" : "low";
21
31
  }
22
- function fileStillNeedsLens(coverageMatrix, path, lens) {
23
- const record = coverageMatrix.files.find((file) => file.path === path);
32
+ function fileStillNeedsLens(coverageByPath, path, lens) {
33
+ const record = coverageByPath.get(path);
24
34
  if (!record || record.audit_status === "excluded") {
25
35
  return false;
26
36
  }
@@ -28,21 +38,31 @@ function fileStillNeedsLens(coverageMatrix, path, lens) {
28
38
  }
29
39
  export function buildFlowRequeueTasks(criticalFlows, flowCoverage, coverageMatrix, externalAnalyzerResults) {
30
40
  const flowMap = new Map(criticalFlows.flows.map((flow) => [flow.id, flow]));
41
+ const coverageByPath = new Map(coverageMatrix.files.map((file) => [file.path, file]));
31
42
  const tasks = [];
32
43
  const seen = new Set();
33
- const externalPaths = new Set((externalAnalyzerResults?.results ?? []).map((item) => item.path));
44
+ const externalPaths = getExternalSignalPaths(externalAnalyzerResults);
34
45
  for (const record of flowCoverage.flows) {
35
46
  const flow = flowMap.get(record.flow_id);
36
47
  if (!flow) {
37
48
  continue;
38
49
  }
39
- const missingLenses = record.required_lenses.filter((lens) => !record.completed_lenses.includes(lens));
50
+ const requiredLenses = Array.isArray(record.required_lenses)
51
+ ? record.required_lenses.filter((lens) => typeof lens === "string")
52
+ : [];
53
+ const completedLenses = new Set(Array.isArray(record.completed_lenses)
54
+ ? record.completed_lenses.filter((lens) => typeof lens === "string")
55
+ : []);
56
+ const missingLenses = requiredLenses.filter((lens) => !completedLenses.has(lens));
57
+ const flowPaths = Array.isArray(flow.paths)
58
+ ? flow.paths.filter((path) => typeof path === "string")
59
+ : [];
40
60
  for (const lensName of missingLenses) {
41
61
  if (!isLens(lensName)) {
42
- continue;
62
+ throw new Error(`buildFlowRequeueTasks encountered unsupported lens "${String(lensName)}" for flow ${record.flow_id}.`);
43
63
  }
44
- for (const path of flow.paths) {
45
- if (!fileStillNeedsLens(coverageMatrix, path, lensName)) {
64
+ for (const path of flowPaths) {
65
+ if (!fileStillNeedsLens(coverageByPath, path, lensName)) {
46
66
  continue;
47
67
  }
48
68
  const signature = `${flow.id}|${lensName}|${path}`;
@@ -57,7 +77,7 @@ export function buildFlowRequeueTasks(criticalFlows, flowCoverage, coverageMatri
57
77
  pass_id: `flow-requeue:${lensName}`,
58
78
  lens: lensName,
59
79
  file_paths: [path],
60
- rationale: `Requeue ${path} because critical flow ${flow.id} is still missing the ${lensName} lens.${hasExternalSignal ? " External analyzer signals make this follow-up higher priority." : ""}`,
80
+ rationale: `Mandatory audit coverage is still missing for critical flow ${flow.id} at ${path} under the ${lensName} lens.`,
61
81
  priority: taskPriority(hasExternalSignal, lensName),
62
82
  tags: hasExternalSignal
63
83
  ? ["critical_flow_followup", "external_analyzer_signal"]
@@ -9,8 +9,9 @@ export interface ExecutorRunResult {
9
9
  }
10
10
  export declare function runIntakeExecutor(bundle: ArtifactBundle, root: string): Promise<ExecutorRunResult>;
11
11
  export declare function runStructureExecutor(bundle: ArtifactBundle): ExecutorRunResult;
12
- export declare function runPlanningExecutor(bundle: ArtifactBundle, lineIndex?: Record<string, number>): ExecutorRunResult;
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
+ export declare function runRuntimeValidationExecutor(bundle: ArtifactBundle, root: string): Promise<ExecutorRunResult>;
14
15
  export declare function runRuntimeValidationUpdateExecutor(bundle: ArtifactBundle, updates: RuntimeValidationReport): ExecutorRunResult;
15
16
  export declare function runSynthesisExecutor(bundle: ArtifactBundle, results?: AuditResult[]): ExecutorRunResult;
16
17
  export declare function runExternalAnalyzerImportExecutor(bundle: ArtifactBundle, externalResults: ExternalAnalyzerResults): ExecutorRunResult;