auditor-lambda 0.1.0 → 0.2.2

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 (87) hide show
  1. package/README.md +2 -1
  2. package/audit-code-wrapper-lib.mjs +205 -187
  3. package/dist/adapters/eslint.js +4 -2
  4. package/dist/adapters/npmAudit.js +1 -1
  5. package/dist/cli.js +296 -12
  6. package/dist/coverage.d.ts +0 -1
  7. package/dist/coverage.js +3 -34
  8. package/dist/extractors/bucketing.js +14 -35
  9. package/dist/extractors/disposition.js +8 -9
  10. package/dist/extractors/flows.js +14 -23
  11. package/dist/extractors/pathPatterns.d.ts +19 -0
  12. package/dist/extractors/pathPatterns.js +87 -0
  13. package/dist/extractors/surfaces.js +2 -7
  14. package/dist/io/artifacts.d.ts +23 -1
  15. package/dist/io/artifacts.js +3 -1
  16. package/dist/io/runArtifacts.js +1 -1
  17. package/dist/orchestrator/advance.js +1 -1
  18. package/dist/orchestrator/flowPlanning.d.ts +1 -1
  19. package/dist/orchestrator/flowPlanning.js +21 -28
  20. package/dist/orchestrator/internalExecutors.js +4 -7
  21. package/dist/orchestrator/planning.js +12 -20
  22. package/dist/orchestrator/resultIngestion.js +3 -2
  23. package/dist/orchestrator/runtimeValidation.js +5 -0
  24. package/dist/orchestrator/syntaxResolutionExecutor.js +10 -2
  25. package/dist/orchestrator/taskBuilder.d.ts +7 -2
  26. package/dist/orchestrator/taskBuilder.js +47 -52
  27. package/dist/prompts/renderWorkerPrompt.js +33 -0
  28. package/dist/providers/claudeCodeProvider.js +5 -0
  29. package/dist/providers/constants.d.ts +1 -0
  30. package/dist/providers/constants.js +1 -0
  31. package/dist/providers/index.js +9 -2
  32. package/dist/providers/spawnLoggedCommand.js +4 -0
  33. package/dist/reporting/mergeFindings.js +0 -7
  34. package/dist/reporting/rootCause.d.ts +0 -1
  35. package/dist/reporting/rootCause.js +0 -6
  36. package/dist/reporting/synthesis.js +18 -0
  37. package/dist/supervisor/operatorHandoff.d.ts +2 -0
  38. package/dist/supervisor/operatorHandoff.js +21 -9
  39. package/dist/supervisor/runLedger.js +6 -3
  40. package/dist/supervisor/sessionConfig.js +1 -0
  41. package/dist/types/flowCoverage.d.ts +1 -1
  42. package/dist/types/runLedger.d.ts +1 -1
  43. package/dist/types/runtimeValidation.d.ts +2 -1
  44. package/dist/types/sessionConfig.d.ts +2 -0
  45. package/dist/types/surfaces.d.ts +2 -1
  46. package/dist/types/workerSession.d.ts +4 -0
  47. package/dist/types.d.ts +0 -2
  48. package/dist/validation/auditResults.d.ts +11 -0
  49. package/dist/validation/auditResults.js +118 -0
  50. package/docs/agent-integrations.md +61 -56
  51. package/docs/agent-roles.md +69 -69
  52. package/docs/architecture.md +90 -90
  53. package/docs/artifacts.md +69 -69
  54. package/docs/bootstrap-install.md +1 -1
  55. package/docs/model-selection.md +86 -86
  56. package/docs/next-steps.md +11 -9
  57. package/docs/packaging.md +3 -3
  58. package/docs/pipeline.md +152 -152
  59. package/docs/production-readiness.md +6 -5
  60. package/docs/repo-layout.md +18 -18
  61. package/docs/run-flow.md +5 -5
  62. package/docs/session-config.md +216 -210
  63. package/docs/supervisor.md +70 -70
  64. package/docs/windows-setup.md +139 -139
  65. package/package.json +56 -56
  66. package/schemas/audit-code-v1alpha1.schema.json +80 -76
  67. package/schemas/audit_result.schema.json +54 -48
  68. package/schemas/audit_state.schema.json +2 -2
  69. package/schemas/audit_task.schema.json +60 -49
  70. package/schemas/blind_spot_register.schema.json +13 -3
  71. package/schemas/coverage_matrix.schema.json +14 -17
  72. package/schemas/critical_flows.schema.json +6 -3
  73. package/schemas/external_analyzer_results.schema.json +10 -4
  74. package/schemas/file_disposition.schema.json +33 -33
  75. package/schemas/finding.schema.json +86 -62
  76. package/schemas/flow_coverage.schema.json +53 -44
  77. package/schemas/graph_bundle.schema.json +12 -6
  78. package/schemas/merged_findings.schema.json +7 -2
  79. package/schemas/risk_register.schema.json +5 -1
  80. package/schemas/root_cause_clusters.schema.json +2 -5
  81. package/schemas/runtime_validation_report.schema.json +34 -34
  82. package/schemas/runtime_validation_tasks.schema.json +4 -1
  83. package/schemas/surface_manifest.schema.json +4 -1
  84. package/schemas/synthesis_report.schema.json +61 -61
  85. package/schemas/unit_manifest.schema.json +10 -3
  86. package/skills/audit-code/SKILL.md +37 -37
  87. package/skills/audit-code/audit-code.prompt.md +54 -54
