auditor-lambda 0.3.40 → 0.5.0
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-lib.mjs +20 -2
- package/dist/cli/args.d.ts +59 -0
- package/dist/cli/args.js +244 -0
- package/dist/cli/dispatch.d.ts +80 -0
- package/dist/cli/dispatch.js +532 -0
- package/dist/cli/prompts.d.ts +37 -0
- package/dist/cli/prompts.js +225 -0
- package/dist/cli/steps.d.ts +29 -0
- package/dist/cli/steps.js +30 -0
- package/dist/cli/waveManifest.d.ts +40 -0
- package/dist/cli/waveManifest.js +41 -0
- package/dist/cli/workerResult.d.ts +18 -0
- package/dist/cli/workerResult.js +42 -0
- package/dist/cli.d.ts +2 -22
- package/dist/cli.js +442 -975
- package/dist/extractors/analyzers/css.d.ts +2 -0
- package/dist/extractors/analyzers/css.js +101 -0
- package/dist/extractors/analyzers/html.d.ts +2 -0
- package/dist/extractors/analyzers/html.js +92 -0
- package/dist/extractors/analyzers/merge.d.ts +14 -0
- package/dist/extractors/analyzers/merge.js +85 -0
- package/dist/extractors/analyzers/python.d.ts +2 -0
- package/dist/extractors/analyzers/python.js +104 -0
- package/dist/extractors/analyzers/registry.d.ts +33 -0
- package/dist/extractors/analyzers/registry.js +100 -0
- package/dist/extractors/analyzers/resourceUrl.d.ts +7 -0
- package/dist/extractors/analyzers/resourceUrl.js +25 -0
- package/dist/extractors/analyzers/sql.d.ts +2 -0
- package/dist/extractors/analyzers/sql.js +19 -0
- package/dist/extractors/analyzers/treeSitter.d.ts +34 -0
- package/dist/extractors/analyzers/treeSitter.js +111 -0
- package/dist/extractors/analyzers/types.d.ts +53 -0
- package/dist/extractors/analyzers/typescript.d.ts +2 -0
- package/dist/extractors/analyzers/typescript.js +257 -0
- package/dist/extractors/browserExtension.d.ts +1 -3
- package/dist/extractors/browserExtension.js +2 -2
- package/dist/extractors/designAssessment.d.ts +1 -3
- package/dist/extractors/disposition.d.ts +2 -1
- package/dist/extractors/disposition.js +11 -1
- package/dist/extractors/flows.d.ts +1 -3
- package/dist/extractors/flows.js +2 -2
- package/dist/extractors/graph.d.ts +2 -2
- package/dist/extractors/graph.js +171 -327
- package/dist/extractors/graphManifestEdges.d.ts +1 -1
- package/dist/extractors/graphPathUtils.d.ts +1 -1
- package/dist/extractors/graphPythonImports.d.ts +18 -0
- package/dist/extractors/graphPythonImports.js +362 -0
- package/dist/extractors/pathPatterns.d.ts +6 -0
- package/dist/extractors/pathPatterns.js +8 -0
- package/dist/extractors/risk.d.ts +1 -2
- package/dist/extractors/surfaces.d.ts +1 -3
- package/dist/extractors/surfaces.js +2 -2
- package/dist/io/artifacts.d.ts +12 -5
- package/dist/io/artifacts.js +13 -1
- package/dist/io/runArtifacts.js +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/orchestrator/advance.d.ts +21 -0
- package/dist/orchestrator/advance.js +69 -7
- package/dist/orchestrator/auditTaskUtils.d.ts +4 -0
- package/dist/orchestrator/auditTaskUtils.js +27 -0
- package/dist/orchestrator/dependencyMap.js +27 -0
- package/dist/orchestrator/edgeReasoning.d.ts +39 -0
- package/dist/orchestrator/edgeReasoning.js +125 -0
- package/dist/orchestrator/executors.js +11 -1
- package/dist/orchestrator/fileAnchors.d.ts +1 -1
- package/dist/orchestrator/fileIntegrity.d.ts +7 -0
- package/dist/orchestrator/fileIntegrity.js +41 -0
- package/dist/orchestrator/flowCoverage.d.ts +1 -1
- package/dist/orchestrator/flowPlanning.d.ts +1 -1
- package/dist/orchestrator/flowRequeue.d.ts +1 -1
- package/dist/orchestrator/graphEnrichmentExecutor.d.ts +29 -0
- package/dist/orchestrator/graphEnrichmentExecutor.js +196 -0
- package/dist/orchestrator/internalExecutors.d.ts +13 -2
- package/dist/orchestrator/internalExecutors.js +112 -16
- package/dist/orchestrator/localCommands.js +6 -25
- package/dist/orchestrator/nextStep.d.ts +2 -1
- package/dist/orchestrator/nextStep.js +3 -1
- package/dist/orchestrator/planning.d.ts +1 -1
- package/dist/orchestrator/requeueCommand.d.ts +1 -1
- package/dist/orchestrator/reviewPackets.d.ts +37 -4
- package/dist/orchestrator/reviewPackets.js +113 -158
- package/dist/orchestrator/runtimeValidation.d.ts +1 -1
- package/dist/orchestrator/runtimeValidation.js +4 -31
- package/dist/orchestrator/scope.d.ts +62 -0
- package/dist/orchestrator/scope.js +227 -0
- package/dist/orchestrator/state.js +2 -0
- package/dist/orchestrator/taskBuilder.d.ts +1 -1
- package/dist/orchestrator/taskBuilder.js +1 -12
- package/dist/orchestrator/unionFind.d.ts +7 -0
- package/dist/orchestrator/unionFind.js +32 -0
- package/dist/orchestrator/unitBuilder.d.ts +2 -2
- package/dist/orchestrator/unitBuilder.js +4 -18
- package/dist/prompts/renderWorkerPrompt.js +18 -1
- package/dist/providers/claudeCodeProvider.d.ts +4 -4
- package/dist/providers/claudeCodeProvider.js +9 -3
- package/dist/providers/constants.d.ts +1 -1
- package/dist/providers/constants.js +1 -1
- package/dist/providers/index.d.ts +1 -2
- package/dist/providers/index.js +5 -4
- package/dist/providers/localSubprocessProvider.d.ts +2 -2
- package/dist/providers/localSubprocessProvider.js +1 -1
- package/dist/providers/opencodeProvider.d.ts +4 -4
- package/dist/providers/opencodeProvider.js +7 -2
- package/dist/providers/spawnLoggedCommand.d.ts +3 -1
- package/dist/providers/spawnLoggedCommand.js +21 -0
- package/dist/providers/subprocessTemplateProvider.d.ts +4 -4
- package/dist/providers/subprocessTemplateProvider.js +8 -3
- package/dist/providers/vscodeTaskProvider.d.ts +3 -4
- package/dist/providers/vscodeTaskProvider.js +2 -2
- package/dist/quota/discoveredLimits.js +1 -1
- package/dist/quota/hostLimits.d.ts +1 -2
- package/dist/quota/hostLimits.js +4 -46
- package/dist/quota/index.d.ts +18 -15
- package/dist/quota/index.js +4 -9
- package/dist/quota/scheduler.d.ts +1 -3
- package/dist/quota/scheduler.js +1 -2
- package/dist/reporting/synthesis.d.ts +37 -3
- package/dist/reporting/synthesis.js +97 -16
- package/dist/reporting/synthesisNarrativePrompt.d.ts +7 -0
- package/dist/reporting/synthesisNarrativePrompt.js +60 -0
- package/dist/reporting/workBlocks.d.ts +2 -11
- package/dist/supervisor/operatorHandoff.js +1 -1
- package/dist/supervisor/runLedger.d.ts +1 -1
- package/dist/supervisor/runLedger.js +2 -2
- package/dist/supervisor/sessionConfig.d.ts +8 -1
- package/dist/supervisor/sessionConfig.js +22 -3
- package/dist/types/analyzerCapability.d.ts +16 -0
- package/dist/types/auditScope.d.ts +43 -0
- package/dist/types/auditScope.js +14 -0
- package/dist/types/reviewPlanning.d.ts +1 -1
- package/dist/types/synthesisNarrative.d.ts +7 -0
- package/dist/types/synthesisNarrative.js +5 -0
- package/dist/types/workerSession.d.ts +6 -0
- package/dist/types.d.ts +2 -19
- package/dist/validation/artifacts.d.ts +1 -1
- package/dist/validation/artifacts.js +10 -1
- package/dist/validation/auditResults.d.ts +1 -1
- package/dist/validation/auditResults.js +1 -1
- package/dist/validation/sessionConfig.d.ts +2 -3
- package/dist/validation/sessionConfig.js +25 -3
- package/package.json +7 -3
- package/schemas/analyzer_capability.schema.json +47 -0
- package/schemas/audit_findings.schema.json +141 -0
- package/schemas/finding.schema.json +2 -1
- package/schemas/graph_bundle.schema.json +5 -0
- package/schemas/scope.schema.json +46 -0
- package/scripts/postinstall.mjs +0 -1
- package/dist/io/json.d.ts +0 -10
- package/dist/io/json.js +0 -142
- package/dist/providers/types.d.ts +0 -33
- package/dist/quota/compositeQuotaSource.d.ts +0 -7
- package/dist/quota/compositeQuotaSource.js +0 -20
- package/dist/quota/errorParsers/claudeCodeErrorParser.d.ts +0 -6
- package/dist/quota/errorParsers/claudeCodeErrorParser.js +0 -39
- package/dist/quota/errorParsers/genericErrorParser.d.ts +0 -9
- package/dist/quota/errorParsers/genericErrorParser.js +0 -7
- package/dist/quota/errorParsers/index.d.ts +0 -5
- package/dist/quota/errorParsers/index.js +0 -12
- package/dist/quota/errorParsing.d.ts +0 -7
- package/dist/quota/errorParsing.js +0 -69
- package/dist/quota/fileLock.d.ts +0 -6
- package/dist/quota/fileLock.js +0 -64
- package/dist/quota/learnedQuotaSource.d.ts +0 -7
- package/dist/quota/learnedQuotaSource.js +0 -25
- package/dist/quota/limits.d.ts +0 -16
- package/dist/quota/limits.js +0 -77
- package/dist/quota/quotaSource.d.ts +0 -12
- package/dist/quota/slidingWindow.d.ts +0 -4
- package/dist/quota/slidingWindow.js +0 -28
- package/dist/quota/state.d.ts +0 -15
- package/dist/quota/state.js +0 -148
- package/dist/quota/types.d.ts +0 -67
- package/dist/quota/types.js +0 -1
- package/dist/reporting/rootCause.d.ts +0 -10
- package/dist/reporting/rootCause.js +0 -146
- package/dist/types/disposition.d.ts +0 -9
- package/dist/types/disposition.js +0 -1
- package/dist/types/flows.d.ts +0 -17
- package/dist/types/flows.js +0 -1
- package/dist/types/graph.d.ts +0 -22
- package/dist/types/graph.js +0 -1
- package/dist/types/risk.d.ts +0 -9
- package/dist/types/risk.js +0 -1
- package/dist/types/runLedger.d.ts +0 -17
- package/dist/types/runLedger.js +0 -6
- package/dist/types/sessionConfig.d.ts +0 -79
- package/dist/types/sessionConfig.js +0 -15
- package/dist/types/surfaces.d.ts +0 -15
- package/dist/types/surfaces.js +0 -1
- package/dist/validation/basic.d.ts +0 -13
- package/dist/validation/basic.js +0 -46
- /package/dist/{providers → extractors/analyzers}/types.js +0 -0
- /package/dist/{quota/quotaSource.js → types/analyzerCapability.js} +0 -0
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import { decideNextStep } from "./nextStep.js";
|
|
1
|
+
import { decideNextStep, findObligation } from "./nextStep.js";
|
|
2
2
|
import { deriveAuditState } from "./state.js";
|
|
3
3
|
import { computeArtifactMetadata } from "./artifactMetadata.js";
|
|
4
|
-
import { runIntakeExecutor, runStructureExecutor, runPlanningExecutor, runResultIngestionExecutor, runRuntimeValidationExecutor, runRuntimeValidationUpdateExecutor, runSynthesisExecutor, runDesignAssessmentExecutor, runDesignReviewAutoComplete, runExternalAnalyzerImportExecutor, } from "./internalExecutors.js";
|
|
4
|
+
import { runIntakeExecutor, runStructureExecutor, runPlanningExecutor, runResultIngestionExecutor, runRuntimeValidationExecutor, runRuntimeValidationUpdateExecutor, runSynthesisExecutor, runSynthesisNarrativeExecutor, runDesignAssessmentExecutor, runDesignReviewAutoComplete, runExternalAnalyzerImportExecutor, } from "./internalExecutors.js";
|
|
5
5
|
import { runAutoFixExecutor } from "./autoFixExecutor.js";
|
|
6
6
|
import { runSyntaxResolutionExecutor } from "./syntaxResolutionExecutor.js";
|
|
7
|
+
import { runGraphEnrichmentExecutor } from "./graphEnrichmentExecutor.js";
|
|
8
|
+
import { resolveAuditScope } from "./scope.js";
|
|
9
|
+
import { RunLogger } from "@audit-tools/shared";
|
|
7
10
|
function cloneState(state) {
|
|
8
11
|
return {
|
|
9
12
|
...state,
|
|
@@ -18,12 +21,19 @@ function formatExecutorFailure(selectedExecutor, selectedObligation, error) {
|
|
|
18
21
|
});
|
|
19
22
|
}
|
|
20
23
|
export async function advanceAudit(bundle, options = {}) {
|
|
24
|
+
const log = options.runLogger ?? RunLogger.disabled();
|
|
21
25
|
const decision = decideNextStep(bundle);
|
|
22
26
|
const forcedExecutor = options.preferredExecutor ?? null;
|
|
23
27
|
const selectedExecutor = forcedExecutor ?? decision.selected_executor;
|
|
24
28
|
const selectedObligation = forcedExecutor
|
|
25
29
|
? `forced:${forcedExecutor}`
|
|
26
30
|
: decision.selected_obligation;
|
|
31
|
+
log.event({
|
|
32
|
+
phase: "advance",
|
|
33
|
+
kind: "obligation",
|
|
34
|
+
obligation: selectedObligation ?? undefined,
|
|
35
|
+
note: decision.reason,
|
|
36
|
+
});
|
|
27
37
|
if (!selectedExecutor) {
|
|
28
38
|
const state = cloneState(decision.state);
|
|
29
39
|
state.last_executor = bundle.audit_state?.last_executor ?? state.last_executor;
|
|
@@ -43,6 +53,14 @@ export async function advanceAudit(bundle, options = {}) {
|
|
|
43
53
|
};
|
|
44
54
|
}
|
|
45
55
|
let run;
|
|
56
|
+
let plannedScope;
|
|
57
|
+
const executorStartedAt = Date.now();
|
|
58
|
+
log.event({
|
|
59
|
+
phase: "advance",
|
|
60
|
+
kind: "executor_start",
|
|
61
|
+
obligation: selectedObligation ?? undefined,
|
|
62
|
+
note: selectedExecutor,
|
|
63
|
+
});
|
|
46
64
|
try {
|
|
47
65
|
switch (selectedExecutor) {
|
|
48
66
|
case "intake_executor":
|
|
@@ -53,6 +71,14 @@ export async function advanceAudit(bundle, options = {}) {
|
|
|
53
71
|
case "structure_executor":
|
|
54
72
|
run = await runStructureExecutor(bundle, options.root);
|
|
55
73
|
break;
|
|
74
|
+
case "graph_enrichment_executor":
|
|
75
|
+
run = await runGraphEnrichmentExecutor(bundle, {
|
|
76
|
+
root: options.root,
|
|
77
|
+
analyzers: options.analyzers,
|
|
78
|
+
llmEdgeReasoning: options.graphLlmEdgeReasoning,
|
|
79
|
+
edgeReasoning: options.edgeReasoningResults,
|
|
80
|
+
});
|
|
81
|
+
break;
|
|
56
82
|
case "design_assessment_executor":
|
|
57
83
|
run = runDesignAssessmentExecutor(bundle);
|
|
58
84
|
break;
|
|
@@ -62,7 +88,12 @@ export async function advanceAudit(bundle, options = {}) {
|
|
|
62
88
|
case "planning_executor":
|
|
63
89
|
if (!options.root)
|
|
64
90
|
throw new Error("advanceAudit planning_executor requires root");
|
|
65
|
-
|
|
91
|
+
plannedScope = resolveAuditScope({
|
|
92
|
+
root: options.root,
|
|
93
|
+
since: options.since,
|
|
94
|
+
bundle,
|
|
95
|
+
});
|
|
96
|
+
run = await runPlanningExecutor(bundle, options.root, options.lineIndex ?? {}, options.sizeIndex, plannedScope);
|
|
66
97
|
break;
|
|
67
98
|
case "result_ingestion_executor":
|
|
68
99
|
run = runResultIngestionExecutor(bundle, options.auditResults ?? bundle.audit_results ?? []);
|
|
@@ -70,11 +101,16 @@ export async function advanceAudit(bundle, options = {}) {
|
|
|
70
101
|
case "runtime_validation_executor":
|
|
71
102
|
if (!options.root)
|
|
72
103
|
throw new Error("advanceAudit runtime_validation_executor requires root");
|
|
73
|
-
run = await runRuntimeValidationExecutor(bundle, options.root
|
|
104
|
+
run = await runRuntimeValidationExecutor(bundle, options.root, {
|
|
105
|
+
opentoken: options.opentoken,
|
|
106
|
+
});
|
|
74
107
|
break;
|
|
75
108
|
case "synthesis_executor":
|
|
76
109
|
run = runSynthesisExecutor(bundle, options.auditResults);
|
|
77
110
|
break;
|
|
111
|
+
case "synthesis_narrative_executor":
|
|
112
|
+
run = runSynthesisNarrativeExecutor(bundle, options.narrativeResults);
|
|
113
|
+
break;
|
|
78
114
|
case "runtime_validation_update_executor":
|
|
79
115
|
if (!options.runtimeValidationUpdates)
|
|
80
116
|
throw new Error("advanceAudit runtime_validation_update_executor requires runtimeValidationUpdates");
|
|
@@ -95,7 +131,7 @@ export async function advanceAudit(bundle, options = {}) {
|
|
|
95
131
|
throw new Error("advanceAudit syntax_resolution_executor requires root");
|
|
96
132
|
run = runSyntaxResolutionExecutor(bundle, options.root);
|
|
97
133
|
break;
|
|
98
|
-
default:
|
|
134
|
+
default: {
|
|
99
135
|
const state = deriveAuditState(bundle);
|
|
100
136
|
state.last_executor = selectedExecutor;
|
|
101
137
|
state.last_obligation = selectedObligation ?? undefined;
|
|
@@ -109,11 +145,37 @@ export async function advanceAudit(bundle, options = {}) {
|
|
|
109
145
|
next_likely_step: selectedObligation,
|
|
110
146
|
updated_bundle: { ...bundle, audit_state: state },
|
|
111
147
|
};
|
|
148
|
+
}
|
|
112
149
|
}
|
|
113
150
|
}
|
|
114
151
|
catch (error) {
|
|
115
152
|
throw formatExecutorFailure(selectedExecutor, selectedObligation, error);
|
|
116
153
|
}
|
|
154
|
+
log.event({
|
|
155
|
+
phase: "advance",
|
|
156
|
+
kind: "executor_end",
|
|
157
|
+
obligation: selectedObligation ?? undefined,
|
|
158
|
+
note: selectedExecutor,
|
|
159
|
+
duration_ms: Date.now() - executorStartedAt,
|
|
160
|
+
});
|
|
161
|
+
if (plannedScope) {
|
|
162
|
+
log.event({
|
|
163
|
+
phase: "advance",
|
|
164
|
+
kind: "scope",
|
|
165
|
+
obligation: selectedObligation ?? undefined,
|
|
166
|
+
note: plannedScope.mode === "delta"
|
|
167
|
+
? `delta since ${plannedScope.since}: ${plannedScope.seed_files.length} changed + ${plannedScope.expanded_files.length} neighbors; full audit advised before release`
|
|
168
|
+
: "full audit scope",
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
for (const artifact of run.artifacts_written) {
|
|
172
|
+
log.event({
|
|
173
|
+
phase: "advance",
|
|
174
|
+
kind: "artifact_write",
|
|
175
|
+
obligation: selectedObligation ?? undefined,
|
|
176
|
+
artifact,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
117
179
|
const metadata = computeArtifactMetadata(run.updated, bundle.artifact_metadata, [...run.artifacts_written, "tooling_manifest.json"]);
|
|
118
180
|
const metadataBundle = {
|
|
119
181
|
...run.updated,
|
|
@@ -124,7 +186,7 @@ export async function advanceAudit(bundle, options = {}) {
|
|
|
124
186
|
updatedState.last_executor = selectedExecutor;
|
|
125
187
|
updatedState.last_obligation = selectedObligation ?? undefined;
|
|
126
188
|
const finalizedBundle = { ...metadataBundle, audit_state: updatedState };
|
|
127
|
-
const
|
|
189
|
+
const nextObligation = findObligation(updatedState.obligations);
|
|
128
190
|
return {
|
|
129
191
|
audit_state: updatedState,
|
|
130
192
|
selected_obligation: selectedObligation,
|
|
@@ -136,7 +198,7 @@ export async function advanceAudit(bundle, options = {}) {
|
|
|
136
198
|
"audit_state.json",
|
|
137
199
|
],
|
|
138
200
|
progress_summary: run.progress_summary,
|
|
139
|
-
next_likely_step:
|
|
201
|
+
next_likely_step: nextObligation?.id ?? null,
|
|
140
202
|
updated_bundle: finalizedBundle,
|
|
141
203
|
};
|
|
142
204
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const LENS_ORDER = [
|
|
2
|
+
"security",
|
|
3
|
+
"correctness",
|
|
4
|
+
"reliability",
|
|
5
|
+
"data_integrity",
|
|
6
|
+
"performance",
|
|
7
|
+
"operability",
|
|
8
|
+
"config_deployment",
|
|
9
|
+
"observability",
|
|
10
|
+
"maintainability",
|
|
11
|
+
"tests",
|
|
12
|
+
];
|
|
13
|
+
export function priorityRank(priority) {
|
|
14
|
+
switch (priority) {
|
|
15
|
+
case "high":
|
|
16
|
+
return 3;
|
|
17
|
+
case "medium":
|
|
18
|
+
return 2;
|
|
19
|
+
case "low":
|
|
20
|
+
default:
|
|
21
|
+
return 1;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function sortLenses(lenses) {
|
|
25
|
+
const set = new Set(lenses);
|
|
26
|
+
return LENS_ORDER.filter((lens) => set.has(lens));
|
|
27
|
+
}
|
|
@@ -19,6 +19,15 @@ export const ARTIFACT_DEPENDENCY_MAP = {
|
|
|
19
19
|
"runtime_validation_report.json",
|
|
20
20
|
"audit-report.md",
|
|
21
21
|
],
|
|
22
|
+
// The optional graph-enrichment pass layers analyzer edges onto graph_bundle
|
|
23
|
+
// and records provenance in analyzer_capability.json. A re-built (structure)
|
|
24
|
+
// graph re-stales the marker so enrichment re-runs. No cycle: the enrichment
|
|
25
|
+
// executor writes graph_bundle AND the marker in one advanceAudit call, and
|
|
26
|
+
// computeArtifactMetadata is dependency-first, so the marker records the
|
|
27
|
+
// post-enrichment graph_bundle revision (mirrors audit-findings → narrative).
|
|
28
|
+
"graph_bundle.json": [
|
|
29
|
+
"analyzer_capability.json",
|
|
30
|
+
],
|
|
22
31
|
"file_disposition.json": [
|
|
23
32
|
"unit_manifest.json",
|
|
24
33
|
"surface_manifest.json",
|
|
@@ -91,6 +100,17 @@ export const ARTIFACT_DEPENDENCY_MAP = {
|
|
|
91
100
|
"runtime_validation_report.json",
|
|
92
101
|
"audit-report.md",
|
|
93
102
|
],
|
|
103
|
+
// Phase 3 delta scope. scope.json is produced by the planning executor (full
|
|
104
|
+
// or delta) and gates coverage: in delta mode it decides which coverage
|
|
105
|
+
// entries are (re)queued vs. inherited-complete/excluded. A changed scope
|
|
106
|
+
// (different `--since`/seed set → new content hash) re-stales coverage so the
|
|
107
|
+
// plan rebuilds. No cycle: planning writes scope.json AND coverage_matrix.json
|
|
108
|
+
// in one advanceAudit call, and computeArtifactMetadata is dependency-first,
|
|
109
|
+
// so coverage records the post-write scope revision (mirrors graph_bundle →
|
|
110
|
+
// analyzer_capability and audit-findings → narrative).
|
|
111
|
+
"scope.json": [
|
|
112
|
+
"coverage_matrix.json",
|
|
113
|
+
],
|
|
94
114
|
"coverage_matrix.json": [
|
|
95
115
|
"flow_coverage.json",
|
|
96
116
|
"audit_plan_metrics.json",
|
|
@@ -115,4 +135,11 @@ export const ARTIFACT_DEPENDENCY_MAP = {
|
|
|
115
135
|
"runtime_validation_report.json": [
|
|
116
136
|
"audit-report.md",
|
|
117
137
|
],
|
|
138
|
+
// The canonical machine contract is co-produced with audit-report.md by the
|
|
139
|
+
// synthesis executor. The optional narrative pass tracks its revision: a fresh
|
|
140
|
+
// (re-synthesized) audit-findings.json re-stales the narrative marker so the
|
|
141
|
+
// themes/executive-summary/top-risks regenerate. See spec/dependency-map.md.
|
|
142
|
+
"audit-findings.json": [
|
|
143
|
+
"synthesis-narrative.json",
|
|
144
|
+
],
|
|
118
145
|
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { GraphBundle, GraphEdge } from "@audit-tools/shared";
|
|
2
|
+
export declare const DEFAULT_EDGE_CONFIDENCE_FLOOR = 0.65;
|
|
3
|
+
/** Bound the candidate set so one pathological repo cannot balloon the call. */
|
|
4
|
+
export declare const MAX_REASONED_EDGES = 200;
|
|
5
|
+
/** One host-supplied reason rewrite, matched to an edge by (from, to, kind). */
|
|
6
|
+
export interface EdgeReasonRewrite {
|
|
7
|
+
from: string;
|
|
8
|
+
to: string;
|
|
9
|
+
/** Optional; when omitted the rewrite matches any candidate with from+to. */
|
|
10
|
+
kind?: string;
|
|
11
|
+
reason: string;
|
|
12
|
+
}
|
|
13
|
+
export interface EdgeReasoningResults {
|
|
14
|
+
rewrites: EdgeReasonRewrite[];
|
|
15
|
+
}
|
|
16
|
+
export interface EdgeReasoningOptions {
|
|
17
|
+
/** Edges strictly below this confidence are candidates (default 0.65). */
|
|
18
|
+
confidenceFloor?: number;
|
|
19
|
+
}
|
|
20
|
+
export interface EdgeReasoningSummary {
|
|
21
|
+
rewritten: number;
|
|
22
|
+
candidates: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Collect the low-confidence edges (the actual edge objects, so the caller can
|
|
26
|
+
* mutate `reason` in place) in a deterministic order. Routes are excluded — they
|
|
27
|
+
* carry no `reason`/`confidence`.
|
|
28
|
+
*/
|
|
29
|
+
export declare function collectLowConfidenceEdges(bundle: GraphBundle, floor?: number): GraphEdge[];
|
|
30
|
+
/** Stable content hash of the candidate edge set, for host-side call caching. */
|
|
31
|
+
export declare function edgeReasoningContentHash(candidates: GraphEdge[]): string;
|
|
32
|
+
/** The single bounded prompt a host runs to produce {@link EdgeReasoningResults}. */
|
|
33
|
+
export declare function buildEdgeReasoningPrompt(candidates: GraphEdge[]): string;
|
|
34
|
+
/**
|
|
35
|
+
* Apply host-supplied reason rewrites to `bundle` (mutated in place). Only edges
|
|
36
|
+
* below the confidence floor are eligible; a rewrite that matches no eligible
|
|
37
|
+
* edge is ignored. Returns a summary; the edge set itself is invariant.
|
|
38
|
+
*/
|
|
39
|
+
export declare function applyEdgeReasoning(bundle: GraphBundle, results: EdgeReasoningResults | undefined, options?: EdgeReasoningOptions): EdgeReasoningSummary;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
/**
|
|
3
|
+
* Phase 4B — optional, bounded edge-reasoning pass.
|
|
4
|
+
*
|
|
5
|
+
* A deterministic transform that may only rewrite the human-readable `reason`
|
|
6
|
+
* of existing low-confidence graph edges. It never adds, removes, re-targets, or
|
|
7
|
+
* re-weights an edge: the `(from, to, kind, confidence, direction)` identity of
|
|
8
|
+
* every edge is preserved exactly. Rewrites are host/provider-supplied (the same
|
|
9
|
+
* conversation-first pattern as the Phase 6 synthesis narrative) — no in-process
|
|
10
|
+
* LLM call. No rewrites (or the config flag off) → no-op, leaving the
|
|
11
|
+
* deterministic graph byte-identical. This is part of the
|
|
12
|
+
* `graph_enrichment_current` obligation.
|
|
13
|
+
*
|
|
14
|
+
* The pass is bounded to edges below a confidence floor (default 0.65) because
|
|
15
|
+
* those are exactly the heuristic edges whose terse machine reason benefits from
|
|
16
|
+
* a clearer explanation; high-confidence compiler/import edges are left alone.
|
|
17
|
+
* {@link buildEdgeReasoningPrompt} and {@link edgeReasoningContentHash} let a
|
|
18
|
+
* host produce and cache that single rewriting call by edge-set content hash.
|
|
19
|
+
*/
|
|
20
|
+
const EDGE_REASONING_VERSION = 1;
|
|
21
|
+
export const DEFAULT_EDGE_CONFIDENCE_FLOOR = 0.65;
|
|
22
|
+
/** Bound the candidate set so one pathological repo cannot balloon the call. */
|
|
23
|
+
export const MAX_REASONED_EDGES = 200;
|
|
24
|
+
function confidenceOf(edge) {
|
|
25
|
+
return typeof edge.confidence === "number" && Number.isFinite(edge.confidence)
|
|
26
|
+
? edge.confidence
|
|
27
|
+
: 0;
|
|
28
|
+
}
|
|
29
|
+
function edgeSignature(edge) {
|
|
30
|
+
return `${edge.from}\0${edge.to}\0${edge.kind ?? ""}`;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Collect the low-confidence edges (the actual edge objects, so the caller can
|
|
34
|
+
* mutate `reason` in place) in a deterministic order. Routes are excluded — they
|
|
35
|
+
* carry no `reason`/`confidence`.
|
|
36
|
+
*/
|
|
37
|
+
export function collectLowConfidenceEdges(bundle, floor = DEFAULT_EDGE_CONFIDENCE_FLOOR) {
|
|
38
|
+
const candidates = [];
|
|
39
|
+
for (const bucket of [
|
|
40
|
+
bundle.graphs.imports,
|
|
41
|
+
bundle.graphs.calls,
|
|
42
|
+
bundle.graphs.references,
|
|
43
|
+
]) {
|
|
44
|
+
for (const edge of bucket ?? []) {
|
|
45
|
+
if (confidenceOf(edge) < floor) {
|
|
46
|
+
candidates.push(edge);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return candidates
|
|
51
|
+
.sort((a, b) => edgeSignature(a).localeCompare(edgeSignature(b)))
|
|
52
|
+
.slice(0, MAX_REASONED_EDGES);
|
|
53
|
+
}
|
|
54
|
+
/** Stable content hash of the candidate edge set, for host-side call caching. */
|
|
55
|
+
export function edgeReasoningContentHash(candidates) {
|
|
56
|
+
const basis = JSON.stringify({
|
|
57
|
+
version: EDGE_REASONING_VERSION,
|
|
58
|
+
edges: candidates.map((edge) => ({
|
|
59
|
+
from: edge.from,
|
|
60
|
+
to: edge.to,
|
|
61
|
+
kind: edge.kind ?? "",
|
|
62
|
+
confidence: confidenceOf(edge),
|
|
63
|
+
reason: edge.reason ?? "",
|
|
64
|
+
})),
|
|
65
|
+
});
|
|
66
|
+
return createHash("sha256").update(basis).digest("hex");
|
|
67
|
+
}
|
|
68
|
+
/** The single bounded prompt a host runs to produce {@link EdgeReasoningResults}. */
|
|
69
|
+
export function buildEdgeReasoningPrompt(candidates) {
|
|
70
|
+
const lines = candidates.map((edge) => `- from: ${edge.from} | to: ${edge.to} | kind: ${edge.kind ?? "?"} | confidence: ${confidenceOf(edge).toFixed(2)} | current: ${edge.reason ?? "(none)"}`);
|
|
71
|
+
return [
|
|
72
|
+
"You are improving the human-readable 'reason' for low-confidence edges in a code dependency graph.",
|
|
73
|
+
"Each edge links a source file to a target file by a relationship 'kind'.",
|
|
74
|
+
"For each edge you can improve, write one clear, specific sentence explaining why that relationship plausibly holds.",
|
|
75
|
+
"Do NOT invent new edges, drop edges, or change which files are linked — only rewrite the reason text.",
|
|
76
|
+
"Omit any edge whose reason you cannot improve.",
|
|
77
|
+
"",
|
|
78
|
+
"Edges:",
|
|
79
|
+
...lines,
|
|
80
|
+
"",
|
|
81
|
+
'Respond with JSON only: {"rewrites":[{"from":"...","to":"...","kind":"...","reason":"..."}]}',
|
|
82
|
+
].join("\n");
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Apply host-supplied reason rewrites to `bundle` (mutated in place). Only edges
|
|
86
|
+
* below the confidence floor are eligible; a rewrite that matches no eligible
|
|
87
|
+
* edge is ignored. Returns a summary; the edge set itself is invariant.
|
|
88
|
+
*/
|
|
89
|
+
export function applyEdgeReasoning(bundle, results, options = {}) {
|
|
90
|
+
const floor = options.confidenceFloor ?? DEFAULT_EDGE_CONFIDENCE_FLOOR;
|
|
91
|
+
const candidates = collectLowConfidenceEdges(bundle, floor);
|
|
92
|
+
if (!results || !Array.isArray(results.rewrites) || candidates.length === 0) {
|
|
93
|
+
return { rewritten: 0, candidates: candidates.length };
|
|
94
|
+
}
|
|
95
|
+
const bySignature = new Map();
|
|
96
|
+
const byEndpoints = new Map();
|
|
97
|
+
for (const edge of candidates) {
|
|
98
|
+
bySignature.set(edgeSignature(edge), edge);
|
|
99
|
+
const endpoints = `${edge.from}\0${edge.to}`;
|
|
100
|
+
if (!byEndpoints.has(endpoints)) {
|
|
101
|
+
byEndpoints.set(endpoints, edge);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
let rewritten = 0;
|
|
105
|
+
const seen = new Set();
|
|
106
|
+
for (const rewrite of results.rewrites) {
|
|
107
|
+
if (!rewrite ||
|
|
108
|
+
typeof rewrite.from !== "string" ||
|
|
109
|
+
typeof rewrite.to !== "string" ||
|
|
110
|
+
typeof rewrite.reason !== "string" ||
|
|
111
|
+
rewrite.reason.trim().length === 0) {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
const edge = rewrite.kind !== undefined
|
|
115
|
+
? bySignature.get(`${rewrite.from}\0${rewrite.to}\0${rewrite.kind}`)
|
|
116
|
+
: byEndpoints.get(`${rewrite.from}\0${rewrite.to}`);
|
|
117
|
+
if (!edge || seen.has(edge)) {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
edge.reason = rewrite.reason.trim();
|
|
121
|
+
seen.add(edge);
|
|
122
|
+
rewritten += 1;
|
|
123
|
+
}
|
|
124
|
+
return { rewritten, candidates: candidates.length };
|
|
125
|
+
}
|
|
@@ -9,6 +9,11 @@ export const EXECUTOR_REGISTRY = [
|
|
|
9
9
|
obligation_ids: ["structure_artifacts"],
|
|
10
10
|
description: "Build structure artifacts such as units, surfaces, graphs, flows, and risk.",
|
|
11
11
|
},
|
|
12
|
+
{
|
|
13
|
+
id: "graph_enrichment_executor",
|
|
14
|
+
obligation_ids: ["graph_enrichment_current"],
|
|
15
|
+
description: "Layer optional language-analyzer edges onto the deterministic graph (regex floor preserved); record analyzer provenance.",
|
|
16
|
+
},
|
|
12
17
|
{
|
|
13
18
|
id: "design_assessment_executor",
|
|
14
19
|
obligation_ids: ["design_assessment_current"],
|
|
@@ -42,7 +47,12 @@ export const EXECUTOR_REGISTRY = [
|
|
|
42
47
|
{
|
|
43
48
|
id: "synthesis_executor",
|
|
44
49
|
obligation_ids: ["synthesis_current"],
|
|
45
|
-
description: "
|
|
50
|
+
description: "Emit the canonical audit-findings.json and render the deterministic Markdown audit report.",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: "synthesis_narrative_executor",
|
|
54
|
+
obligation_ids: ["synthesis_narrative_current"],
|
|
55
|
+
description: "Resolve the optional synthesis narrative (themes, executive summary, top risks); omit deterministically without a provider.",
|
|
46
56
|
},
|
|
47
57
|
{
|
|
48
58
|
id: "external_analyzer_import_executor",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ExternalAnalyzerResults } from "../types/externalAnalyzer.js";
|
|
2
|
-
import type { GraphBundle } from "
|
|
2
|
+
import type { GraphBundle } from "@audit-tools/shared";
|
|
3
3
|
export type FileAnchorKind = "boundary" | "import" | "export" | "symbol" | "route" | "keyword" | "graph" | "analyzer_signal";
|
|
4
4
|
export interface FileAnchor {
|
|
5
5
|
kind: FileAnchorKind;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RepoManifest } from "../types.js";
|
|
2
|
+
export interface FileIntegrityResult {
|
|
3
|
+
changed_files: string[];
|
|
4
|
+
missing_files: string[];
|
|
5
|
+
is_clean: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function checkFileIntegrity(root: string, manifest: RepoManifest, scope?: string[]): Promise<FileIntegrityResult>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { join, isAbsolute } from "node:path";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
async function hashFile(absolutePath) {
|
|
6
|
+
const content = await readFile(absolutePath);
|
|
7
|
+
return createHash("sha256").update(content).digest("hex");
|
|
8
|
+
}
|
|
9
|
+
export async function checkFileIntegrity(root, manifest, scope) {
|
|
10
|
+
const changed = [];
|
|
11
|
+
const missing = [];
|
|
12
|
+
const scopeSet = scope ? new Set(scope) : null;
|
|
13
|
+
const files = scopeSet
|
|
14
|
+
? manifest.files.filter((f) => scopeSet.has(f.path))
|
|
15
|
+
: manifest.files;
|
|
16
|
+
for (const record of files) {
|
|
17
|
+
if (!record.hash)
|
|
18
|
+
continue;
|
|
19
|
+
const absolute = isAbsolute(record.path)
|
|
20
|
+
? record.path
|
|
21
|
+
: join(root, record.path);
|
|
22
|
+
if (!existsSync(absolute)) {
|
|
23
|
+
missing.push(record.path);
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const currentHash = await hashFile(absolute);
|
|
28
|
+
if (currentHash !== record.hash) {
|
|
29
|
+
changed.push(record.path);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
missing.push(record.path);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
changed_files: changed,
|
|
38
|
+
missing_files: missing,
|
|
39
|
+
is_clean: changed.length === 0 && missing.length === 0,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { CoverageMatrix } from "../types.js";
|
|
2
2
|
import type { FlowCoverageManifest } from "../types/flowCoverage.js";
|
|
3
|
-
import type { CriticalFlowManifest } from "
|
|
3
|
+
import type { CriticalFlowManifest } from "@audit-tools/shared";
|
|
4
4
|
export declare function buildFlowCoverage(criticalFlows: CriticalFlowManifest, coverageMatrix: CoverageMatrix): FlowCoverageManifest;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ExternalAnalyzerResults } from "../types/externalAnalyzer.js";
|
|
2
2
|
import type { AuditTask, CoverageMatrix } from "../types.js";
|
|
3
3
|
import type { FlowCoverageManifest } from "../types/flowCoverage.js";
|
|
4
|
-
import type { CriticalFlowManifest } from "
|
|
4
|
+
import type { CriticalFlowManifest } from "@audit-tools/shared";
|
|
5
5
|
export declare function buildFlowRequeueTasks(criticalFlows: CriticalFlowManifest, flowCoverage: FlowCoverageManifest, coverageMatrix: CoverageMatrix, externalAnalyzerResults?: ExternalAnalyzerResults): AuditTask[];
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ArtifactBundle } from "../io/artifacts.js";
|
|
2
|
+
import type { ExecutorRunResult } from "./internalExecutors.js";
|
|
3
|
+
import type { AnalyzerSetting } from "@audit-tools/shared";
|
|
4
|
+
import type { LanguageAnalyzer } from "../extractors/analyzers/types.js";
|
|
5
|
+
import { type EdgeReasoningResults } from "./edgeReasoning.js";
|
|
6
|
+
export interface GraphEnrichmentOptions {
|
|
7
|
+
root?: string;
|
|
8
|
+
analyzers?: Record<string, AnalyzerSetting>;
|
|
9
|
+
/** Injectable for tests; defaults to the global registry. */
|
|
10
|
+
registry?: LanguageAnalyzer[];
|
|
11
|
+
/** Injectable analyzer-cache root; defaults to ~/.audit-tools/analyzer-cache. */
|
|
12
|
+
cacheRoot?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Phase 4B: gate for the optional edge-reasoning pass (mirrors
|
|
15
|
+
* session-config `graph.llm_edge_reasoning`; default off).
|
|
16
|
+
*/
|
|
17
|
+
llmEdgeReasoning?: boolean;
|
|
18
|
+
/** Phase 4B: host-supplied reason rewrites for low-confidence edges. */
|
|
19
|
+
edgeReasoning?: EdgeReasoningResults;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Resolve the optional graph-enrichment obligation. Layers language-analyzer
|
|
23
|
+
* edges onto the deterministic regex floor in `graph_bundle.json`
|
|
24
|
+
* (higher-confidence-kind-wins) and records provenance in
|
|
25
|
+
* `analyzer_capability.json`. With no root, or when every analyzer skips / is
|
|
26
|
+
* absent / not-applicable, the graph bundle is left byte-identical to the floor
|
|
27
|
+
* and only the marker is written.
|
|
28
|
+
*/
|
|
29
|
+
export declare function runGraphEnrichmentExecutor(bundle: ArtifactBundle, options?: GraphEnrichmentOptions): Promise<ExecutorRunResult>;
|