auditor-lambda 0.2.1 → 0.2.3

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 (62) hide show
  1. package/audit-code-wrapper-lib.mjs +229 -289
  2. package/dist/adapters/eslint.js +4 -2
  3. package/dist/adapters/npmAudit.js +1 -1
  4. package/dist/cli.js +82 -45
  5. package/dist/extractors/bucketing.js +14 -35
  6. package/dist/extractors/disposition.js +8 -9
  7. package/dist/extractors/fileInventory.js +0 -2
  8. package/dist/extractors/flows.js +14 -23
  9. package/dist/extractors/fsIntake.js +4 -1
  10. package/dist/extractors/pathPatterns.d.ts +19 -0
  11. package/dist/extractors/pathPatterns.js +91 -0
  12. package/dist/extractors/surfaces.js +2 -7
  13. package/dist/io/artifacts.d.ts +23 -1
  14. package/dist/io/artifacts.js +4 -3
  15. package/dist/io/runArtifacts.js +1 -1
  16. package/dist/orchestrator/advance.js +53 -71
  17. package/dist/orchestrator/flowCoverage.js +1 -2
  18. package/dist/orchestrator/internalExecutors.js +4 -6
  19. package/dist/orchestrator/planning.js +12 -20
  20. package/dist/orchestrator/resultIngestion.js +3 -2
  21. package/dist/orchestrator/runtimeValidation.js +5 -0
  22. package/dist/orchestrator/syntaxResolutionExecutor.js +10 -2
  23. package/dist/orchestrator/taskBuilder.js +15 -28
  24. package/dist/prompts/renderWorkerPrompt.js +2 -1
  25. package/dist/providers/claudeCodeProvider.js +1 -2
  26. package/dist/providers/constants.d.ts +1 -0
  27. package/dist/providers/constants.js +1 -0
  28. package/dist/providers/index.js +7 -3
  29. package/dist/providers/opencodeProvider.js +1 -6
  30. package/dist/providers/spawnLoggedCommand.js +4 -0
  31. package/dist/providers/types.d.ts +0 -1
  32. package/dist/supervisor/operatorHandoff.d.ts +2 -0
  33. package/dist/supervisor/operatorHandoff.js +21 -9
  34. package/dist/supervisor/runLedger.js +7 -8
  35. package/dist/supervisor/sessionConfig.js +1 -0
  36. package/dist/types/flowCoverage.d.ts +1 -1
  37. package/dist/types/runLedger.d.ts +1 -1
  38. package/dist/types/runtimeValidation.d.ts +2 -1
  39. package/dist/types/sessionConfig.d.ts +0 -6
  40. package/dist/types/surfaces.d.ts +2 -1
  41. package/dist/types/workerSession.d.ts +2 -0
  42. package/dist/types.d.ts +0 -1
  43. package/dist/validation/sessionConfig.js +1 -15
  44. package/package.json +1 -1
  45. package/schemas/audit-code-v1alpha1.schema.json +4 -0
  46. package/schemas/audit_result.schema.json +9 -3
  47. package/schemas/audit_state.schema.json +2 -2
  48. package/schemas/audit_task.schema.json +14 -3
  49. package/schemas/blind_spot_register.schema.json +13 -3
  50. package/schemas/coverage_matrix.schema.json +16 -4
  51. package/schemas/critical_flows.schema.json +6 -3
  52. package/schemas/external_analyzer_results.schema.json +10 -4
  53. package/schemas/finding.schema.json +31 -3
  54. package/schemas/flow_coverage.schema.json +12 -3
  55. package/schemas/graph_bundle.schema.json +12 -6
  56. package/schemas/merged_findings.schema.json +7 -2
  57. package/schemas/risk_register.schema.json +5 -1
  58. package/schemas/root_cause_clusters.schema.json +2 -1
  59. package/schemas/runtime_validation_tasks.schema.json +4 -1
  60. package/schemas/surface_manifest.schema.json +4 -1
  61. package/schemas/unit_manifest.schema.json +10 -3
  62. package/skills/audit-code/audit-code.prompt.md +0 -2
@@ -1,6 +1,8 @@
1
1
  import { mkdir, writeFile } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
3
  import { writeJsonFile } from "../io/json.js";
