auditor-lambda 0.10.3 → 0.10.7
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.
- package/audit-code-wrapper-build.mjs +198 -0
- package/audit-code-wrapper-install-hosts.mjs +1140 -0
- package/audit-code-wrapper-io.mjs +155 -0
- package/audit-code-wrapper-legacy.mjs +125 -0
- package/audit-code-wrapper-lib.mjs +17 -1801
- package/audit-code-wrapper-opencode.mjs +256 -0
- package/dispatch/merge-results.mjs +5 -3
- package/dispatch/validate-result.mjs +2 -2
- package/dist/adapters/coverageSummary.js +6 -2
- package/dist/adapters/normalizeExternal.js +16 -1
- package/dist/adapters/npmAudit.js +20 -9
- package/dist/adapters/semgrep.js +26 -1
- package/dist/cli/advanceAuditCommand.d.ts +1 -0
- package/dist/cli/advanceAuditCommand.js +95 -0
- package/dist/cli/args.js +1 -2
- package/dist/cli/auditStep.js +2 -2
- package/dist/cli/cleanup.d.ts +11 -1
- package/dist/cli/cleanup.js +25 -5
- package/dist/cli/cleanupCommand.d.ts +1 -0
- package/dist/cli/cleanupCommand.js +24 -0
- package/dist/cli/dispatch.d.ts +55 -31
- package/dist/cli/dispatch.js +298 -241
- package/dist/cli/dispatchStatusCommand.d.ts +1 -0
- package/dist/cli/dispatchStatusCommand.js +68 -0
- package/dist/cli/explainTaskCommand.d.ts +1 -0
- package/dist/cli/explainTaskCommand.js +33 -0
- package/dist/cli/importExternalAnalyzerCommand.d.ts +1 -0
- package/dist/cli/importExternalAnalyzerCommand.js +20 -0
- package/dist/cli/ingestResultsCommand.d.ts +1 -0
- package/dist/cli/ingestResultsCommand.js +34 -0
- package/dist/cli/intakeCommand.d.ts +1 -0
- package/dist/cli/intakeCommand.js +17 -0
- package/dist/cli/lineIndex.js +19 -12
- package/dist/cli/nextStepCommand.d.ts +139 -0
- package/dist/cli/nextStepCommand.js +281 -232
- package/dist/cli/planCommand.d.ts +1 -0
- package/dist/cli/planCommand.js +16 -0
- package/dist/cli/prepareDispatchCommand.d.ts +1 -0
- package/dist/cli/prepareDispatchCommand.js +25 -0
- package/dist/cli/quotaCommand.d.ts +1 -0
- package/dist/cli/quotaCommand.js +56 -0
- package/dist/cli/requeueCommand.d.ts +1 -0
- package/dist/cli/requeueCommand.js +10 -0
- package/dist/cli/runToCompletion.js +451 -412
- package/dist/cli/sampleRunCommand.d.ts +1 -0
- package/dist/cli/sampleRunCommand.js +93 -0
- package/dist/cli/statusCommand.js +1 -1
- package/dist/cli/steps.js +4 -1
- package/dist/cli/submitPacketCommand.js +16 -15
- package/dist/cli/synthesizeCommand.d.ts +1 -0
- package/dist/cli/synthesizeCommand.js +15 -0
- package/dist/cli/updateRuntimeValidationCommand.d.ts +1 -0
- package/dist/cli/updateRuntimeValidationCommand.js +16 -0
- package/dist/cli/validateCommand.d.ts +1 -0
- package/dist/cli/validateCommand.js +41 -0
- package/dist/cli/validateResultCommand.d.ts +1 -0
- package/dist/cli/validateResultCommand.js +63 -0
- package/dist/cli/validateResultsCommand.d.ts +1 -0
- package/dist/cli/validateResultsCommand.js +31 -0
- package/dist/cli/workerRunCommand.d.ts +15 -1
- package/dist/cli/workerRunCommand.js +40 -4
- package/dist/cli.d.ts +3 -2
- package/dist/cli.js +21 -628
- package/dist/coverage.js +7 -3
- package/dist/extractors/analyzers/css.js +2 -2
- package/dist/extractors/analyzers/html.js +2 -2
- package/dist/extractors/analyzers/python.js +2 -2
- package/dist/extractors/analyzers/registry.js +17 -36
- package/dist/extractors/analyzers/treeSitter.d.ts +10 -1
- package/dist/extractors/analyzers/treeSitter.js +28 -6
- package/dist/extractors/analyzers/typescript.js +104 -85
- package/dist/extractors/browserExtension.js +4 -1
- package/dist/extractors/designAssessment.js +21 -21
- package/dist/extractors/fsIntake.js +34 -10
- package/dist/extractors/graph.js +17 -7
- package/dist/extractors/graphManifestEdges/cargo.d.ts +4 -0
- package/dist/extractors/graphManifestEdges/cargo.js +107 -0
- package/dist/extractors/graphManifestEdges/go.d.ts +5 -0
- package/dist/extractors/graphManifestEdges/go.js +151 -0
- package/dist/extractors/graphManifestEdges/index.d.ts +8 -0
- package/dist/extractors/graphManifestEdges/index.js +11 -0
- package/dist/extractors/graphManifestEdges/jsonc.d.ts +3 -0
- package/dist/extractors/graphManifestEdges/jsonc.js +97 -0
- package/dist/extractors/graphManifestEdges/maven.d.ts +3 -0
- package/dist/extractors/graphManifestEdges/maven.js +73 -0
- package/dist/extractors/graphManifestEdges/packageJson.d.ts +19 -0
- package/dist/extractors/graphManifestEdges/packageJson.js +204 -0
- package/dist/extractors/graphManifestEdges/pnpm.d.ts +2 -0
- package/dist/extractors/graphManifestEdges/pnpm.js +42 -0
- package/dist/extractors/graphManifestEdges/pyproject.d.ts +3 -0
- package/dist/extractors/graphManifestEdges/pyproject.js +83 -0
- package/dist/extractors/graphManifestEdges/toml.d.ts +4 -0
- package/dist/extractors/graphManifestEdges/toml.js +68 -0
- package/dist/extractors/graphManifestEdges/typescript.d.ts +3 -0
- package/dist/extractors/graphManifestEdges/typescript.js +56 -0
- package/dist/extractors/graphManifestEdges/workspace.d.ts +10 -0
- package/dist/extractors/graphManifestEdges/workspace.js +72 -0
- package/dist/extractors/graphManifestEdges/yaml.d.ts +3 -0
- package/dist/extractors/graphManifestEdges/yaml.js +59 -0
- package/dist/extractors/graphManifestEdges/yamlPaths.d.ts +4 -0
- package/dist/extractors/graphManifestEdges/yamlPaths.js +89 -0
- package/dist/extractors/graphPythonImports.js +4 -20
- package/dist/extractors/pathPatterns.js +3 -13
- package/dist/io/artifacts.d.ts +1 -1
- package/dist/io/artifacts.js +4 -1
- package/dist/io/runArtifacts.d.ts +8 -2
- package/dist/io/runArtifacts.js +103 -69
- package/dist/io/toolingManifest.js +2 -1
- package/dist/orchestrator/advance.js +36 -0
- package/dist/orchestrator/artifactFreshness.d.ts +1 -1
- package/dist/orchestrator/artifactFreshness.js +1 -1
- package/dist/orchestrator/artifactMetadata.js +5 -5
- package/dist/orchestrator/auditTaskUtils.d.ts +4 -0
- package/dist/orchestrator/auditTaskUtils.js +8 -12
- package/dist/orchestrator/autoFixExecutor.js +40 -26
- package/dist/orchestrator/dependencyMap.js +1 -1
- package/dist/orchestrator/executorResult.d.ts +33 -0
- package/dist/orchestrator/executors.d.ts +7 -0
- package/dist/orchestrator/executors.js +24 -0
- package/dist/orchestrator/fileAnchors.js +42 -29
- package/dist/orchestrator/fileIntegrity.js +6 -1
- package/dist/orchestrator/flowCoverage.js +1 -2
- package/dist/orchestrator/flowPlanning.js +8 -4
- package/dist/orchestrator/graphEnrichmentExecutor.js +67 -45
- package/dist/orchestrator/ingestionExecutors.js +9 -1
- package/dist/orchestrator/intakeExecutors.d.ts +0 -4
- package/dist/orchestrator/intakeExecutors.js +24 -14
- package/dist/orchestrator/localCommands.d.ts +1 -0
- package/dist/orchestrator/localCommands.js +10 -17
- package/dist/orchestrator/nextStep.js +3 -1
- package/dist/orchestrator/requeueCommand.js +4 -0
- package/dist/orchestrator/reviewPacketGraph.js +50 -18
- package/dist/orchestrator/reviewPackets.js +10 -8
- package/dist/orchestrator/runtimeCommand.js +35 -7
- package/dist/orchestrator/runtimeValidationUpdate.js +6 -0
- package/dist/orchestrator/selectiveDeepening/highRiskClean.js +3 -2
- package/dist/orchestrator/selectiveDeepening/lensVerification.js +44 -18
- package/dist/orchestrator/staleness.js +3 -3
- package/dist/orchestrator/state.js +1 -1
- package/dist/orchestrator/syntaxResolutionExecutor.js +17 -24
- package/dist/orchestrator/synthesisExecutors.js +1 -0
- package/dist/orchestrator/taskBuilder.js +5 -4
- package/dist/providers/claudeCodeProvider.js +4 -1
- package/dist/providers/opencodeProvider.js +4 -1
- package/dist/quota/discoveredLimits.js +3 -3
- package/dist/quota/headerExtraction.js +5 -2
- package/dist/quota/headerExtractors/claudeCodeHeaderExtractor.js +3 -0
- package/dist/quota/headerExtractors/index.js +3 -3
- package/dist/quota/index.d.ts +3 -1
- package/dist/quota/index.js +3 -0
- package/dist/reporting/findingRanks.d.ts +3 -0
- package/dist/reporting/findingRanks.js +24 -0
- package/dist/reporting/mergeFindings.js +1 -24
- package/dist/reporting/synthesis.d.ts +3 -1
- package/dist/reporting/synthesis.js +30 -6
- package/dist/reporting/synthesisNarrativePrompt.js +3 -0
- package/dist/reporting/workBlocks.js +1 -14
- package/dist/supervisor/operatorHandoff.js +2 -6
- package/dist/supervisor/runLedger.js +30 -41
- package/dist/types/activeDispatch.d.ts +31 -0
- package/dist/types/activeDispatch.js +2 -0
- package/dist/types.d.ts +21 -4
- package/dist/types.js +24 -16
- package/dist/validation/artifacts.js +3 -0
- package/dist/validation/auditResults.js +8 -2
- package/package.json +2 -2
- package/schemas/audit_findings.schema.json +5 -1
- package/schemas/audit_plan_metrics.schema.json +1 -1
- package/schemas/audit_result.schema.json +5 -6
- package/schemas/audit_task.schema.json +1 -4
- package/schemas/blind_spot_register.schema.json +1 -1
- package/schemas/coverage_matrix.schema.json +2 -8
- package/schemas/finding.schema.json +1 -16
- package/schemas/flow_coverage.schema.json +2 -8
- package/schemas/graph_bundle.schema.json +31 -0
- package/schemas/lens.schema.json +7 -0
- package/schemas/review_packets.schema.json +6 -17
- package/schemas/step_contract.schema.json +8 -2
- package/schemas/unit_manifest.schema.json +1 -4
- package/scripts/postinstall.mjs +3 -1
- package/skills/audit-code/audit-code.prompt.md +2 -3
- package/dist/extractors/graphManifestEdges.d.ts +0 -12
- package/dist/extractors/graphManifestEdges.js +0 -1135
|
@@ -131,6 +131,9 @@ function addTaskBlock(params, context) {
|
|
|
131
131
|
});
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
|
+
function withSignalTag(baseTags, hasExternalSignal) {
|
|
135
|
+
return hasExternalSignal ? [...baseTags, "external_analyzer_signal"] : baseTags;
|
|
136
|
+
}
|
|
134
137
|
function buildCoverageIndex(coverageMatrix) {
|
|
135
138
|
return new Map(coverageMatrix.files.map((file) => [file.path, file]));
|
|
136
139
|
}
|
|
@@ -206,9 +209,7 @@ export function buildChunkedAuditTasks(coverageMatrix, unitLineIndex, options =
|
|
|
206
209
|
lens: block.lens,
|
|
207
210
|
filePaths: block.file_paths,
|
|
208
211
|
priority: taskPriority(hasExternalSignal, block.lens, true),
|
|
209
|
-
tags: hasExternalSignal
|
|
210
|
-
? ["critical_flow", `critical_flow:${block.flow_id}`, "external_analyzer_signal"]
|
|
211
|
-
: ["critical_flow", `critical_flow:${block.flow_id}`],
|
|
212
|
+
tags: withSignalTag(["critical_flow", `critical_flow:${block.flow_id}`], hasExternalSignal),
|
|
212
213
|
rationale: (filePaths, splitKind) => splitKind === "large_file"
|
|
213
214
|
? `Audit ${filePaths[0]} (large file from critical flow ${block.flow_id}) under the ${block.lens} lens.${hasExternalSignal ? " External analyzer signals raise priority." : ""}`
|
|
214
215
|
: splitKind === "budget"
|
|
@@ -259,7 +260,7 @@ export function buildChunkedAuditTasks(coverageMatrix, unitLineIndex, options =
|
|
|
259
260
|
lens: block.lens,
|
|
260
261
|
filePaths: block.filePaths,
|
|
261
262
|
priority: taskPriority(hasExternalSignal, block.lens),
|
|
262
|
-
tags:
|
|
263
|
+
tags: withSignalTag([], hasExternalSignal),
|
|
263
264
|
rationale: (filePaths, splitKind) => splitKind === "large_file"
|
|
264
265
|
? `Audit ${filePaths[0]} (large file split from ${block.unitId}) under the ${block.lens} lens.${hasExternalSignal ? " External analyzer signals raise priority." : ""}`
|
|
265
266
|
: splitKind === "budget"
|
|
@@ -29,9 +29,12 @@ export class ClaudeCodeProvider {
|
|
|
29
29
|
? ["--dangerously-skip-permissions"]
|
|
30
30
|
: []),
|
|
31
31
|
];
|
|
32
|
-
|
|
32
|
+
process.stderr.write(JSON.stringify({ event: "provider_launch", provider: this.name, runId: input.runId, obligationId: input.obligationId, promptPath: input.promptPath, taskPath: input.taskPath }) + "\n");
|
|
33
|
+
const result = await this.launchCommand(command, args, applyWorkerTaskLaunchSettings(input, task), undefined, {
|
|
33
34
|
opentoken: this.opentoken.enabled,
|
|
34
35
|
opentokenCommand: this.opentoken.command,
|
|
35
36
|
});
|
|
37
|
+
process.stderr.write(JSON.stringify({ event: "provider_done", provider: this.name, runId: input.runId, obligationId: input.obligationId, accepted: result.accepted, exitCode: result.exitCode ?? null }) + "\n");
|
|
38
|
+
return result;
|
|
36
39
|
}
|
|
37
40
|
}
|
|
@@ -16,9 +16,12 @@ export class OpenCodeProvider {
|
|
|
16
16
|
// On Windows the `opencode` launcher is a `.cmd` shim that `spawn` cannot
|
|
17
17
|
// run without a shell; resolve it through cmd.exe (no-op on other OSes).
|
|
18
18
|
const { command, args } = resolveOpenCodeSpawnCommand(baseCommand, baseArgs);
|
|
19
|
-
|
|
19
|
+
process.stderr.write(JSON.stringify({ event: "provider_launch", provider: this.name, runId: input.runId, obligationId: input.obligationId, promptPath: input.promptPath, taskPath: input.taskPath }) + "\n");
|
|
20
|
+
const result = await spawnLoggedCommand(command, args, applyWorkerTaskLaunchSettings(input, task), undefined, {
|
|
20
21
|
opentoken: this.opentoken.enabled,
|
|
21
22
|
opentokenCommand: this.opentoken.command,
|
|
22
23
|
});
|
|
24
|
+
process.stderr.write(JSON.stringify({ event: "provider_done", provider: this.name, runId: input.runId, obligationId: input.obligationId, accepted: result.accepted, exitCode: result.exitCode ?? null }) + "\n");
|
|
25
|
+
return result;
|
|
23
26
|
}
|
|
24
27
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
-
import { dirname } from "node:path";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
3
|
import { getQuotaStatePath } from "@audit-tools/shared";
|
|
4
4
|
function getCachePath() {
|
|
5
|
-
return getQuotaStatePath()
|
|
5
|
+
return join(dirname(getQuotaStatePath()), "discovered-limits.json");
|
|
6
6
|
}
|
|
7
7
|
export async function readDiscoveredLimitsCache() {
|
|
8
8
|
try {
|
|
@@ -17,7 +17,7 @@ export async function readDiscoveredLimitsCache() {
|
|
|
17
17
|
}
|
|
18
18
|
catch (error) {
|
|
19
19
|
if (error.code !== "ENOENT") {
|
|
20
|
-
process.stderr.write(`[quota] ignoring unreadable discovered-limits cache: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
20
|
+
process.stderr.write(`[quota] ignoring unreadable discovered-limits cache (${getCachePath()}): ${error instanceof Error ? error.message : String(error)}\n`);
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
return { version: 1, entries: {} };
|
|
@@ -30,7 +30,7 @@ function parseResetValue(value) {
|
|
|
30
30
|
}
|
|
31
31
|
function parseNumericValue(value) {
|
|
32
32
|
const n = parseInt(value, 10);
|
|
33
|
-
return Number.isFinite(n) && n
|
|
33
|
+
return Number.isFinite(n) && n >= 0 ? n : null;
|
|
34
34
|
}
|
|
35
35
|
export function extractRateLimitHeaders(text) {
|
|
36
36
|
const result = {
|
|
@@ -68,6 +68,9 @@ export function extractRateLimitHeaders(text) {
|
|
|
68
68
|
if (jsonResult)
|
|
69
69
|
return jsonResult;
|
|
70
70
|
}
|
|
71
|
+
if (!found && text.trim().length > 0) {
|
|
72
|
+
process.stderr.write("[quota] header extraction: no rate-limit data found in non-empty stderr text (possible provider format change)\n");
|
|
73
|
+
}
|
|
71
74
|
return found ? result : null;
|
|
72
75
|
}
|
|
73
76
|
function extractFromJson(text) {
|
|
@@ -108,7 +111,7 @@ function extractFromHeaderObject(headers) {
|
|
|
108
111
|
const val = headers[key] ?? headers[key.toLowerCase()];
|
|
109
112
|
if (val != null) {
|
|
110
113
|
const n = typeof val === "number" ? val : parseInt(String(val), 10);
|
|
111
|
-
if (Number.isFinite(n) && n
|
|
114
|
+
if (Number.isFinite(n) && n >= 0)
|
|
112
115
|
return n;
|
|
113
116
|
}
|
|
114
117
|
}
|
|
@@ -23,6 +23,9 @@ export class ClaudeCodeHeaderExtractor {
|
|
|
23
23
|
return extractRateLimitHeaders(candidates.join("\n"));
|
|
24
24
|
}
|
|
25
25
|
// Fall back to scanning the full text for raw header lines
|
|
26
|
+
if (stderr.trim().length > 0) {
|
|
27
|
+
process.stderr.write("[quota] claude-code header extractor: no structured JSON lines with headers/response_headers found in non-empty stderr; falling back to raw-text scan\n");
|
|
28
|
+
}
|
|
26
29
|
return extractRateLimitHeaders(stderr);
|
|
27
30
|
}
|
|
28
31
|
}
|
|
@@ -3,10 +3,10 @@ export { ClaudeCodeHeaderExtractor } from "./claudeCodeHeaderExtractor.js";
|
|
|
3
3
|
import { GenericHeaderExtractor } from "./genericHeaderExtractor.js";
|
|
4
4
|
import { ClaudeCodeHeaderExtractor } from "./claudeCodeHeaderExtractor.js";
|
|
5
5
|
const PROVIDER_EXTRACTORS = {
|
|
6
|
-
"claude-code":
|
|
6
|
+
"claude-code": new ClaudeCodeHeaderExtractor(),
|
|
7
7
|
};
|
|
8
8
|
const genericExtractor = new GenericHeaderExtractor();
|
|
9
9
|
export function getHeaderExtractorForProvider(providerName) {
|
|
10
|
-
const
|
|
11
|
-
return
|
|
10
|
+
const extractor = PROVIDER_EXTRACTORS[providerName];
|
|
11
|
+
return extractor ?? genericExtractor;
|
|
12
12
|
}
|
package/dist/quota/index.d.ts
CHANGED
|
@@ -12,8 +12,10 @@ export { extractRateLimitHeaders } from "./headerExtraction.js";
|
|
|
12
12
|
export type { ExtractedRateLimits } from "./headerExtraction.js";
|
|
13
13
|
export type { HeaderExtractor } from "./headerExtractors/index.js";
|
|
14
14
|
export { GenericHeaderExtractor, ClaudeCodeHeaderExtractor, getHeaderExtractorForProvider } from "./headerExtractors/index.js";
|
|
15
|
+
export declare const DISPATCH_QUOTA_V1ALPHA1: "audit-code-dispatch-quota/v1alpha1";
|
|
16
|
+
export declare const DISPATCH_QUOTA_V1ALPHA2: "audit-code-dispatch-quota/v1alpha2";
|
|
15
17
|
export interface DispatchQuota {
|
|
16
|
-
contract_version:
|
|
18
|
+
contract_version: typeof DISPATCH_QUOTA_V1ALPHA1 | typeof DISPATCH_QUOTA_V1ALPHA2;
|
|
17
19
|
run_id: string;
|
|
18
20
|
model: string | null;
|
|
19
21
|
resolved_limits: _ResolvedLimits;
|
package/dist/quota/index.js
CHANGED
|
@@ -13,3 +13,6 @@ export { detectHostActiveSubagentLimit, resolveHostActiveSubagentLimit, } from "
|
|
|
13
13
|
export { lookupDiscoveredLimits, updateDiscoveredLimits, mergeDiscoveredLimits, readDiscoveredLimitsCache, writeDiscoveredLimitsCache, } from "./discoveredLimits.js";
|
|
14
14
|
export { extractRateLimitHeaders } from "./headerExtraction.js";
|
|
15
15
|
export { GenericHeaderExtractor, ClaudeCodeHeaderExtractor, getHeaderExtractorForProvider } from "./headerExtractors/index.js";
|
|
16
|
+
// Auditor-only type (not in shared)
|
|
17
|
+
export const DISPATCH_QUOTA_V1ALPHA1 = "audit-code-dispatch-quota/v1alpha1";
|
|
18
|
+
export const DISPATCH_QUOTA_V1ALPHA2 = "audit-code-dispatch-quota/v1alpha2";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export function severityRank(severity) {
|
|
2
|
+
switch (severity) {
|
|
3
|
+
case "critical":
|
|
4
|
+
return 5;
|
|
5
|
+
case "high":
|
|
6
|
+
return 4;
|
|
7
|
+
case "medium":
|
|
8
|
+
return 3;
|
|
9
|
+
case "low":
|
|
10
|
+
return 2;
|
|
11
|
+
case "info":
|
|
12
|
+
return 1;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function confidenceRank(confidence) {
|
|
16
|
+
switch (confidence) {
|
|
17
|
+
case "high":
|
|
18
|
+
return 3;
|
|
19
|
+
case "medium":
|
|
20
|
+
return 2;
|
|
21
|
+
case "low":
|
|
22
|
+
return 1;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { severityRank, confidenceRank } from "./findingRanks.js";
|
|
1
2
|
function normalizeText(value) {
|
|
2
3
|
return (value ?? "").trim().toLowerCase();
|
|
3
4
|
}
|
|
@@ -43,30 +44,6 @@ function findingKey(finding) {
|
|
|
43
44
|
String(finding.affected_files[0]?.line_end ?? ""),
|
|
44
45
|
].join("|");
|
|
45
46
|
}
|
|
46
|
-
function severityRank(severity) {
|
|
47
|
-
switch (severity) {
|
|
48
|
-
case "critical":
|
|
49
|
-
return 5;
|
|
50
|
-
case "high":
|
|
51
|
-
return 4;
|
|
52
|
-
case "medium":
|
|
53
|
-
return 3;
|
|
54
|
-
case "low":
|
|
55
|
-
return 2;
|
|
56
|
-
case "info":
|
|
57
|
-
return 1;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
function confidenceRank(confidence) {
|
|
61
|
-
switch (confidence) {
|
|
62
|
-
case "high":
|
|
63
|
-
return 3;
|
|
64
|
-
case "medium":
|
|
65
|
-
return 2;
|
|
66
|
-
case "low":
|
|
67
|
-
return 1;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
47
|
function runtimeSummary(report) {
|
|
71
48
|
if (!report) {
|
|
72
49
|
return [];
|
|
@@ -3,7 +3,7 @@ import type { AuditScopeManifest } from "../types/auditScope.js";
|
|
|
3
3
|
import type { DesignAssessment } from "../types/designAssessment.js";
|
|
4
4
|
import type { ExternalAnalyzerResults } from "../types/externalAnalyzer.js";
|
|
5
5
|
import type { AuditFindingsReport, CriticalFlowManifest, Finding as SharedFinding, FindingTheme, GraphBundle, SynthesisNarrative } from "@audit-tools/shared";
|
|
6
|
-
import type { RuntimeValidationReport } from "../types/runtimeValidation.js";
|
|
6
|
+
import type { RuntimeValidationReport, RuntimeValidationTaskManifest } from "../types/runtimeValidation.js";
|
|
7
7
|
import { type WorkBlock } from "./workBlocks.js";
|
|
8
8
|
/** Contract version stamped onto the canonical `audit-findings.json`. */
|
|
9
9
|
export declare const AUDIT_FINDINGS_CONTRACT_VERSION = "audit-tools/audit-findings/v1";
|
|
@@ -25,6 +25,7 @@ export interface AuditReportSummary {
|
|
|
25
25
|
finding_count: number;
|
|
26
26
|
work_block_count: number;
|
|
27
27
|
severity_breakdown: Record<string, number>;
|
|
28
|
+
lens_breakdown?: Record<string, number>;
|
|
28
29
|
audited_file_count: number;
|
|
29
30
|
excluded_file_count: number;
|
|
30
31
|
runtime_validation_status_breakdown: Record<string, number>;
|
|
@@ -49,6 +50,7 @@ export declare function buildAuditReportModel(params: {
|
|
|
49
50
|
criticalFlows?: CriticalFlowManifest;
|
|
50
51
|
coverageMatrix?: CoverageMatrix;
|
|
51
52
|
runtimeValidationReport?: RuntimeValidationReport;
|
|
53
|
+
runtimeValidationTaskManifest?: RuntimeValidationTaskManifest;
|
|
52
54
|
externalAnalyzerResults?: ExternalAnalyzerResults;
|
|
53
55
|
designAssessment?: DesignAssessment;
|
|
54
56
|
}): AuditReportModel;
|
|
@@ -18,8 +18,18 @@ function countBy(items, selectKey) {
|
|
|
18
18
|
function severityBreakdown(findings) {
|
|
19
19
|
return countBy(findings, (finding) => finding.severity);
|
|
20
20
|
}
|
|
21
|
-
function
|
|
22
|
-
return countBy(
|
|
21
|
+
function lensBreakdown(findings) {
|
|
22
|
+
return countBy(findings, (finding) => finding.lens);
|
|
23
|
+
}
|
|
24
|
+
function runtimeStatusBreakdown(report, taskManifest) {
|
|
25
|
+
const breakdown = countBy(report?.results ?? [], (result) => result.status);
|
|
26
|
+
const resultTaskIds = new Set((report?.results ?? []).map((result) => result.task_id));
|
|
27
|
+
for (const task of taskManifest?.tasks ?? []) {
|
|
28
|
+
if (!resultTaskIds.has(task.id)) {
|
|
29
|
+
breakdown.pending = (breakdown.pending ?? 0) + 1;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return breakdown;
|
|
23
33
|
}
|
|
24
34
|
function coverageSummary(coverage) {
|
|
25
35
|
const files = coverage?.files ?? [];
|
|
@@ -37,6 +47,13 @@ function formatSeverityList(summary) {
|
|
|
37
47
|
.map((severity) => `${severity}: ${summary[severity]}`);
|
|
38
48
|
return parts.length > 0 ? parts.join(", ") : "none";
|
|
39
49
|
}
|
|
50
|
+
function formatCountList(summary) {
|
|
51
|
+
const parts = Object.entries(summary)
|
|
52
|
+
.filter(([, count]) => count > 0)
|
|
53
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
54
|
+
.map(([key, count]) => `${key}: ${count}`);
|
|
55
|
+
return parts.length > 0 ? parts.join(", ") : "none";
|
|
56
|
+
}
|
|
40
57
|
export function buildAuditReportModel(params) {
|
|
41
58
|
// Re-key the finalized findings with globally-unique, content-derived ids
|
|
42
59
|
// before anything addresses them by id. buildWorkBlocks keys its union-find on
|
|
@@ -50,19 +67,22 @@ export function buildAuditReportModel(params) {
|
|
|
50
67
|
criticalFlows: params.criticalFlows,
|
|
51
68
|
});
|
|
52
69
|
const coverage = coverageSummary(params.coverageMatrix);
|
|
53
|
-
|
|
70
|
+
const model = {
|
|
54
71
|
summary: {
|
|
55
72
|
finding_count: findings.length,
|
|
56
73
|
work_block_count: workBlocks.length,
|
|
57
74
|
severity_breakdown: severityBreakdown(findings),
|
|
75
|
+
lens_breakdown: lensBreakdown(findings),
|
|
58
76
|
audited_file_count: coverage.audited_file_count,
|
|
59
77
|
excluded_file_count: coverage.excluded_file_count,
|
|
60
78
|
budget_deferred_task_count: coverage.budget_deferred_task_count,
|
|
61
|
-
runtime_validation_status_breakdown: runtimeStatusBreakdown(params.runtimeValidationReport),
|
|
79
|
+
runtime_validation_status_breakdown: runtimeStatusBreakdown(params.runtimeValidationReport, params.runtimeValidationTaskManifest),
|
|
62
80
|
},
|
|
63
81
|
findings,
|
|
64
82
|
work_blocks: workBlocks,
|
|
65
83
|
};
|
|
84
|
+
console.error(JSON.stringify({ tag: 'synthesis_complete', finding_count: findings.length, work_block_count: workBlocks.length, severity_breakdown: severityBreakdown(findings), audited_file_count: coverage.audited_file_count, excluded_file_count: coverage.excluded_file_count, budget_deferred_task_count: coverage.budget_deferred_task_count }));
|
|
85
|
+
return model;
|
|
66
86
|
}
|
|
67
87
|
/**
|
|
68
88
|
* Wrap the deterministic report model in the canonical `audit-findings.json`
|
|
@@ -70,12 +90,14 @@ export function buildAuditReportModel(params) {
|
|
|
70
90
|
* are absent here; they are layered on later by {@link applyNarrative}.
|
|
71
91
|
*/
|
|
72
92
|
export function buildAuditFindingsReport(model) {
|
|
73
|
-
|
|
93
|
+
const report = {
|
|
74
94
|
contract_version: AUDIT_FINDINGS_CONTRACT_VERSION,
|
|
75
95
|
summary: { ...model.summary },
|
|
76
96
|
findings: model.findings,
|
|
77
97
|
work_blocks: model.work_blocks,
|
|
78
98
|
};
|
|
99
|
+
console.error(JSON.stringify({ tag: 'audit_findings_report_built', contract_version: AUDIT_FINDINGS_CONTRACT_VERSION, finding_count: model.findings.length, work_block_count: model.work_blocks.length }));
|
|
100
|
+
return report;
|
|
79
101
|
}
|
|
80
102
|
/**
|
|
81
103
|
* Merge an LLM synthesis narrative into the canonical findings report: keep only
|
|
@@ -125,7 +147,9 @@ export function renderAuditReportMarkdown(report, options = {}) {
|
|
|
125
147
|
if (report.executive_summary && report.executive_summary.trim().length > 0) {
|
|
126
148
|
lines.push("## Executive Summary", "", report.executive_summary.trim(), "");
|
|
127
149
|
}
|
|
128
|
-
lines.push("## Summary", "", `- Findings: ${report.summary.finding_count}`, `- Work blocks: ${report.summary.work_block_count}`, `- Severity breakdown: ${formatSeverityList(report.summary.severity_breakdown)}`,
|
|
150
|
+
lines.push("## Summary", "", `- Findings: ${report.summary.finding_count}`, `- Work blocks: ${report.summary.work_block_count}`, `- Severity breakdown: ${formatSeverityList(report.summary.severity_breakdown)}`, ...(report.summary.lens_breakdown && Object.keys(report.summary.lens_breakdown).length > 0
|
|
151
|
+
? [`- Lens breakdown: ${formatCountList(report.summary.lens_breakdown)}`]
|
|
152
|
+
: []), `- Fully audited files: ${report.summary.audited_file_count}`, `- Excluded non-auditable files: ${report.summary.excluded_file_count}`, ...((report.summary.budget_deferred_task_count ?? 0) > 0
|
|
129
153
|
? [
|
|
130
154
|
`- Not audited (budget): ${report.summary.budget_deferred_task_count} task(s) skipped by packet budget cap`,
|
|
131
155
|
]
|
|
@@ -17,6 +17,9 @@ export function renderSynthesisNarrativePrompt(report) {
|
|
|
17
17
|
const overflowNote = findings.length > MAX_RENDERED_FINDINGS
|
|
18
18
|
? [` ... and ${findings.length - MAX_RENDERED_FINDINGS} more findings (see audit-findings.json).`]
|
|
19
19
|
: [];
|
|
20
|
+
if (findings.length > MAX_RENDERED_FINDINGS) {
|
|
21
|
+
console.warn(`[audit-code] synthesisNarrative: truncated findings list to ${MAX_RENDERED_FINDINGS} of ${findings.length} total — remaining findings omitted from narrative prompt (see audit-findings.json)`);
|
|
22
|
+
}
|
|
20
23
|
return [
|
|
21
24
|
"# Synthesis narrative",
|
|
22
25
|
"",
|
|
@@ -1,17 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
switch (severity) {
|
|
3
|
-
case "critical":
|
|
4
|
-
return 5;
|
|
5
|
-
case "high":
|
|
6
|
-
return 4;
|
|
7
|
-
case "medium":
|
|
8
|
-
return 3;
|
|
9
|
-
case "low":
|
|
10
|
-
return 2;
|
|
11
|
-
case "info":
|
|
12
|
-
return 1;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
1
|
+
import { severityRank } from "./findingRanks.js";
|
|
15
2
|
function buildFileUnitMap(unitManifest) {
|
|
16
3
|
const map = new Map();
|
|
17
4
|
for (const unit of unitManifest?.units ?? []) {
|
|
@@ -35,11 +35,8 @@ function quoteShellPath(filePath) {
|
|
|
35
35
|
// double-quote wrapping plus escaping embedded double quotes.
|
|
36
36
|
return `"${filePath.replace(/"/g, '\\"')}"`;
|
|
37
37
|
}
|
|
38
|
-
function quoteShellArg(value) {
|
|
39
|
-
return quoteShellPath(value);
|
|
40
|
-
}
|
|
41
38
|
function renderShellCommand(argv) {
|
|
42
|
-
return argv.map((item) =>
|
|
39
|
+
return argv.map((item) => quoteShellPath(item)).join(" ");
|
|
43
40
|
}
|
|
44
41
|
function buildPendingObligations(state) {
|
|
45
42
|
return state.obligations
|
|
@@ -274,7 +271,6 @@ export async function writeAuditCodeHandoffArtifacts(handoff) {
|
|
|
274
271
|
await writeFile(handoff.artifact_paths.operator_handoff_markdown, renderMarkdown(handoff), "utf8");
|
|
275
272
|
}
|
|
276
273
|
catch (error) {
|
|
277
|
-
|
|
278
|
-
throw new Error(`Failed to write operator handoff artifacts: ${message}`);
|
|
274
|
+
throw new Error(`Failed to write operator handoff artifacts: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
279
275
|
}
|
|
280
276
|
}
|
|
@@ -1,16 +1,36 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import {
|
|
2
|
+
import { open, mkdir, rename, rm } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { RUN_LEDGER_STATUSES, } from "@audit-tools/shared";
|
|
5
|
-
import { isFileMissingError, readJsonFile, writeJsonFile } from "@audit-tools/shared";
|
|
5
|
+
import { isFileMissingError, readJsonFile, writeJsonFile, withFileLock, withFsRetry } from "@audit-tools/shared";
|
|
6
6
|
const RUN_LEDGER_FILENAME = "run-ledger.json";
|
|
7
7
|
const RUN_LEDGER_LOCK_FILENAME = "run-ledger.lock";
|
|
8
|
-
const LOCK_RETRY_DELAY_MS = 20;
|
|
9
|
-
const LOCK_RETRY_LIMIT = 100;
|
|
10
8
|
const VALID_RUN_LEDGER_STATUSES = new Set(RUN_LEDGER_STATUSES);
|
|
11
9
|
function ledgerPath(artifactsDir) {
|
|
12
10
|
return join(artifactsDir, RUN_LEDGER_FILENAME);
|
|
13
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Wrap withFileLock for the run ledger, emitting a stderr message on the first
|
|
14
|
+
* contention event so operators can observe prolonged lock waits before the
|
|
15
|
+
* full timeout expires.
|
|
16
|
+
*/
|
|
17
|
+
async function withLedgerLock(lockPath, fn) {
|
|
18
|
+
// Probe for an immediate lock acquisition; if the lock file already exists,
|
|
19
|
+
// log contention before delegating to withFileLock for the full retry loop.
|
|
20
|
+
try {
|
|
21
|
+
const fd = await open(lockPath, "wx");
|
|
22
|
+
await fd.close();
|
|
23
|
+
// Lock acquired on the first attempt — no contention; release and let
|
|
24
|
+
// withFileLock manage the full acquire + release lifecycle.
|
|
25
|
+
await rm(lockPath, { force: true });
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
if (err.code === "EEXIST") {
|
|
29
|
+
process.stderr.write(`[audit-code] runLedger: lock contention detected on ${lockPath}, waiting...\n`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return withFileLock(lockPath, fn);
|
|
33
|
+
}
|
|
14
34
|
function ledgerLockPath(artifactsDir) {
|
|
15
35
|
return join(artifactsDir, RUN_LEDGER_LOCK_FILENAME);
|
|
16
36
|
}
|
|
@@ -20,12 +40,6 @@ function buildTempLedgerPath(artifactsDir) {
|
|
|
20
40
|
function isRecord(value) {
|
|
21
41
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22
42
|
}
|
|
23
|
-
function isFileExistsError(error) {
|
|
24
|
-
return (typeof error === "object" &&
|
|
25
|
-
error !== null &&
|
|
26
|
-
"code" in error &&
|
|
27
|
-
error.code === "EEXIST");
|
|
28
|
-
}
|
|
29
43
|
function assertRunLedgerEntry(value, fieldPath) {
|
|
30
44
|
if (!isRecord(value)) {
|
|
31
45
|
throw new Error(`Invalid run ledger in ${fieldPath}: expected an object.`);
|
|
@@ -43,7 +57,7 @@ function assertRunLedgerEntry(value, fieldPath) {
|
|
|
43
57
|
return null;
|
|
44
58
|
}
|
|
45
59
|
if (typeof entry !== "string" || entry.trim().length === 0) {
|
|
46
|
-
throw new Error(`Invalid run ledger in ${fieldPath}.${field}: expected a string or null.`);
|
|
60
|
+
throw new Error(`Invalid run ledger in ${fieldPath}.${field}: expected a non-empty string or null.`);
|
|
47
61
|
}
|
|
48
62
|
return entry;
|
|
49
63
|
};
|
|
@@ -74,28 +88,6 @@ function parseRunLedger(value, path) {
|
|
|
74
88
|
runs: value.runs.map((entry, index) => assertRunLedgerEntry(entry, `${path}.runs[${index}]`)),
|
|
75
89
|
};
|
|
76
90
|
}
|
|
77
|
-
function sleep(ms) {
|
|
78
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
79
|
-
}
|
|
80
|
-
async function acquireLedgerLock(artifactsDir) {
|
|
81
|
-
const lockPath = ledgerLockPath(artifactsDir);
|
|
82
|
-
await mkdir(artifactsDir, { recursive: true });
|
|
83
|
-
for (let attempt = 0; attempt < LOCK_RETRY_LIMIT; attempt += 1) {
|
|
84
|
-
try {
|
|
85
|
-
return await open(lockPath, "wx");
|
|
86
|
-
}
|
|
87
|
-
catch (error) {
|
|
88
|
-
if (!isFileExistsError(error)) {
|
|
89
|
-
throw error;
|
|
90
|
-
}
|
|
91
|
-
if (attempt === LOCK_RETRY_LIMIT - 1) {
|
|
92
|
-
throw new Error(`Timed out waiting to update ${ledgerPath(artifactsDir)} because ${lockPath} is locked.`);
|
|
93
|
-
}
|
|
94
|
-
await sleep(LOCK_RETRY_DELAY_MS);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
throw new Error(`Failed to acquire lock for ${ledgerPath(artifactsDir)}.`);
|
|
98
|
-
}
|
|
99
91
|
export async function loadRunLedger(artifactsDir) {
|
|
100
92
|
const path = ledgerPath(artifactsDir);
|
|
101
93
|
try {
|
|
@@ -110,18 +102,15 @@ export async function loadRunLedger(artifactsDir) {
|
|
|
110
102
|
}
|
|
111
103
|
}
|
|
112
104
|
export async function appendRunLedgerEntry(artifactsDir, entry) {
|
|
113
|
-
const lockHandle = await acquireLedgerLock(artifactsDir);
|
|
114
105
|
const path = ledgerPath(artifactsDir);
|
|
106
|
+
const lockPath = ledgerLockPath(artifactsDir);
|
|
115
107
|
const tempPath = buildTempLedgerPath(artifactsDir);
|
|
116
|
-
|
|
108
|
+
await mkdir(artifactsDir, { recursive: true });
|
|
109
|
+
await withLedgerLock(lockPath, async () => {
|
|
117
110
|
const ledger = await loadRunLedger(artifactsDir);
|
|
118
111
|
ledger.runs.push(entry);
|
|
119
112
|
await writeJsonFile(tempPath, ledger);
|
|
120
|
-
await rename(tempPath, path);
|
|
121
|
-
}
|
|
122
|
-
finally {
|
|
123
|
-
await lockHandle.close();
|
|
124
|
-
await rm(ledgerLockPath(artifactsDir), { force: true });
|
|
113
|
+
await withFsRetry(() => rename(tempPath, path));
|
|
125
114
|
await rm(tempPath, { force: true }).catch(() => undefined);
|
|
126
|
-
}
|
|
115
|
+
});
|
|
127
116
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export declare const DISPATCH_RESULT_MAP_FILENAME = "dispatch-result-map.json";
|
|
2
|
+
export declare const ACTIVE_DISPATCH_FILENAME = "active-dispatch.json";
|
|
3
|
+
export interface ActiveDispatchState {
|
|
4
|
+
run_id: string;
|
|
5
|
+
created_at: string;
|
|
6
|
+
/** Emitted packets only (after canary/budget filtering). */
|
|
7
|
+
packet_count: number;
|
|
8
|
+
/** Tasks remaining this round (not-yet-done), not just emitted-packet tasks. */
|
|
9
|
+
task_count: number;
|
|
10
|
+
status: "active" | "merged";
|
|
11
|
+
/** "canary" on first contact when only the top packet was emitted; "fan_out" otherwise. */
|
|
12
|
+
phase: "canary" | "fan_out";
|
|
13
|
+
/** packet_id of the emitted canary packet when phase==="canary", else null. */
|
|
14
|
+
canary_packet_id: string | null;
|
|
15
|
+
/** Total packets that would have been emitted before a budget cap (present only when capped). */
|
|
16
|
+
budget_packet_count?: number;
|
|
17
|
+
/** packet_ids NOT emitted due to the budget cap. */
|
|
18
|
+
deferred_packet_ids?: string[];
|
|
19
|
+
/** task_ids NOT emitted due to the budget cap. */
|
|
20
|
+
deferred_task_ids?: string[];
|
|
21
|
+
}
|
|
22
|
+
export interface DispatchResultMapEntry {
|
|
23
|
+
packet_id: string;
|
|
24
|
+
task_id: string;
|
|
25
|
+
result_path: string;
|
|
26
|
+
}
|
|
27
|
+
export interface DispatchResultMap {
|
|
28
|
+
contract_version: "audit-code-dispatch-results/v1alpha1";
|
|
29
|
+
run_id: string;
|
|
30
|
+
entries: DispatchResultMapEntry[];
|
|
31
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
import type { Finding as SharedFinding } from "@audit-tools/shared";
|
|
2
2
|
export type Lens = "correctness" | "architecture" | "maintainability" | "security" | "reliability" | "performance" | "data_integrity" | "tests" | "operability" | "config_deployment" | "observability";
|
|
3
|
-
/**
|
|
4
|
-
*
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
/** Single authoritative record for one audit lens. `order_weight` governs task
|
|
4
|
+
* priority ordering — lower values sort earlier (higher urgency). */
|
|
5
|
+
export interface LensDefinition {
|
|
6
|
+
id: Lens;
|
|
7
|
+
display_name: string;
|
|
8
|
+
/** Lower = higher priority in task ordering. */
|
|
9
|
+
order_weight: number;
|
|
10
|
+
default_enabled: boolean;
|
|
11
|
+
}
|
|
12
|
+
/** Single source of truth for all lens metadata. Adding or renaming a lens
|
|
13
|
+
* requires a single edit here; `ALL_LENSES`, `ENABLED_LENSES`, and
|
|
14
|
+
* `LENS_ORDER` (in auditTaskUtils) are all derived from this registry. */
|
|
15
|
+
export declare const LENS_REGISTRY: readonly LensDefinition[];
|
|
16
|
+
/** Canonical list of every valid {@link Lens}. Derived from {@link LENS_REGISTRY}
|
|
17
|
+
* — import {@link isLens} / `ALL_LENSES` instead of hand-copying lens lists into
|
|
18
|
+
* local guards, which drift (a copy omitting "observability" caused it to be
|
|
19
|
+
* wrongly rejected in flow requeue). */
|
|
7
20
|
export declare const ALL_LENSES: readonly Lens[];
|
|
21
|
+
/** Lenses enabled by default (all entries in the registry with default_enabled true). */
|
|
22
|
+
export declare const ENABLED_LENSES: readonly Lens[];
|
|
8
23
|
export declare function isLens(value: unknown): value is Lens;
|
|
9
24
|
export interface FileRecord {
|
|
10
25
|
path: string;
|
|
@@ -100,4 +115,6 @@ export interface AuditResult {
|
|
|
100
115
|
requires_followup?: boolean;
|
|
101
116
|
followup_tasks?: string[];
|
|
102
117
|
verification?: AuditVerification;
|
|
118
|
+
run_id?: string;
|
|
119
|
+
submitted_at?: string;
|
|
103
120
|
}
|
package/dist/types.js
CHANGED
|
@@ -1,20 +1,28 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
"correctness",
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"observability",
|
|
1
|
+
/** Single source of truth for all lens metadata. Adding or renaming a lens
|
|
2
|
+
* requires a single edit here; `ALL_LENSES`, `ENABLED_LENSES`, and
|
|
3
|
+
* `LENS_ORDER` (in auditTaskUtils) are all derived from this registry. */
|
|
4
|
+
export const LENS_REGISTRY = [
|
|
5
|
+
{ id: "security", display_name: "Security", order_weight: 10, default_enabled: true },
|
|
6
|
+
{ id: "correctness", display_name: "Correctness", order_weight: 20, default_enabled: true },
|
|
7
|
+
{ id: "reliability", display_name: "Reliability", order_weight: 30, default_enabled: true },
|
|
8
|
+
{ id: "data_integrity", display_name: "Data Integrity", order_weight: 40, default_enabled: true },
|
|
9
|
+
{ id: "performance", display_name: "Performance", order_weight: 50, default_enabled: true },
|
|
10
|
+
{ id: "architecture", display_name: "Architecture", order_weight: 60, default_enabled: true },
|
|
11
|
+
{ id: "operability", display_name: "Operability", order_weight: 70, default_enabled: true },
|
|
12
|
+
{ id: "config_deployment", display_name: "Config & Deployment", order_weight: 80, default_enabled: true },
|
|
13
|
+
{ id: "observability", display_name: "Observability", order_weight: 90, default_enabled: true },
|
|
14
|
+
{ id: "maintainability", display_name: "Maintainability", order_weight: 100, default_enabled: true },
|
|
15
|
+
{ id: "tests", display_name: "Tests", order_weight: 110, default_enabled: true },
|
|
17
16
|
];
|
|
17
|
+
/** Canonical list of every valid {@link Lens}. Derived from {@link LENS_REGISTRY}
|
|
18
|
+
* — import {@link isLens} / `ALL_LENSES` instead of hand-copying lens lists into
|
|
19
|
+
* local guards, which drift (a copy omitting "observability" caused it to be
|
|
20
|
+
* wrongly rejected in flow requeue). */
|
|
21
|
+
export const ALL_LENSES = LENS_REGISTRY.map((d) => d.id);
|
|
22
|
+
/** Lenses enabled by default (all entries in the registry with default_enabled true). */
|
|
23
|
+
export const ENABLED_LENSES = LENS_REGISTRY
|
|
24
|
+
.filter((d) => d.default_enabled)
|
|
25
|
+
.map((d) => d.id);
|
|
18
26
|
export function isLens(value) {
|
|
19
27
|
return (typeof value === "string" && ALL_LENSES.includes(value));
|
|
20
28
|
}
|