@@ -1,27 +1,18 @@
1
1
  import { isAuditExcludedStatus } from "./disposition.js";
2
+ import { isSecuritySensitivePath, isDataLayerPath, isConcurrencyPath, isInterfacePath, isDeploymentConfigPath, } from "./pathPatterns.js";
2
3
  function inferConcerns(paths) {
3
4
  const concerns = new Set();
4
5
  for (const path of paths) {
5
6
  const normalized = path.toLowerCase();
6
- if (normalized.includes("auth") ||
7
- normalized.includes("token") ||
8
- normalized.includes("session"))
7
+ if (isSecuritySensitivePath(normalized))
9
8
  concerns.add("security");
10
- if (normalized.includes("db") ||
11
- normalized.includes("model") ||
12
- normalized.includes("schema") ||
13
- normalized.includes("migration") ||
9
+ if (isDataLayerPath(normalized) ||
14
10
  normalized.includes("invoice") ||
15
11
  normalized.includes("payment"))
16
12
  concerns.add("data_integrity");
17
- if (normalized.includes("worker") ||
18
- normalized.includes("job") ||
19
- normalized.includes("retry") ||
20
- normalized.includes("queue"))
13
+ if (isConcurrencyPath(normalized))
21
14
  concerns.add("reliability");
22
- if (normalized.includes("api") ||
23
- normalized.includes("route") ||
24
- normalized.includes("controller"))
15
+ if (isInterfacePath(normalized))
25
16
  concerns.add("correctness");
26
17
  }
27
18
  return concerns.size > 0 ? [...concerns] : ["correctness"];
@@ -33,13 +24,15 @@ function relatedPaths(entry, availablePaths) {
33
24
  const lower = path.toLowerCase();
34
25
  if (path === entry)
35
26
  continue;
36
- if ((normalized.includes("auth") || normalized.includes("session")) &&
27
+ // Auth / session flows: link sibling auth, session, token, user paths
28
+ if (isSecuritySensitivePath(normalized) &&
37
29
  (lower.includes("auth") ||
38
30
  lower.includes("session") ||
39
31
  lower.includes("token") ||
40
32
  lower.includes("user"))) {
41
33
  linked.add(path);
42
34
  }
35
+ // Billing / payment flows: link ledger and subscription paths
43
36
  if ((normalized.includes("billing") ||
44
37
  normalized.includes("invoice") ||
45
38
  normalized.includes("payment")) &&
@@ -50,9 +43,8 @@ function relatedPaths(entry, availablePaths) {
50
43
  lower.includes("subscription"))) {
51
44
  linked.add(path);
52
45
  }
53
- if ((normalized.includes("job") ||
54
- normalized.includes("worker") ||
55
- normalized.includes("queue")) &&
46
+ // Async / queue flows: link worker, job, retry, and task paths
47
+ if (isConcurrencyPath(normalized) &&
56
48
  (lower.includes("queue") ||
57
49
  lower.includes("retry") ||
58
50
  lower.includes("worker") ||
@@ -60,7 +52,8 @@ function relatedPaths(entry, availablePaths) {
60
52
  lower.includes("task"))) {
61
53
  linked.add(path);
62
54
  }
63
- if ((normalized.includes("deploy") || normalized.includes("docker")) &&
55
+ // Deployment / infra flows: link docker, k8s, terraform, workflow paths
56
+ if (isDeploymentConfigPath(normalized) &&
64
57
  (lower.includes("deploy") ||
65
58
  lower.includes("docker") ||
66
59
  lower.includes("workflow") ||
@@ -75,7 +68,7 @@ function dedupeFlows(flows) {
75
68
  const seen = new Set();
76
69
  const deduped = [];
77
70
  for (const flow of flows) {
78
- const signature = `${flow.name}|${flow.paths.join(",")}|${flow.concerns.join(",")}`;
71
+ const signature = `${flow.name}|${[...flow.paths].sort().join(",")}|${[...flow.concerns].sort().join(",")}`;
79
72
  if (seen.has(signature))
80
73
  continue;
81
74
  seen.add(signature);
@@ -108,9 +101,7 @@ export function buildCriticalFlowManifest(repoManifest, surfaceManifest, disposi
108
101
  }
109
102
  for (const path of availablePaths) {
110
103
  const lower = path.toLowerCase();
111
- if (lower.includes("migration") ||
112
- lower.includes("schema") ||
113
- lower.includes("seed")) {
104
+ if (isDataLayerPath(lower) || lower.includes("seed")) {
114
105
  flows.push({
115
106
  id: `flow:data:${path.replace(/[^a-zA-Z0-9:_-]/g, "-")}`,
116
107
  name: `data evolution flow for ${path}`,
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Centralised path-pattern predicates shared across disposition, bucketing,
3
+ * surfaces, and flows extractors. Every function operates on the
4
+ * already-lower-cased form of the path.
5
+ */
6
+ export declare function isNodeModulesOrGit(normalized: string): boolean;
7
+ export declare function isBuildOutput(normalized: string): boolean;
8
+ export declare function isVendorPath(normalized: string): boolean;
9
+ export declare function isBinaryArtifact(normalized: string): boolean;
10
+ export declare function isDocPath(normalized: string): boolean;
11
+ export declare function isTestPath(normalized: string): boolean;
12
+ export declare function isInterfacePath(normalized: string): boolean;
13
+ export declare function isDataLayerPath(normalized: string): boolean;
14
+ export declare function isSecuritySensitivePath(normalized: string): boolean;
15
+ export declare function isConcurrencyPath(normalized: string): boolean;
16
+ export declare function isScriptPath(normalized: string): boolean;
17
+ export declare function isDeploymentConfigPath(normalized: string): boolean;
18
+ export declare function isGeneratedPath(normalized: string): boolean;
19
+ export declare function isSurfacePath(normalized: string): boolean;
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Centralised path-pattern predicates shared across disposition, bucketing,
3
+ * surfaces, and flows extractors. Every function operates on the
4
+ * already-lower-cased form of the path.
5
+ */
6
+ export function isNodeModulesOrGit(normalized) {
7
+ return (normalized.startsWith("node_modules/") ||
8
+ normalized === "node_modules" ||
9
+ normalized.startsWith(".git/") ||
10
+ normalized === ".git");
11
+ }
12
+ export function isBuildOutput(normalized) {
13
+ return normalized.startsWith("dist/") || normalized.startsWith("build/");
14
+ }
15
+ export function isVendorPath(normalized) {
16
+ return normalized.includes("vendor") || normalized.includes("third_party");
17
+ }
18
+ export function isBinaryArtifact(normalized) {
19
+ return (normalized.endsWith(".png") ||
20
+ normalized.endsWith(".jpg") ||
21
+ normalized.endsWith(".jpeg") ||
22
+ normalized.endsWith(".gif") ||
23
+ normalized.endsWith(".pdf") ||
24
+ normalized.endsWith(".zip"));
25
+ }
26
+ export function isDocPath(normalized) {
27
+ return normalized.endsWith(".md") || normalized.startsWith("docs/");
28
+ }
29
+ export function isTestPath(normalized) {
30
+ return (normalized.includes("test") ||
31
+ normalized.includes("spec") ||
32
+ normalized.includes("__tests__"));
33
+ }
34
+ export function isInterfacePath(normalized) {
35
+ return (normalized.includes("route") ||
36
+ normalized.includes("controller") ||
37
+ normalized.includes("handler") ||
38
+ normalized.includes("api/"));
39
+ }
40
+ export function isDataLayerPath(normalized) {
41
+ return (normalized.includes("model") ||
42
+ normalized.includes("schema") ||
43
+ normalized.includes("migration") ||
44
+ normalized.includes("seed") ||
45
+ normalized.includes("db/"));
46
+ }
47
+ export function isSecuritySensitivePath(normalized) {
48
+ return (normalized.includes("auth") ||
49
+ normalized.includes("secret") ||
50
+ normalized.includes("token") ||
51
+ normalized.includes("permission") ||
52
+ normalized.includes("session"));
53
+ }
54
+ export function isConcurrencyPath(normalized) {
55
+ return (normalized.includes("queue") ||
56
+ normalized.includes("worker") ||
57
+ normalized.includes("job") ||
58
+ normalized.includes("cache") ||
59
+ normalized.includes("retry") ||
60
+ normalized.includes("lock"));
61
+ }
62
+ export function isScriptPath(normalized) {
63
+ return (normalized.includes("script") ||
64
+ normalized.startsWith("scripts/") ||
65
+ normalized.startsWith("bin/"));
66
+ }
67
+ export function isDeploymentConfigPath(normalized) {
68
+ return (normalized.includes("docker") ||
69
+ normalized.includes("terraform") ||
70
+ normalized.includes("deploy") ||
71
+ normalized.includes("workflow") ||
72
+ normalized.includes("k8s") ||
73
+ normalized.endsWith(".yml") ||
74
+ normalized.endsWith(".yaml"));
75
+ }
76
+ export function isGeneratedPath(normalized) {
77
+ return normalized.includes("vendor") || normalized.includes("generated");
78
+ }
79
+ export function isSurfacePath(normalized) {
80
+ return (normalized.includes("api/") ||
81
+ normalized.includes("route") ||
82
+ normalized.includes("controller") ||
83
+ normalized.includes("worker") ||
84
+ normalized.includes("job") ||
85
+ normalized.includes("command") ||
86
+ normalized.includes("cli"));
87
+ }
@@ -1,4 +1,5 @@
1
1
  import { isAuditExcludedStatus } from "./disposition.js";
2
+ import { isSurfacePath } from "./pathPatterns.js";
2
3
  function methodsForPath(path) {
3
4
  const normalized = path.toLowerCase();
4
5
  if (normalized.includes("api") || normalized.includes("route")) {
@@ -15,13 +16,7 @@ export function buildSurfaceManifest(repoManifest, disposition) {
15
16
  continue;
16
17
  }
17
18
  const normalized = file.path.toLowerCase();
18
- if (normalized.includes("api/") ||
19
- normalized.includes("route") ||
20
- normalized.includes("controller") ||
21
- normalized.includes("worker") ||
22
- normalized.includes("job") ||
23
- normalized.includes("command") ||
24
- normalized.includes("cli")) {
19
+ if (isSurfacePath(normalized)) {
25
20
  surfaces.push({
26
21
  id: `surface:${file.path}`,
27
22
  kind: normalized.includes("worker") || normalized.includes("job")
@@ -32,7 +32,29 @@ export interface ArtifactBundle {
32
32
  audit_state?: AuditState;
33
33
  artifact_metadata?: ArtifactMetadataManifest;
34
34
  }
35
- export declare const ARTIFACT_FILE_TO_BUNDLE_KEY: Record<string, keyof ArtifactBundle>;
35
+ export declare const ARTIFACT_FILE_TO_BUNDLE_KEY: {
36
+ readonly "repo_manifest.json": "repo_manifest";
37
+ readonly "file_disposition.json": "file_disposition";
38
+ readonly "auto_fixes_applied.json": "auto_fixes_applied";
39
+ readonly "unit_manifest.json": "unit_manifest";
40
+ readonly "graph_bundle.json": "graph_bundle";
41
+ readonly "surface_manifest.json": "surface_manifest";
42
+ readonly "critical_flows.json": "critical_flows";
43
+ readonly "flow_coverage.json": "flow_coverage";
44
+ readonly "risk_register.json": "risk_register";
45
+ readonly "coverage_matrix.json": "coverage_matrix";
46
+ readonly "runtime_validation_tasks.json": "runtime_validation_tasks";
47
+ readonly "runtime_validation_report.json": "runtime_validation_report";
48
+ readonly "external_analyzer_results.json": "external_analyzer_results";
49
+ readonly "audit_results.jsonl": "audit_results";
50
+ readonly "audit_tasks.json": "audit_tasks";
51
+ readonly "requeue_tasks.json": "requeue_tasks";
52
+ readonly "merged_findings.json": "merged_findings";
53
+ readonly "root_cause_clusters.json": "root_cause_clusters";
54
+ readonly "synthesis_report.json": "synthesis_report";
55
+ readonly "audit_state.json": "audit_state";
56
+ readonly "artifact_metadata.json": "artifact_metadata";
57
+ };
36
58
  export declare function getArtifactValue(bundle: ArtifactBundle, artifactName: string): unknown;
37
59
  export declare function loadArtifactBundle(root: string): Promise<ArtifactBundle>;
38
60
  export declare function writeCoreArtifacts(root: string, bundle: ArtifactBundle): Promise<void>;
@@ -22,8 +22,10 @@ export const ARTIFACT_FILE_TO_BUNDLE_KEY = {
22
22
  "audit_state.json": "audit_state",
23
23
  "artifact_metadata.json": "artifact_metadata",
24
24
  };
25
+ const _bundleKeyCoverage = true;
25
26
  export function getArtifactValue(bundle, artifactName) {
26
- const key = ARTIFACT_FILE_TO_BUNDLE_KEY[artifactName];
27
+ const map = ARTIFACT_FILE_TO_BUNDLE_KEY;
28
+ const key = map[artifactName];
27
29
  return key ? bundle[key] : undefined;
28
30
  }
29
31
  export async function loadArtifactBundle(root) {
@@ -3,7 +3,7 @@ import { join } from "node:path";
3
3
  import { writeJsonFile } from "./json.js";
4
4
  export function buildRunId(obligationId, index) {
5
5
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
6
- const obligation = obligationId ?? "terminal";
6
+ const obligation = (obligationId ?? "terminal").replace(/[^a-zA-Z0-9_-]/g, "-");
7
7
  return `${timestamp}_${obligation}_${String(index).padStart(3, "0")}`;
8
8
  }
9
9
  export function getRunPaths(artifactsDir, runId) {
@@ -13,7 +13,7 @@ export async function advanceAudit(bundle, options = {}) {
13
13
  : decision.selected_obligation;
14
14
  if (!selectedExecutor) {
15
15
  const state = deriveAuditState(bundle);
16
- state.last_executor = selectedExecutor ?? undefined;
16
+ // Do not overwrite last_executor when no executor was selected — preserve prior value
17
17
  state.last_obligation = selectedObligation ?? undefined;
18
18
  return {
19
19
  audit_state: state,
@@ -1,3 +1,3 @@
1
1
  import type { AuditTask } 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 declare function buildFlowAwareTaskAugmentations(existingTasks: AuditTask[], criticalFlows: CriticalFlowManifest, _lineIndex: Record<string, number>): AuditTask[];
@@ -3,39 +3,32 @@ const DEFAULT_FLOW_LENS_PRIORITY = [
3
3
  "reliability",
4
4
  "correctness",
5
5
  ];
6
- function normalizeTaskSignature(task) {
7
- const path = task.file_paths.join(",");
8
- const range = task.line_ranges?.map((r) => `${r.path}:${r.start}-${r.end}`).join(",") ??
9
- "full";
10
- return `${task.lens}|${path}|${range}`;
11
- }
12
- export function buildFlowAwareTaskAugmentations(existingTasks, criticalFlows, lineIndex) {
6
+ export function buildFlowAwareTaskAugmentations(existingTasks, criticalFlows, _lineIndex) {
13
7
  const seenTaskIds = new Set(existingTasks.map((task) => task.task_id));
14
- const existingSignatures = new Set(existingTasks.map(normalizeTaskSignature));
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(",")}`));
15
11
  const extraTasks = [];
16
12
  for (const flow of criticalFlows.flows) {
17
13
  const desiredLenses = flow.concerns.filter((concern) => DEFAULT_FLOW_LENS_PRIORITY.includes(concern));
18
- for (const path of flow.paths) {
19
- const totalLines = lineIndex[path] ?? 0;
20
- for (const lens of desiredLenses) {
21
- const candidate = {
22
- task_id: `flow:${flow.id}:${lens}:${path}`,
23
- unit_id: `flow:${flow.id}`,
24
- pass_id: `flow-pass:${lens}`,
25
- lens,
26
- file_paths: [path],
27
- line_ranges: totalLines > 0 ? [{ path, start: 1, end: totalLines }] : undefined,
28
- rationale: `Flow-aware audit for ${path} because it participates in critical flow ${flow.id} under the ${lens} lens.`,
29
- };
30
- const signature = normalizeTaskSignature(candidate);
31
- if (seenTaskIds.has(candidate.task_id) ||
32
- existingSignatures.has(signature)) {
33
- continue;
34
- }
35
- extraTasks.push(candidate);
36
- seenTaskIds.add(candidate.task_id);
37
- existingSignatures.add(signature);
14
+ 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)) {
20
+ continue;
38
21
  }
22
+ extraTasks.push({
23
+ task_id: taskId,
24
+ unit_id: `flow:${flow.id}`,
25
+ pass_id: `flow-pass:${lens}`,
26
+ 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.`,
29
+ });
30
+ seenTaskIds.add(taskId);
31
+ existingSignatures.add(signature);
39
32
  }
40
33
  }
41
34
  return extraTasks;
@@ -87,7 +87,6 @@ export function runPlanningExecutor(bundle, lineIndex = {}) {
87
87
  const runtimeValidationTasks = buildRuntimeValidationTasks(bundle.unit_manifest, bundle.critical_flows, flowCoverage);
88
88
  const runtimeValidationReport = preserveOrPlaceholder(runtimeValidationTasks, bundle.runtime_validation_report);
89
89
  const baseTasks = buildChunkedAuditTasks(bundle.unit_manifest, lineIndex, {
90
- chunk_size: 200,
91
90
  external_analyzer_results: externalAnalyzerResults,
92
91
  });
93
92
  const analyzerTasks = buildExternalSignalTasks(coverage, lineIndex, externalAnalyzerResults);
@@ -119,9 +118,9 @@ export function runResultIngestionExecutor(bundle, results) {
119
118
  if (!bundle.coverage_matrix) {
120
119
  throw new Error("Cannot ingest results without coverage_matrix");
121
120
  }
122
- ingestAuditResults(bundle.coverage_matrix, results);
121
+ const updatedCoverageMatrix = ingestAuditResults(bundle.coverage_matrix, results);
123
122
  const flowCoverage = bundle.critical_flows
124
- ? buildFlowCoverage(bundle.critical_flows, bundle.coverage_matrix)
123
+ ? buildFlowCoverage(bundle.critical_flows, updatedCoverageMatrix)
125
124
  : bundle.flow_coverage;
126
125
  const runtimeValidationTasks = bundle.unit_manifest
127
126
  ? buildRuntimeValidationTasks(bundle.unit_manifest, bundle.critical_flows, flowCoverage)
@@ -129,15 +128,13 @@ export function runResultIngestionExecutor(bundle, results) {
129
128
  const runtimeValidationReport = runtimeValidationTasks
130
129
  ? preserveOrPlaceholder(runtimeValidationTasks, bundle.runtime_validation_report)
131
130
  : bundle.runtime_validation_report;
132
- const requeuePayload = bundle.coverage_matrix
133
- ? buildRequeuePayload(bundle.coverage_matrix, bundle.critical_flows, flowCoverage, bundle.external_analyzer_results)
134
- : { tasks: [], task_count: 0 };
131
+ const requeuePayload = buildRequeuePayload(updatedCoverageMatrix, bundle.critical_flows, flowCoverage, bundle.external_analyzer_results);
135
132
  const mergedResults = [...(bundle.audit_results ?? []), ...results];
136
133
  const synthesisReport = buildSynthesisReport(mergedResults, runtimeValidationReport, bundle.external_analyzer_results);
137
134
  return {
138
135
  updated: {
139
136
  ...bundle,
140
- coverage_matrix: bundle.coverage_matrix,
137
+ coverage_matrix: updatedCoverageMatrix,
141
138
  flow_coverage: flowCoverage,
142
139
  runtime_validation_tasks: runtimeValidationTasks,
143
140
  runtime_validation_report: runtimeValidationReport,
@@ -1,27 +1,19 @@
1
1
  import { applyUnitCoverage, createCoverageMatrix, markExcludedPath, } from "../coverage.js";
2
2
  import { isAuditExcludedStatus } from "../extractors/disposition.js";
3
+ const CATEGORY_LENS_TABLE = [
4
+ [["security", "secret"], ["security", "correctness"]],
5
+ [["dependency", "vuln"], ["security", "config_deployment"]],
6
+ [["tests", "coverage"], ["tests"]],
7
+ [["data"], ["data_integrity", "correctness"]],
8
+ [["reliability", "concurrency"], ["reliability", "correctness"]],
9
+ [["maintainability", "lint", "style"], ["maintainability"]],
10
+ ];
3
11
  function analyzerCategoryToLenses(category) {
4
12
  const normalized = category.toLowerCase();
5
- if (normalized.includes("security") || normalized.includes("secret")) {
6
- return ["security", "correctness"];
7
- }
8
- if (normalized.includes("dependency") || normalized.includes("vuln")) {
9
- return ["security", "config_deployment"];
10
- }
11
- if (normalized.includes("tests") || normalized.includes("coverage")) {
12
- return ["tests"];
13
- }
14
- if (normalized.includes("data")) {
15
- return ["data_integrity", "correctness"];
16
- }
17
- if (normalized.includes("reliability") ||
18
- normalized.includes("concurrency")) {
19
- return ["reliability", "correctness"];
20
- }
21
- if (normalized.includes("maintainability") ||
22
- normalized.includes("lint") ||
23
- normalized.includes("style")) {
24
- return ["maintainability"];
13
+ for (const [keywords, lenses] of CATEGORY_LENS_TABLE) {
14
+ if (keywords.some((kw) => normalized.includes(kw))) {
15
+ return lenses;
16
+ }
25
17
  }
26
18
  return ["correctness"];
27
19
  }
@@ -1,5 +1,6 @@
1
1
  import { applyReviewedRanges } from "../coverage.js";
2
2
  export function ingestAuditResults(coverageMatrix, results) {
3
+ const matrix = JSON.parse(JSON.stringify(coverageMatrix));
3
4
  const reviewedRanges = results.flatMap((result) => result.reviewed_ranges.map((range) => ({
4
5
  path: range.path,
5
6
  start: range.start,
@@ -8,6 +9,6 @@ export function ingestAuditResults(coverageMatrix, results) {
8
9
  lens: result.lens,
9
10
  agent_role: result.agent_role,
10
11
  })));
11
- applyReviewedRanges(coverageMatrix, reviewedRanges);
12
- return coverageMatrix;
12
+ applyReviewedRanges(matrix, reviewedRanges);
13
+ return matrix;
13
14
  }
@@ -63,6 +63,11 @@ export function buildRuntimeValidationTasks(unitManifest, criticalFlows, flowCov
63
63
  });
64
64
  }
65
65
  }
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
+ }
66
71
  return { tasks };
67
72
  }
68
73
  export function buildPlaceholderRuntimeValidationReport(tasks) {
@@ -20,12 +20,16 @@ function runTsc(root) {
20
20
  category: "correctness",
21
21
  severity: "error",
22
22
  path: match[1].replace(/\\/g, "/"),
23
+ line_start: parseInt(match[2], 10),
23
24
  summary: match[3],
24
25
  rule: "tsc",
25
26
  });
26
27
  }
27
28
  }
28
29
  }
30
+ else {
31
+ process.stderr.write(`[syntax-resolution] tsc exited with no stdout; stderr: ${(error.stderr?.toString() ?? "").slice(0, 200)}\n`);
32
+ }
29
33
  }
30
34
  return results;
31
35
  }
@@ -51,6 +55,7 @@ function runEslint(root) {
51
55
  path: fileResult.filePath
52
56
  .replace(/\\/g, "/")
53
57
  .replace(root.replace(/\\/g, "/") + "/", ""),
58
+ line_start: msg.line,
54
59
  summary: msg.message,
55
60
  rule: msg.ruleId || "eslint-error",
56
61
  });
@@ -58,9 +63,12 @@ function runEslint(root) {
58
63
  }
59
64
  }
60
65
  catch (e) {
61
- // failed to parse
66
+ process.stderr.write(`[syntax-resolution] eslint output could not be parsed: ${(error.stdout?.toString() ?? "").slice(0, 200)}\n`);
62
67
  }
63
68
  }
69
+ else {
70
+ process.stderr.write(`[syntax-resolution] eslint exited with no stdout; stderr: ${(error.stderr?.toString() ?? "").slice(0, 200)}\n`);
71
+ }
64
72
  }
65
73
  return results;
66
74
  }
@@ -78,7 +86,7 @@ export function runSyntaxResolutionExecutor(bundle, root) {
78
86
  const seen = new Set();
79
87
  const deduped = [];
80
88
  for (const r of merged) {
81
- const key = `${r.path}:${r.rule}:${r.summary}`;
89
+ const key = `${r.path}:${r.line_start ?? ""}:${r.rule}:${r.summary}`;
82
90
  if (!seen.has(key)) {
83
91
  seen.add(key);
84
92
  deduped.push(r);
@@ -4,9 +4,14 @@ export interface UnitLineIndex {
4
4
  [path: string]: number;
5
5
  }
6
6
  export interface BuildChunkedTaskOptions {
7
- chunk_size?: number;
7
+ /**
8
+ * Line count above which a single file gets its own task rather than being
9
+ * grouped with the rest of its unit. Default: 3000. Set to 0 to disable
10
+ * splitting entirely.
11
+ */
12
+ file_split_threshold?: number;
8
13
  limit_lenses?: Lens[];
9
14
  external_analyzer_results?: ExternalAnalyzerResults;
10
15
  }
11
16
  export declare function buildChunkedAuditTasks(unitManifest: UnitManifest, unitLineIndex: UnitLineIndex, options?: BuildChunkedTaskOptions): AuditTask[];
12
- export declare function buildExternalSignalTasks(coverageMatrix: CoverageMatrix, unitLineIndex: UnitLineIndex, externalAnalyzerResults?: ExternalAnalyzerResults): AuditTask[];
17
+ export declare function buildExternalSignalTasks(coverageMatrix: CoverageMatrix, _unitLineIndex: UnitLineIndex, externalAnalyzerResults?: ExternalAnalyzerResults): AuditTask[];