4
+ import { LOCAL_SUBPROCESS_PROVIDER_NAME } from "../providers/constants.js";
5
+ export const CONFIG_ERROR_BLOCKER_PREFIX = "config-error:";
4
6
  function quoteShellPath(path) {
5
7
  return `"${path.replace(/"/g, '\\"')}"`;
6
8
  }
@@ -23,8 +25,8 @@ function buildSummary(status, providerName, fallbackSummary) {
23
25
  ? `Automatic work can continue under ${providerName}. Re-run the same wrapper or inspect the listed artifacts if you need operator context.`
24
26
  : "Automatic work can continue. Re-run the same wrapper or inspect the listed artifacts if you need operator context.";
25
27
  }
26
- function buildSuggestedInputs(artifactsDir, status) {
27
- if (status !== "blocked") {
28
+ function buildSuggestedInputs(artifactsDir, status, isConfigError) {
29
+ if (status !== "blocked" || isConfigError) {
28
30
  return [];
29
31
  }
30
32
  const incomingDir = join(artifactsDir, "incoming");
@@ -52,11 +54,14 @@ function buildSuggestedCommands(suggestedInputs, status) {
52
54
  }
53
55
  return suggestedInputs.map((item) => `audit-code ${item.flag} ${quoteShellPath(item.suggested_path)}`);
54
56
  }
55
- function buildInteractiveProviderHint(status, providerName, sessionConfigPath) {
57
+ function buildInteractiveProviderHint(status, providerName, sessionConfigPath, isConfigError) {
56
58
  if (status !== "blocked") {
57
59
  return null;
58
60
  }
59
- const providerLabel = providerName ?? "local-subprocess";
61
+ if (isConfigError) {
62
+ return `A project configuration issue is blocking the audit. Verify that --root points to the repository root containing a project file (package.json, go.mod, etc.), then run audit-code again.`;
63
+ }
64
+ const providerLabel = providerName ?? LOCAL_SUBPROCESS_PROVIDER_NAME;
60
65
  return `Current provider is ${providerLabel}. If you want the backend to continue through an interactive provider instead of importing results manually, set "provider" in ${sessionConfigPath} to "auto", "claude-code", "opencode", "subprocess-template", or "vscode-task", then run audit-code again from the repository root.`;
61
66
  }
62
67
  function renderMarkdown(handoff) {
@@ -109,6 +114,7 @@ function renderMarkdown(handoff) {
109
114
  return lines.join("\n");
110
115
  }
111
116
  export function buildAuditCodeHandoff(params) {
117
+ const isConfigError = params.isConfigError ?? false;
112
118
  const incomingDir = join(params.artifactsDir, "incoming");
113
119
  const artifactPaths = {
114
120
  incoming_dir: incomingDir,
@@ -123,7 +129,7 @@ export function buildAuditCodeHandoff(params) {
123
129
  ? join(params.artifactsDir, "runtime_validation_tasks.json")
124
130
  : null,
125
131
  };
126
- const suggestedInputs = buildSuggestedInputs(params.artifactsDir, params.state.status);
132
+ const suggestedInputs = buildSuggestedInputs(params.artifactsDir, params.state.status, isConfigError);
127
133
  return {
128
134
  status: params.state.status,
129
135
  repo_root: params.root,
@@ -133,12 +139,18 @@ export function buildAuditCodeHandoff(params) {
133
139
  pending_obligations: buildPendingObligations(params.state),
134
140
  suggested_inputs: suggestedInputs,
135
141
  suggested_commands: buildSuggestedCommands(suggestedInputs, params.state.status),
136
- interactive_provider_hint: buildInteractiveProviderHint(params.state.status, params.providerName ?? null, artifactPaths.session_config),
142
+ interactive_provider_hint: buildInteractiveProviderHint(params.state.status, params.providerName ?? null, artifactPaths.session_config, isConfigError),
137
143
  artifact_paths: artifactPaths,
138
144
  };
139
145
  }
140
146
  export async function writeAuditCodeHandoffArtifacts(handoff) {
141
- await mkdir(handoff.artifact_paths.incoming_dir, { recursive: true });
142
- await writeJsonFile(handoff.artifact_paths.operator_handoff_json, handoff);
143
- await writeFile(handoff.artifact_paths.operator_handoff_markdown, renderMarkdown(handoff), "utf8");
147
+ try {
148
+ await mkdir(handoff.artifact_paths.incoming_dir, { recursive: true });
149
+ await writeJsonFile(handoff.artifact_paths.operator_handoff_json, handoff);
150
+ await writeFile(handoff.artifact_paths.operator_handoff_markdown, renderMarkdown(handoff), "utf8");
151
+ }
152
+ catch (error) {
153
+ const message = error instanceof Error ? error.message : String(error);
154
+ throw new Error(`Failed to write operator handoff artifacts: ${message}`);
155
+ }
144
156
  }
@@ -1,5 +1,4 @@
1
- import { rename, writeFile } from "node:fs/promises";
2
- import { readJsonFile } from "../io/json.js";
1
+ import { isFileMissingError, readJsonFile, writeJsonFile } from "../io/json.js";
3
2
  function ledgerPath(artifactsDir) {
4
3
  return `${artifactsDir}/run-ledger.json`;
5
4
  }
@@ -7,15 +6,15 @@ export async function loadRunLedger(artifactsDir) {
7
6
  try {
8
7
  return await readJsonFile(ledgerPath(artifactsDir));
9
8
  }
10
- catch {
11
- return { runs: [] };
9
+ catch (error) {
10
+ if (isFileMissingError(error)) {
11
+ return { runs: [] };
12
+ }
13
+ throw error;
12
14
  }
13
15
  }
14
16
  export async function appendRunLedgerEntry(artifactsDir, entry) {
15
17
  const ledger = await loadRunLedger(artifactsDir);
16
18
  ledger.runs.push(entry);
17
- const target = ledgerPath(artifactsDir);
18
- const tmp = `${target}.tmp`;
19
- await writeFile(tmp, JSON.stringify(ledger, null, 2) + "\n", "utf8");
20
- await rename(tmp, target);
19
+ await writeJsonFile(ledgerPath(artifactsDir), ledger);
21
20
  }
@@ -16,6 +16,7 @@ export async function loadSessionConfig(artifactsDir) {
16
16
  const configPath = getSessionConfigPath(artifactsDir);
17
17
  const rawConfig = await readOptionalJsonFile(configPath);
18
18
  if (rawConfig === undefined) {
19
+ process.stderr.write(`[session-config] no session-config.json found at ${configPath}; using empty defaults\n`);
19
20
  return {};
20
21
  }
21
22
  const issues = validateSessionConfig(rawConfig);
@@ -3,7 +3,7 @@ export interface FlowCoverageRecord {
3
3
  paths: string[];
4
4
  required_lenses: string[];
5
5
  completed_lenses: string[];
6
- status: string;
6
+ status: "pending" | "partial" | "complete";
7
7
  notes?: string[];
8
8
  }
9
9
  export interface FlowCoverageManifest {
@@ -3,7 +3,7 @@ export interface RunLedgerEntry {
3
3
  provider: string;
4
4
  obligation_id: string | null;
5
5
  selected_executor: string | null;
6
- status: string;
6
+ status: "completed" | "blocked" | "failed" | "no_progress";
7
7
  started_at: string;
8
8
  ended_at: string;
9
9
  result_path: string;
@@ -1,6 +1,7 @@
1
+ export type RuntimeValidationKind = "unit-risk-check" | "critical-flow-check";
1
2
  export interface RuntimeValidationTask {
2
3
  id: string;
3
- kind: string;
4
+ kind: RuntimeValidationKind;
4
5
  target_paths: string[];
5
6
  reason: string;
6
7
  priority: "high" | "medium" | "low";
@@ -16,11 +16,6 @@ export interface VSCodeTaskConfig {
16
16
  command_template: string[];
17
17
  env?: Record<string, string>;
18
18
  }
19
- export interface ModelTiersConfig {
20
- fast?: string;
21
- balanced?: string;
22
- capable?: string;
23
- }
24
19
  export interface SessionConfig {
25
20
  provider?: ProviderName;
26
21
  timeout_ms?: number;
@@ -31,5 +26,4 @@ export interface SessionConfig {
31
26
  vscode_task?: VSCodeTaskConfig;
32
27
  agent_task_batch_size?: number;
33
28
  parallel_workers?: number;
34
- model_tiers?: ModelTiersConfig;
35
29
  }
@@ -1,6 +1,7 @@
1
+ export type SurfaceKind = "interface" | "background";
1
2
  export interface SurfaceRecord {
2
3
  id: string;
3
- kind: string;
4
+ kind: SurfaceKind;
4
5
  entrypoint: string;
5
6
  exposure?: string;
6
7
  methods?: string[];
@@ -12,4 +12,6 @@ export interface WorkerTask {
12
12
  runtime_updates_path?: string;
13
13
  external_analyzer_results_path?: string;
14
14
  skip_worker_command?: boolean;
15
+ timeout_ms?: number;
16
+ max_retries?: number;
15
17
  }
package/dist/types.d.ts CHANGED
@@ -62,7 +62,6 @@ export interface AuditTask {
62
62
  rationale: string;
63
63
  priority?: "high" | "medium" | "low";
64
64
  tags?: string[];
65
- model_hint?: "fast" | "balanced" | "capable";
66
65
  }
67
66
  export interface Finding {
68
67
  id: string;
@@ -71,8 +71,7 @@ function validateAgentProviderSection(value, path, issues) {
71
71
  return;
72
72
  }
73
73
  if (value.command !== undefined) {
74
- if (typeof value.command !== "string" ||
75
- value.command.trim().length === 0) {
74
+ if (typeof value.command !== "string" || value.command.trim().length === 0) {
76
75
  pushIssue(issues, `${path}.command`, "command must be a non-empty string when provided.");
77
76
  }
78
77
  }
@@ -118,19 +117,6 @@ export function validateSessionConfig(value) {
118
117
  validateTemplateProviderSection(value.vscode_task, "vscode_task", issues, provider === "vscode-task");
119
118
  validateAgentProviderSection(value.claude_code, "claude_code", issues);
120
119
  validateAgentProviderSection(value.opencode, "opencode", issues);
121
- if (value.model_tiers !== undefined) {
122
- if (!isRecord(value.model_tiers)) {
123
- pushIssue(issues, "model_tiers", "model_tiers must be a JSON object.");
124
- }
125
- else {
126
- for (const tier of ["fast", "balanced", "capable"]) {
127
- const v = value.model_tiers[tier];
128
- if (v !== undefined && (typeof v !== "string" || v.trim().length === 0)) {
129
- pushIssue(issues, `model_tiers.${tier}`, `model_tiers.${tier} must be a non-empty string when provided.`);
130
- }
131
- }
132
- }
133
- }
134
120
  return issues;
135
121
  }
136
122
  export function validateConfiguredProviderEnvironment(sessionConfig, options = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auditor-lambda",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "private": false,
5
5
  "description": "Portable hybrid code-auditing framework for arbitrary repositories.",
6
6
  "type": "module",
@@ -24,6 +24,7 @@
24
24
  "required": ["status", "obligations"],
25
25
  "properties": {
26
26
  "status": {
27
+ "type": "string",
27
28
  "enum": ["not_started", "active", "blocked", "complete"]
28
29
  },
29
30
  "last_executor": {
@@ -49,6 +50,7 @@
49
50
  "type": "string"
50
51
  },
51
52
  "state": {
53
+ "type": "string",
52
54
  "enum": ["missing", "present", "stale", "blocked", "satisfied"]
53
55
  },
54
56
  "reason": {
@@ -97,6 +99,7 @@
97
99
  ],
98
100
  "properties": {
99
101
  "status": {
102
+ "type": "string",
100
103
  "enum": ["not_started", "active", "blocked", "complete"]
101
104
  },
102
105
  "repo_root": {
@@ -125,6 +128,7 @@
125
128
  "required": ["flag", "suggested_path", "description"],
126
129
  "properties": {
127
130
  "flag": {
131
+ "type": "string",
128
132
  "enum": [
129
133
  "--results",
130
134
  "--updates",
@@ -11,14 +11,20 @@
11
11
  "reviewed_ranges",
12
12
  "findings"
13
13
  ],
14
+ "$defs": {
15
+ "Finding": {
16
+ "$ref": "finding.schema.json"
17
+ }
18
+ },
14
19
  "properties": {
15
20
  "task_id": { "type": "string" },
16
21
  "unit_id": { "type": "string" },
17
22
  "pass_id": { "type": "string" },
18
- "lens": { "type": "string", "enum": ["correctness", "architecture", "maintainability", "security", "reliability", "performance", "data_integrity", "tests", "operability", "config_deployment"] },
23
+ "lens": { "type": "string" },
19
24
  "agent_role": { "type": "string" },
20
25
  "reviewed_ranges": {
21
26
  "type": "array",
27
+ "minItems": 1,
22
28
  "items": {
23
29
  "type": "object",
24
30
  "required": ["path", "start", "end"],
@@ -32,7 +38,7 @@
32
38
  },
33
39
  "findings": {
34
40
  "type": "array",
35
- "items": { "$ref": "finding.schema.json" }
41
+ "items": { "$ref": "#/$defs/Finding" }
36
42
  },
37
43
  "notes": {
38
44
  "type": "array",
@@ -44,5 +50,5 @@
44
50
  "items": { "type": "string" }
45
51
  }
46
52
  },
47
- "additionalProperties": true
53
+ "additionalProperties": false
48
54
  }
@@ -28,9 +28,9 @@
28
28
  },
29
29
  "reason": { "type": "string" }
30
30
  },
31
- "additionalProperties": true
31
+ "additionalProperties": false
32
32
  }
33
33
  }
34
34
  },
35
- "additionalProperties": true
35
+ "additionalProperties": false
36
36
  }
@@ -15,7 +15,10 @@
15
15
  "task_id": { "type": "string" },
16
16
  "unit_id": { "type": "string" },
17
17
  "pass_id": { "type": "string" },
18
- "lens": { "type": "string", "enum": ["correctness", "architecture", "maintainability", "security", "reliability", "performance", "data_integrity", "tests", "operability", "config_deployment"] },
18
+ "lens": {
19
+ "type": "string",
20
+ "enum": ["correctness", "architecture", "maintainability", "security", "reliability", "performance", "data_integrity", "tests", "operability", "config_deployment"]
21
+ },
19
22
  "file_paths": {
20
23
  "type": "array",
21
24
  "items": { "type": "string" }
@@ -43,7 +46,15 @@
43
46
  },
44
47
  "additionalProperties": true
45
48
  },
46
- "rationale": { "type": "string" }
49
+ "rationale": { "type": "string" },
50
+ "priority": {
51
+ "type": "string",
52
+ "enum": ["high", "medium", "low"]
53
+ },
54
+ "tags": {
55
+ "type": "array",
56
+ "items": { "type": "string" }
57
+ }
47
58
  },
48
- "additionalProperties": true
59
+ "additionalProperties": false
49
60
  }
@@ -13,7 +13,17 @@
13
13
  "properties": {
14
14
  "id": { "type": "string" },
15
15
  "title": { "type": "string" },
16
- "kind": { "type": "string" },
16
+ "kind": {
17
+ "type": "string",
18
+ "enum": [
19
+ "coverage-gap",
20
+ "trust-boundary",
21
+ "dynamic-behavior",
22
+ "operational-risk",
23
+ "documentation-drift",
24
+ "external-dependency"
25
+ ]
26
+ },
17
27
  "summary": { "type": "string" },
18
28
  "affected_paths": {
19
29
  "type": "array",
@@ -32,9 +42,9 @@
32
42
  "items": { "type": "string" }
33
43
  }
34
44
  },
35
- "additionalProperties": true
45
+ "additionalProperties": false
36
46
  }
37
47
  }
38
48
  },
39
- "additionalProperties": true
49
+ "additionalProperties": false
40
50
  }
@@ -16,15 +16,27 @@
16
16
  "type": "array",
17
17
  "items": { "type": "string" }
18
18
  },
19
- "classification_status": { "type": "string" },
20
- "audit_status": { "type": "string" },
19
+ "classification_status": {
20
+ "type": "string",
21
+ "enum": ["unclassified", "classified", "excluded", "generated", "vendor", "binary", "doc_only"]
22
+ },
23
+ "audit_status": {
24
+ "type": "string",
25
+ "enum": ["pending", "partial", "complete", "excluded"]
26
+ },
21
27
  "required_lenses": {
22
28
  "type": "array",
23
- "items": { "type": "string" }
29
+ "items": {
30
+ "type": "string",
31
+ "enum": ["correctness", "architecture", "maintainability", "security", "reliability", "performance", "data_integrity", "tests", "operability", "config_deployment"]
32
+ }
24
33
  },
25
34
  "completed_lenses": {
26
35
  "type": "array",
27
- "items": { "type": "string" }
36
+ "items": {
37
+ "type": "string",
38
+ "enum": ["correctness", "architecture", "maintainability", "security", "reliability", "performance", "data_integrity", "tests", "operability", "config_deployment"]
39
+ }
28
40
  }
29
41
  },
30
42
  "additionalProperties": true
@@ -15,15 +15,18 @@
15
15
  "name": { "type": "string" },
16
16
  "entrypoints": {
17
17
  "type": "array",
18
- "items": { "type": "string" }
18
+ "items": { "type": "string" },
19
+ "minItems": 1
19
20
  },
20
21
  "paths": {
21
22
  "type": "array",
22
- "items": { "type": "string" }
23
+ "items": { "type": "string" },
24
+ "minItems": 1
23
25
  },
24
26
  "concerns": {
25
27
  "type": "array",
26
- "items": { "type": "string" }
28
+ "items": { "type": "string" },
29
+ "minItems": 1
27
30
  },
28
31
  "notes": {
29
32
  "type": "array",
@@ -14,8 +14,14 @@
14
14
  "required": ["id", "category", "severity", "path", "summary"],
15
15
  "properties": {
16
16
  "id": { "type": "string" },
17
- "category": { "type": "string" },
18
- "severity": { "type": "string" },
17
+ "category": {
18
+ "type": "string",
19
+ "description": "Free-form category string from the originating tool (e.g. 'security/injection', 'style/lint'). Mapped to audit lenses by analyzerCategoryToLenses."
20
+ },
21
+ "severity": {
22
+ "type": "string",
23
+ "enum": ["critical", "high", "medium", "low", "info"]
24
+ },
19
25
  "path": { "type": "string" },
20
26
  "line_start": { "type": "integer" },
21
27
  "line_end": { "type": "integer" },
@@ -23,9 +29,9 @@
23
29
  "rule": { "type": "string" },
24
30
  "raw": {}
25
31
  },
26
- "additionalProperties": true
32
+ "additionalProperties": false
27
33
  }
28
34
  }
29
35
  },
30
- "additionalProperties": true
36
+ "additionalProperties": false
31
37
  }
@@ -16,13 +16,41 @@
16
16
  "properties": {
17
17
  "id": { "type": "string" },
18
18
  "title": { "type": "string" },
19
- "category": { "type": "string" },
19
+ "category": {
20
+ "type": "string",
21
+ "enum": [
22
+ "correctness",
23
+ "architecture",
24
+ "maintainability",
25
+ "security",
26
+ "reliability",
27
+ "performance",
28
+ "data_integrity",
29
+ "tests",
30
+ "operability",
31
+ "config_deployment"
32
+ ]
33
+ },
20
34
  "severity": {
21
35
  "type": "string",
22
36
  "enum": ["critical", "high", "medium", "low", "info"]
23
37
  },
24
38
  "confidence": { "type": "string", "enum": ["high", "medium", "low"] },
25
- "lens": { "type": "string", "enum": ["correctness", "architecture", "maintainability", "security", "reliability", "performance", "data_integrity", "tests", "operability", "config_deployment"] },
39
+ "lens": {
40
+ "type": "string",
41
+ "enum": [
42
+ "correctness",
43
+ "architecture",
44
+ "maintainability",
45
+ "security",
46
+ "reliability",
47
+ "performance",
48
+ "data_integrity",
49
+ "tests",
50
+ "operability",
51
+ "config_deployment"
52
+ ]
53
+ },
26
54
  "summary": { "type": "string" },
27
55
  "affected_files": {
28
56
  "type": "array",
@@ -35,7 +63,7 @@
35
63
  "line_end": { "type": "integer" },
36
64
  "symbol": { "type": "string" }
37
65
  },
38
- "additionalProperties": true
66
+ "additionalProperties": false
39
67
  }
40
68
  },
41
69
  "impact": { "type": "string" },
@@ -24,13 +24,22 @@
24
24
  },
25
25
  "required_lenses": {
26
26
  "type": "array",
27
- "items": { "type": "string" }
27
+ "items": {
28
+ "type": "string",
29
+ "enum": ["correctness", "architecture", "maintainability", "security", "reliability", "performance", "data_integrity", "tests", "operability", "config_deployment"]
30
+ }
28
31
  },
29
32
  "completed_lenses": {
30
33
  "type": "array",
31
- "items": { "type": "string" }
34
+ "items": {
35
+ "type": "string",
36
+ "enum": ["correctness", "architecture", "maintainability", "security", "reliability", "performance", "data_integrity", "tests", "operability", "config_deployment"]
37
+ }
38
+ },
39
+ "status": {
40
+ "type": "string",
41
+ "enum": ["pending", "partial", "complete"]
32
42
  },
33
- "status": { "type": "string" },
34
43
  "notes": {
35
44
  "type": "array",
36
45
  "items": { "type": "string" }
@@ -16,9 +16,12 @@
16
16
  "properties": {
17
17
  "from": { "type": "string" },
18
18
  "to": { "type": "string" },
19
- "kind": { "type": "string" }
19
+ "kind": {
20
+ "type": "string",
21
+ "description": "Import edge kind from the graph extractor (e.g. 'esm', 'commonjs', 'dynamic', 're-export')."
22
+ }
20
23
  },
21
- "additionalProperties": true
24
+ "additionalProperties": false
22
25
  }
23
26
  },
24
27
  "calls": {
@@ -29,9 +32,12 @@
29
32
  "properties": {
30
33
  "from": { "type": "string" },
31
34
  "to": { "type": "string" },
32
- "kind": { "type": "string" }
35
+ "kind": {
36
+ "type": "string",
37
+ "description": "Call edge kind from the graph extractor (e.g. 'sync', 'async', 'constructor', 'callback')."
38
+ }
33
39
  },
34
- "additionalProperties": true
40
+ "additionalProperties": false
35
41
  }
36
42
  },
37
43
  "routes": {
@@ -44,12 +50,12 @@
44
50
  "handler": { "type": "string" },
45
51
  "method": { "type": "string" }
46
52
  },
47
- "additionalProperties": true
53
+ "additionalProperties": false
48
54
  }
49
55
  }
50
56
  },
51
57
  "additionalProperties": true
52
58
  }
53
59
  },
54
- "additionalProperties": true
60
+ "additionalProperties": false
55
61
  }
@@ -4,11 +4,16 @@
4
4
  "title": "Merged Findings",
5
5
  "type": "object",
6
6
  "required": ["findings"],
7
+ "$defs": {
8
+ "Finding": {
9
+ "$ref": "finding.schema.json"
10
+ }
11
+ },
7
12
  "properties": {
8
13
  "findings": {
9
14
  "type": "array",
10
- "items": { "$ref": "finding.schema.json" }
15
+ "items": { "$ref": "#/$defs/Finding" }
11
16
  }
12
17
  },
13
- "additionalProperties": true
18
+ "additionalProperties": false
14
19
  }
@@ -12,7 +12,11 @@
12
12
  "required": ["unit_id", "risk_score", "signals"],
13
13
  "properties": {
14
14
  "unit_id": { "type": "string" },
15
- "risk_score": { "type": "number" },
15
+ "risk_score": {
16
+ "type": "number",
17
+ "minimum": 0,
18
+ "maximum": 1
19
+ },
16
20
  "signals": {
17
21
  "type": "array",
18
22
  "items": { "type": "string" }
@@ -16,7 +16,8 @@
16
16
  "summary": { "type": "string" },
17
17
  "finding_ids": {
18
18
  "type": "array",
19
- "items": { "type": "string" }
19
+ "items": { "type": "string" },
20
+ "minItems": 1
20
21
  }
21
22
  },
22
23
  "additionalProperties": true
@@ -12,7 +12,10 @@
12
12
  "required": ["id", "kind", "target_paths", "reason", "priority"],
13
13
  "properties": {
14
14
  "id": { "type": "string" },
15
- "kind": { "type": "string" },
15
+ "kind": {
16
+ "type": "string",
17
+ "enum": ["unit-risk-check", "critical-flow-check"]
18
+ },
16
19
  "target_paths": {
17
20
  "type": "array",
18
21
  "items": { "type": "string" }