audit-tools 0.40.1 → 0.41.1
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/dist/audit/cli/auditStep.d.ts +1 -1
- package/dist/audit/cli/conceptualDispatch.d.ts +3 -0
- package/dist/audit/cli/conceptualDispatch.d.ts.map +1 -1
- package/dist/audit/cli/conceptualDispatch.js +82 -24
- package/dist/audit/cli/conceptualDispatch.js.map +1 -1
- package/dist/audit/cli/dispatch/hostHandoff.d.ts +12 -0
- package/dist/audit/cli/dispatch/hostHandoff.d.ts.map +1 -1
- package/dist/audit/cli/dispatch/hostHandoff.js +169 -78
- package/dist/audit/cli/dispatch/hostHandoff.js.map +1 -1
- package/dist/audit/cli/fanoutLanes.d.ts +47 -11
- package/dist/audit/cli/fanoutLanes.d.ts.map +1 -1
- package/dist/audit/cli/fanoutLanes.js +15 -7
- package/dist/audit/cli/fanoutLanes.js.map +1 -1
- package/dist/audit/cli/laneSubmissions.d.ts +241 -0
- package/dist/audit/cli/laneSubmissions.d.ts.map +1 -0
- package/dist/audit/cli/laneSubmissions.js +438 -0
- package/dist/audit/cli/laneSubmissions.js.map +1 -0
- package/dist/audit/cli/laneValidators.d.ts +65 -0
- package/dist/audit/cli/laneValidators.d.ts.map +1 -0
- package/dist/audit/cli/laneValidators.js +145 -0
- package/dist/audit/cli/laneValidators.js.map +1 -0
- package/dist/audit/cli/nextStepCommand.d.ts +1 -1
- package/dist/audit/cli/nextStepCommand.d.ts.map +1 -1
- package/dist/audit/cli/nextStepCommand.js +118 -69
- package/dist/audit/cli/nextStepCommand.js.map +1 -1
- package/dist/audit/cli/nextStepHelpers.d.ts +73 -42
- package/dist/audit/cli/nextStepHelpers.d.ts.map +1 -1
- package/dist/audit/cli/nextStepHelpers.js +389 -253
- package/dist/audit/cli/nextStepHelpers.js.map +1 -1
- package/dist/audit/cli/recoverSubmissionCommand.d.ts +16 -0
- package/dist/audit/cli/recoverSubmissionCommand.d.ts.map +1 -0
- package/dist/audit/cli/recoverSubmissionCommand.js +73 -0
- package/dist/audit/cli/recoverSubmissionCommand.js.map +1 -0
- package/dist/audit/cli/semanticReviewStep.d.ts +3 -0
- package/dist/audit/cli/semanticReviewStep.d.ts.map +1 -1
- package/dist/audit/cli/semanticReviewStep.js +30 -1
- package/dist/audit/cli/semanticReviewStep.js.map +1 -1
- package/dist/audit/cli/steps.d.ts +75 -2
- package/dist/audit/cli/steps.d.ts.map +1 -1
- package/dist/audit/cli/steps.js +14 -0
- package/dist/audit/cli/steps.js.map +1 -1
- package/dist/audit/cli.d.ts.map +1 -1
- package/dist/audit/cli.js +5 -1
- package/dist/audit/cli.js.map +1 -1
- package/dist/audit/contracts/wrapperResponse.d.ts +7 -7
- package/dist/audit/contracts/wrapperResponse.js +1 -1
- package/dist/audit/contracts/wrapperResponse.js.map +1 -1
- package/dist/audit/io/artifacts.d.ts +12 -1
- package/dist/audit/io/artifacts.d.ts.map +1 -1
- package/dist/audit/io/artifacts.js +28 -1
- package/dist/audit/io/artifacts.js.map +1 -1
- package/dist/audit/orchestrator/ingestionExecutors.d.ts.map +1 -1
- package/dist/audit/orchestrator/ingestionExecutors.js +13 -16
- package/dist/audit/orchestrator/ingestionExecutors.js.map +1 -1
- package/dist/audit/orchestrator/lensSelection.d.ts +19 -0
- package/dist/audit/orchestrator/lensSelection.d.ts.map +1 -1
- package/dist/audit/orchestrator/lensSelection.js +24 -0
- package/dist/audit/orchestrator/lensSelection.js.map +1 -1
- package/dist/audit/orchestrator/planningExecutors.d.ts +1 -12
- package/dist/audit/orchestrator/planningExecutors.d.ts.map +1 -1
- package/dist/audit/orchestrator/planningExecutors.js +14 -64
- package/dist/audit/orchestrator/planningExecutors.js.map +1 -1
- package/dist/audit/orchestrator/requeueFold.d.ts +43 -0
- package/dist/audit/orchestrator/requeueFold.d.ts.map +1 -0
- package/dist/audit/orchestrator/requeueFold.js +50 -0
- package/dist/audit/orchestrator/requeueFold.js.map +1 -0
- package/dist/audit/orchestrator/synthesisExecutors.d.ts.map +1 -1
- package/dist/audit/orchestrator/synthesisExecutors.js +2 -0
- package/dist/audit/orchestrator/synthesisExecutors.js.map +1 -1
- package/dist/audit/reporting/synthesis.d.ts +9 -1
- package/dist/audit/reporting/synthesis.d.ts.map +1 -1
- package/dist/audit/reporting/synthesis.js +69 -1
- package/dist/audit/reporting/synthesis.js.map +1 -1
- package/dist/audit/supervisor/operatorHandoff.d.ts +9 -2
- package/dist/audit/supervisor/operatorHandoff.d.ts.map +1 -1
- package/dist/audit/supervisor/operatorHandoff.js +17 -10
- package/dist/audit/supervisor/operatorHandoff.js.map +1 -1
- package/dist/audit/types/designAssessment.d.ts +9 -5
- package/dist/audit/types/designAssessment.d.ts.map +1 -1
- package/dist/remediate/index.d.ts.map +1 -1
- package/dist/remediate/index.js +48 -1
- package/dist/remediate/index.js.map +1 -1
- package/dist/remediate/steps/dispatch/hostHandoff.d.ts +38 -6
- package/dist/remediate/steps/dispatch/hostHandoff.d.ts.map +1 -1
- package/dist/remediate/steps/dispatch/hostHandoff.js +87 -75
- package/dist/remediate/steps/dispatch/hostHandoff.js.map +1 -1
- package/dist/shared/decompose/charterClarification.d.ts +1 -1
- package/dist/shared/decompose/charterClarification.js +1 -1
- package/dist/shared/decompose/charterExtraction.js +1 -1
- package/dist/shared/decompose/charterExtraction.js.map +1 -1
- package/dist/shared/decompose/systemicChallenge.js +1 -1
- package/dist/shared/decompose/systemicChallenge.js.map +1 -1
- package/dist/shared/index.d.ts +12 -2
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js +7 -2
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/io/auditToolsPaths.d.ts +24 -4
- package/dist/shared/io/auditToolsPaths.d.ts.map +1 -1
- package/dist/shared/io/auditToolsPaths.js +29 -5
- package/dist/shared/io/auditToolsPaths.js.map +1 -1
- package/dist/shared/io/schemaVersion.d.ts +5 -4
- package/dist/shared/io/schemaVersion.d.ts.map +1 -1
- package/dist/shared/io/schemaVersion.js +17 -5
- package/dist/shared/io/schemaVersion.js.map +1 -1
- package/dist/shared/loopCorePaths.d.ts.map +1 -1
- package/dist/shared/loopCorePaths.js +8 -2
- package/dist/shared/loopCorePaths.js.map +1 -1
- package/dist/shared/submission/expectedSubmissions.d.ts +88 -0
- package/dist/shared/submission/expectedSubmissions.d.ts.map +1 -0
- package/dist/shared/submission/expectedSubmissions.js +84 -0
- package/dist/shared/submission/expectedSubmissions.js.map +1 -0
- package/dist/shared/submission/handRecovery.d.ts +37 -0
- package/dist/shared/submission/handRecovery.d.ts.map +1 -0
- package/dist/shared/submission/handRecovery.js +123 -0
- package/dist/shared/submission/handRecovery.js.map +1 -0
- package/dist/shared/submission/submissionClassifier.d.ts +48 -0
- package/dist/shared/submission/submissionClassifier.d.ts.map +1 -0
- package/dist/shared/submission/submissionClassifier.js +83 -0
- package/dist/shared/submission/submissionClassifier.js.map +1 -0
- package/dist/shared/submission/submissionIdentity.d.ts +49 -0
- package/dist/shared/submission/submissionIdentity.d.ts.map +1 -0
- package/dist/shared/submission/submissionIdentity.js +90 -0
- package/dist/shared/submission/submissionIdentity.js.map +1 -0
- package/dist/shared/submission/submissionLedger.d.ts +37 -0
- package/dist/shared/submission/submissionLedger.d.ts.map +1 -0
- package/dist/shared/submission/submissionLedger.js +81 -0
- package/dist/shared/submission/submissionLedger.js.map +1 -0
- package/dist/shared/types/finding.d.ts +16 -0
- package/dist/shared/types/finding.d.ts.map +1 -1
- package/dist/shared/types/finding.js +60 -0
- package/dist/shared/types/finding.js.map +1 -1
- package/docs/audit-pkg/product.md +0 -2
- package/package.json +1 -1
|
@@ -31,7 +31,7 @@ export interface RunAuditStepOptions {
|
|
|
31
31
|
/**
|
|
32
32
|
* Already-validated edge-reasoning rewrites. Parsed + shape-checked by the
|
|
33
33
|
* caller (`handleGraphEnrichmentBranch` tolerant-unwraps or quarantines the
|
|
34
|
-
*
|
|
34
|
+
* submission) — never a raw file path, so no unvalidated cast here.
|
|
35
35
|
*/
|
|
36
36
|
edgeReasoningResults?: EdgeReasoningResults;
|
|
37
37
|
analyzers?: Record<string, AnalyzerSetting>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type IntentCheckpoint } from "audit-tools/shared";
|
|
2
2
|
import type { ArtifactBundle } from "../io/artifacts.js";
|
|
3
|
+
import { type LaneSubmissionShortfall } from "./laneSubmissions.js";
|
|
3
4
|
export interface ConceptualReviewSettings {
|
|
4
5
|
max_units?: number;
|
|
5
6
|
conceptual_depth: "shallow" | "deep";
|
|
@@ -54,6 +55,8 @@ export interface ConceptualDispatch {
|
|
|
54
55
|
readPaths: string[];
|
|
55
56
|
/** Result files the host's subagents write. */
|
|
56
57
|
writePaths: string[];
|
|
58
|
+
/** What a previous emission of this pass's lanes is still owed. */
|
|
59
|
+
shortfall: LaneSubmissionShortfall;
|
|
57
60
|
}
|
|
58
61
|
/**
|
|
59
62
|
* Write the conceptual-review prompt artifacts and return the host workload.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conceptualDispatch.d.ts","sourceRoot":"","sources":["../../../src/audit/cli/conceptualDispatch.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"conceptualDispatch.d.ts","sourceRoot":"","sources":["../../../src/audit/cli/conceptualDispatch.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,gBAAgB,EAEtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAUzD,OAAO,EAML,KAAK,uBAAuB,EAC7B,MAAM,sBAAsB,CAAC;AAE9B,MAAM,WAAW,wBAAwB;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,SAAS,GAAG,MAAM,CAAC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,WAAW,CAAC,gBAAgB,CAAC,eAAe,CAAC,CAAC,EAC1D,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,aAAa,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,EACjD,aAAa,EAAE,SAAS,GAAG,MAAM,GAChC,MAAM,CAUR;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,cAAc,GACrB,wBAAwB,CA+B1B;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,OAAO,CAAC;IACd;;;OAGG;IACH,qBAAqB,EAAE,MAAM,CAAC;IAC9B,mEAAmE;IACnE,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,mDAAmD;IACnD,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,8CAA8C;IAC9C,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,+CAA+C;IAC/C,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,mEAAmE;IACnE,SAAS,EAAE,uBAAuB,CAAC;CACpC;AAED;;;;;;;;GAQG;AACH,wBAAsB,yBAAyB,CAAC,IAAI,EAAE;IACpD,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,EAAE,wBAAwB,CAAC;IACnC;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAoK9B"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
-
import { join } from "node:path";
|
|
3
1
|
import { charterReviewDisposition, } from "audit-tools/shared";
|
|
4
2
|
import { renderConceptualReviewPrompt, renderConceptualPerspectivePrompt, renderConceptualJudgePrompt, selectPerspectives, } from "../orchestrator/designReviewPrompt.js";
|
|
3
|
+
import { materializeFanoutLanes } from "./fanoutLanes.js";
|
|
4
|
+
import { AUDIT_GATE_SUBMISSION_SCOPE, GATE_LANES, conceptualPerspectiveLane, conceptualRoundToken, laneSubmissionPath, } from "./laneSubmissions.js";
|
|
5
5
|
/**
|
|
6
6
|
* Render the host-visible reuse notice when a prior `intent_checkpoint.design_review`
|
|
7
7
|
* drives this workload. Content-sorted lens list keeps the text stable (no churn),
|
|
@@ -63,14 +63,26 @@ export async function prepareConceptualDispatch(opts) {
|
|
|
63
63
|
const reReviewSuffix = opts.reReviewSection
|
|
64
64
|
? `\n\n${opts.reReviewSection}`
|
|
65
65
|
: "";
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
// The single conceptual submission the orchestrator ingests — written by the
|
|
67
|
+
// lone reviewer when shallow, by the independent judge when deep. Either way
|
|
68
|
+
// it is the `design_review_conceptual` LANE, so the gate reads one bound path
|
|
69
|
+
// and the state machine is unchanged by the depth choice.
|
|
70
|
+
const conceptualResultsPath = laneSubmissionPath(artifactsDir, GATE_LANES.design_review_conceptual);
|
|
69
71
|
const reviewOptions = { max_units: settings.max_units };
|
|
70
72
|
if (settings.conceptual_depth !== "deep") {
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
const fanout = await materializeFanoutLanes({
|
|
74
|
+
artifactsDir,
|
|
75
|
+
runId: AUDIT_GATE_SUBMISSION_SCOPE,
|
|
76
|
+
lanes: [
|
|
77
|
+
{
|
|
78
|
+
id: GATE_LANES.design_review_conceptual,
|
|
79
|
+
label: "Conceptual review (generative)",
|
|
80
|
+
promptFilename: "design-review-conceptual-prompt.md",
|
|
81
|
+
promptText: renderConceptualReviewPrompt(bundle, reviewOptions) + reReviewSuffix,
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
});
|
|
85
|
+
const conceptualPromptPath = fanout.lanes[0].promptPath;
|
|
74
86
|
return {
|
|
75
87
|
deep: false,
|
|
76
88
|
conceptualResultsPath,
|
|
@@ -84,29 +96,74 @@ export async function prepareConceptualDispatch(opts) {
|
|
|
84
96
|
},
|
|
85
97
|
readPaths: [conceptualPromptPath],
|
|
86
98
|
writePaths: [conceptualResultsPath],
|
|
99
|
+
shortfall: fanout.shortfall,
|
|
87
100
|
};
|
|
88
101
|
}
|
|
89
102
|
// Deep: real fan-out — N perspective subagents + an independent judge.
|
|
103
|
+
// Every one of them is a LANE through the same materializer the rest of the
|
|
104
|
+
// audit uses; this pass used to mint its own filenames, which is precisely how
|
|
105
|
+
// a second naming convention (and a second way for a host to mistype one)
|
|
106
|
+
// came to exist.
|
|
90
107
|
const perspectives = selectPerspectives(settings.perspectives);
|
|
91
108
|
const total = perspectives.length;
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
109
|
+
const perspectiveTexts = perspectives.map((p, i) => renderConceptualPerspectivePrompt(bundle, p, i, total, reviewOptions));
|
|
110
|
+
// The round the perspectives are being asked about: the prompts themselves
|
|
111
|
+
// (the whole upstream projection each perspective reads) plus the judge's
|
|
112
|
+
// re-review section, which is present exactly when this is a re-review after
|
|
113
|
+
// staleness. A fresh round therefore mints fresh lane ids and fresh prompts;
|
|
114
|
+
// an unchanged one re-declares the identical bound paths.
|
|
115
|
+
const roundToken = conceptualRoundToken([
|
|
116
|
+
...perspectiveTexts,
|
|
117
|
+
opts.reReviewSection ?? "",
|
|
118
|
+
]);
|
|
119
|
+
const perspectiveFiles = perspectives.map((p, i) => {
|
|
120
|
+
const lane = conceptualPerspectiveLane(i + 1, roundToken);
|
|
121
|
+
return {
|
|
122
|
+
name: p.name,
|
|
123
|
+
lane,
|
|
124
|
+
promptFilename: `design-review-conceptual-p${i + 1}-prompt.md`,
|
|
125
|
+
promptText: perspectiveTexts[i],
|
|
126
|
+
resultsPath: laneSubmissionPath(artifactsDir, lane, AUDIT_GATE_SUBMISSION_SCOPE),
|
|
127
|
+
};
|
|
128
|
+
});
|
|
102
129
|
const judgePromptText = renderConceptualJudgePrompt(perspectiveFiles.map((f) => ({ name: f.name, path: f.resultsPath }))) + reReviewSuffix;
|
|
103
|
-
|
|
104
|
-
|
|
130
|
+
const laneSpecs = [
|
|
131
|
+
...perspectiveFiles.map((f) => ({
|
|
132
|
+
id: f.lane,
|
|
133
|
+
label: `Conceptual perspective — ${f.name}`,
|
|
134
|
+
promptFilename: f.promptFilename,
|
|
135
|
+
promptText: f.promptText,
|
|
136
|
+
// A perspective's findings are read by the JUDGE, never by this tool —
|
|
137
|
+
// so the tool is owed nothing here and must not record an expectation it
|
|
138
|
+
// will never satisfy. The bound path is still minted and declared below.
|
|
139
|
+
expected: false,
|
|
140
|
+
})),
|
|
141
|
+
{
|
|
142
|
+
// The judge PRODUCES the conceptual submission, so it is that lane — a
|
|
143
|
+
// separate judge lane id would mint a bound path nothing reads.
|
|
144
|
+
id: GATE_LANES.design_review_conceptual,
|
|
145
|
+
label: "Conceptual review judge (independent merge)",
|
|
146
|
+
promptFilename: "design-review-conceptual-judge-prompt.md",
|
|
147
|
+
promptText: judgePromptText,
|
|
148
|
+
},
|
|
149
|
+
];
|
|
150
|
+
const fanout = await materializeFanoutLanes({
|
|
151
|
+
artifactsDir,
|
|
152
|
+
runId: AUDIT_GATE_SUBMISSION_SCOPE,
|
|
153
|
+
lanes: laneSpecs,
|
|
154
|
+
});
|
|
155
|
+
const promptPathFor = (laneId) => fanout.lanes.find((lane) => lane.id === laneId).promptPath;
|
|
156
|
+
const judgePromptPath = promptPathFor(GATE_LANES.design_review_conceptual);
|
|
157
|
+
const perspectivePrompts = perspectiveFiles.map((f) => ({
|
|
158
|
+
...f,
|
|
159
|
+
promptPath: promptPathFor(f.lane),
|
|
160
|
+
}));
|
|
161
|
+
const perspectiveLines = perspectivePrompts.map((f, i) => ` - Perspective ${i + 1} (${f.name}): prompt \`${f.promptPath}\` → findings \`${f.resultsPath}\``);
|
|
105
162
|
const artifactPaths = {
|
|
106
163
|
conceptual_results: conceptualResultsPath,
|
|
107
164
|
conceptual_judge_prompt: judgePromptPath,
|
|
108
165
|
};
|
|
109
|
-
|
|
166
|
+
perspectivePrompts.forEach((f, i) => {
|
|
110
167
|
artifactPaths[`conceptual_perspective_${i + 1}_prompt`] = f.promptPath;
|
|
111
168
|
artifactPaths[`conceptual_perspective_${i + 1}_results`] = f.resultsPath;
|
|
112
169
|
});
|
|
@@ -125,14 +182,15 @@ export async function prepareConceptualDispatch(opts) {
|
|
|
125
182
|
// Perspective result files must be in readPaths: the judge subagent reads
|
|
126
183
|
// them to merge and synthesise the final output (COR-60ca1f72).
|
|
127
184
|
readPaths: [
|
|
128
|
-
...
|
|
129
|
-
...
|
|
185
|
+
...perspectivePrompts.map((f) => f.promptPath),
|
|
186
|
+
...perspectivePrompts.map((f) => f.resultsPath),
|
|
130
187
|
judgePromptPath,
|
|
131
188
|
],
|
|
132
189
|
writePaths: [
|
|
133
|
-
...
|
|
190
|
+
...perspectivePrompts.map((f) => f.resultsPath),
|
|
134
191
|
conceptualResultsPath,
|
|
135
192
|
],
|
|
193
|
+
shortfall: fanout.shortfall,
|
|
136
194
|
};
|
|
137
195
|
}
|
|
138
196
|
//# sourceMappingURL=conceptualDispatch.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conceptualDispatch.js","sourceRoot":"","sources":["../../../src/audit/cli/conceptualDispatch.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"conceptualDispatch.js","sourceRoot":"","sources":["../../../src/audit/cli/conceptualDispatch.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type SubmissionIssue } from "audit-tools/shared";
|
|
1
2
|
import { type AuditResult } from "../../types.js";
|
|
2
3
|
declare const WORKLOAD_CONTRACT_VERSION: "audit-host-workload/v1alpha1";
|
|
3
4
|
declare const RESULT_MAP_CONTRACT_VERSION: "audit-host-result-map/v1alpha1";
|
|
@@ -58,6 +59,17 @@ export interface AuditHostIngestSummary {
|
|
|
58
59
|
readonly accepted_results: readonly AuditResult[];
|
|
59
60
|
readonly accepted_results_path: string;
|
|
60
61
|
readonly completed_work_item_ids: readonly string[];
|
|
62
|
+
/**
|
|
63
|
+
* Every submission this ingest could not accept, classified.
|
|
64
|
+
*
|
|
65
|
+
* The four ways a submission used to fail — absent file, unparseable bytes, a
|
|
66
|
+
* body that violates the result contract, and a conversion that yields
|
|
67
|
+
* nothing — all collapsed into the same bare `null` and the same silent
|
|
68
|
+
* `continue`. A host that never wrote its result and a host that wrote
|
|
69
|
+
* garbage were indistinguishable to every caller, which is exactly the
|
|
70
|
+
* measured drift P25 exists to make visible.
|
|
71
|
+
*/
|
|
72
|
+
readonly issues: readonly SubmissionIssue[];
|
|
61
73
|
}
|
|
62
74
|
export declare function prepareAuditHostHandoff(params: {
|
|
63
75
|
readonly root: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hostHandoff.d.ts","sourceRoot":"","sources":["../../../../src/audit/cli/dispatch/hostHandoff.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hostHandoff.d.ts","sourceRoot":"","sources":["../../../../src/audit/cli/dispatch/hostHandoff.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
1
|
import { mkdir } from "node:fs/promises";
|
|
3
|
-
import {
|
|
4
|
-
import { FindingSchema,
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { FindingSchema, findingContractPromptLines, assertSubmissionRunId, hashContent, isFileMissingError, readJsonFile, readSubmissionDocument, repoRelativePath, resolveContainedPath, stableStringify, submissionPathFor, writeJsonFile, } from "audit-tools/shared";
|
|
5
4
|
import { AuditResultSchema } from "../../types.js";
|
|
6
5
|
const WORKLOAD_CONTRACT_VERSION = "audit-host-workload/v1alpha1";
|
|
7
6
|
const RESULT_MAP_CONTRACT_VERSION = "audit-host-result-map/v1alpha1";
|
|
@@ -11,9 +10,6 @@ const ACCEPTED_RESULTS_CONTRACT_VERSION = "audit-host-accepted-results/v1alpha1"
|
|
|
11
10
|
function compareCodeUnits(left, right) {
|
|
12
11
|
return left < right ? -1 : left > right ? 1 : 0;
|
|
13
12
|
}
|
|
14
|
-
function sha256(value) {
|
|
15
|
-
return createHash("sha256").update(value, "utf8").digest("hex");
|
|
16
|
-
}
|
|
17
13
|
function isRecord(value) {
|
|
18
14
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
19
15
|
}
|
|
@@ -25,38 +21,11 @@ function hasExactKeys(value, expected) {
|
|
|
25
21
|
function isSha256(value) {
|
|
26
22
|
return typeof value === "string" && /^[0-9a-f]{64}$/u.test(value);
|
|
27
23
|
}
|
|
28
|
-
function assertRunId(runId) {
|
|
29
|
-
if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u.test(runId) ||
|
|
30
|
-
runId === "." ||
|
|
31
|
-
runId === "..") {
|
|
32
|
-
throw new Error(`Invalid audit host run id: ${JSON.stringify(runId)}`);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
function resolveContained(base, candidate, label) {
|
|
36
|
-
const absoluteBase = resolve(base);
|
|
37
|
-
const absoluteCandidate = isAbsolute(candidate)
|
|
38
|
-
? resolve(candidate)
|
|
39
|
-
: resolve(absoluteBase, candidate);
|
|
40
|
-
const rel = relative(absoluteBase, absoluteCandidate);
|
|
41
|
-
const firstSegment = rel.split(/[\\/]/u)[0];
|
|
42
|
-
if (isAbsolute(rel) || firstSegment === "..") {
|
|
43
|
-
throw new Error(`${label} must remain beneath ${absoluteBase}`);
|
|
44
|
-
}
|
|
45
|
-
return absoluteCandidate;
|
|
46
|
-
}
|
|
47
|
-
function repoRelative(root, absolutePath, label) {
|
|
48
|
-
const contained = resolveContained(root, absolutePath, label);
|
|
49
|
-
const rel = relative(resolve(root), contained).replaceAll("\\", "/");
|
|
50
|
-
if (rel.length === 0) {
|
|
51
|
-
throw new Error(`${label} must identify a path beneath the repository root`);
|
|
52
|
-
}
|
|
53
|
-
return rel;
|
|
54
|
-
}
|
|
55
24
|
function resolveBoundaryPaths(params) {
|
|
56
|
-
|
|
25
|
+
assertSubmissionRunId(params.runId, "audit host run id");
|
|
57
26
|
const root = resolve(params.root);
|
|
58
|
-
const artifactsDir =
|
|
59
|
-
const runDir =
|
|
27
|
+
const artifactsDir = resolveContainedPath(root, params.artifactsDir, "artifactsDir");
|
|
28
|
+
const runDir = resolveContainedPath(artifactsDir, join("runs", params.runId), "audit host run directory");
|
|
60
29
|
return {
|
|
61
30
|
root,
|
|
62
31
|
artifactsDir,
|
|
@@ -69,9 +38,14 @@ function resolveBoundaryPaths(params) {
|
|
|
69
38
|
acceptedResultsPath: join(runDir, "host-accepted-results.json"),
|
|
70
39
|
};
|
|
71
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* The bound path for one work item's submission — the SHARED rule, not a local
|
|
43
|
+
* copy of it. The audit and remediate handoffs both derived
|
|
44
|
+
* `<resultDir>/<sha256(id)>.json` in their own private helpers; a divergence
|
|
45
|
+
* between the two would have been silent on both sides.
|
|
46
|
+
*/
|
|
72
47
|
function resultPathFor(paths, workItemId) {
|
|
73
|
-
|
|
74
|
-
return repoRelative(paths.root, absolute, `result path for ${workItemId}`);
|
|
48
|
+
return submissionPathFor({ root: paths.root, submissionDir: paths.resultDir }, workItemId);
|
|
75
49
|
}
|
|
76
50
|
function requireNonEmptyString(value, label) {
|
|
77
51
|
if (typeof value !== "string" || value.length === 0) {
|
|
@@ -102,13 +76,13 @@ function normalizeTask(task, root) {
|
|
|
102
76
|
const files = [
|
|
103
77
|
...new Set(task.file_paths.map((path) => {
|
|
104
78
|
const raw = requireNonEmptyString(path, `${taskId}.file_paths[]`);
|
|
105
|
-
const absolute =
|
|
106
|
-
return
|
|
79
|
+
const absolute = resolveContainedPath(root, raw, `${taskId} file path`);
|
|
80
|
+
return repoRelativePath(root, absolute, `${taskId} file path`);
|
|
107
81
|
})),
|
|
108
82
|
].sort(compareCodeUnits);
|
|
109
83
|
const normalizedLineCounts = {};
|
|
110
84
|
for (const [path, count] of Object.entries(task.file_line_counts)) {
|
|
111
|
-
const normalizedPath =
|
|
85
|
+
const normalizedPath = repoRelativePath(root, resolveContainedPath(root, path, `${taskId} line-count path`), `${taskId} line-count path`);
|
|
112
86
|
if (!Number.isInteger(count) || count < 0) {
|
|
113
87
|
throw new Error(`${taskId} has an invalid line count for ${path}`);
|
|
114
88
|
}
|
|
@@ -153,7 +127,10 @@ function buildPrompt(task, resultPath) {
|
|
|
153
127
|
"Review every listed file and return one JSON object at the bound result path.",
|
|
154
128
|
`Assignment: ${assignment}`,
|
|
155
129
|
"Result contract: audit-host-result/v1alpha1 with exactly result_id, run_id, work_item_id, prompt_sha256, file_coverage, and findings in addition to contract_version.",
|
|
156
|
-
"Each file_coverage entry must contain exactly path, reviewed_lines, and total_lines
|
|
130
|
+
"Each file_coverage entry must contain exactly path, reviewed_lines, and total_lines.",
|
|
131
|
+
// The finding contract is CARRIED, not referenced: it is rendered from the
|
|
132
|
+
// very schema ingestion enforces, so a host never has to remember or fetch it.
|
|
133
|
+
...findingContractPromptLines(),
|
|
157
134
|
].join("\n");
|
|
158
135
|
}
|
|
159
136
|
function buildWorkItem(paths, task) {
|
|
@@ -168,7 +145,7 @@ function buildWorkItem(paths, task) {
|
|
|
168
145
|
token_estimate: task.token_estimate,
|
|
169
146
|
},
|
|
170
147
|
prompt: {
|
|
171
|
-
sha256:
|
|
148
|
+
sha256: hashContent(promptText),
|
|
172
149
|
text: promptText,
|
|
173
150
|
},
|
|
174
151
|
scope: {
|
|
@@ -197,7 +174,7 @@ function validateAcceptedEntry(value) {
|
|
|
197
174
|
typeof value.result_id === "string" &&
|
|
198
175
|
isSha256(value.result_sha256) &&
|
|
199
176
|
isRecord(value.result) &&
|
|
200
|
-
value.result_sha256 ===
|
|
177
|
+
value.result_sha256 === hashContent(stableStringify(value.result)) &&
|
|
201
178
|
value.result.work_item_id === value.work_item_id &&
|
|
202
179
|
value.result.prompt_sha256 === value.prompt_sha256 &&
|
|
203
180
|
value.result.result_id === value.result_id &&
|
|
@@ -332,7 +309,7 @@ function parseWorkItem(value) {
|
|
|
332
309
|
!hasExactKeys(value.prompt, ["sha256", "text"]) ||
|
|
333
310
|
!isSha256(value.prompt.sha256) ||
|
|
334
311
|
typeof value.prompt.text !== "string" ||
|
|
335
|
-
|
|
312
|
+
hashContent(value.prompt.text) !== value.prompt.sha256 ||
|
|
336
313
|
!isRecord(value.scope) ||
|
|
337
314
|
!hasExactKeys(value.scope, ["files", "unit_ids"]) ||
|
|
338
315
|
!Array.isArray(value.scope.files) ||
|
|
@@ -455,6 +432,27 @@ function validateHandoffBinding(paths, workload, resultMap, taskBindings) {
|
|
|
455
432
|
}
|
|
456
433
|
return items;
|
|
457
434
|
}
|
|
435
|
+
function refuse(detail) {
|
|
436
|
+
return { ok: false, detail };
|
|
437
|
+
}
|
|
438
|
+
/** `findings[2].affected_files.0.path` — a zod issue path, host-readable. */
|
|
439
|
+
function issueLocation(prefix, path) {
|
|
440
|
+
return [prefix, ...path.map((segment) => String(segment))].join(".");
|
|
441
|
+
}
|
|
442
|
+
function parseFindings(findings) {
|
|
443
|
+
for (const [index, finding] of findings.entries()) {
|
|
444
|
+
const parsed = FindingSchema.safeParse(finding);
|
|
445
|
+
if (parsed.success)
|
|
446
|
+
continue;
|
|
447
|
+
const issue = parsed.error.issues[0];
|
|
448
|
+
const location = issue === undefined
|
|
449
|
+
? `findings[${index}]`
|
|
450
|
+
: issueLocation(`findings[${index}]`, issue.path);
|
|
451
|
+
const reason = issue === undefined ? "invalid" : issue.message;
|
|
452
|
+
return refuse(`findings failed the audit finding contract at ${location}: ${reason}`);
|
|
453
|
+
}
|
|
454
|
+
return null;
|
|
455
|
+
}
|
|
458
456
|
function parseHostResult(value, runId, item, binding) {
|
|
459
457
|
if (!isRecord(value) ||
|
|
460
458
|
!hasExactKeys(value, [
|
|
@@ -468,35 +466,63 @@ function parseHostResult(value, runId, item, binding) {
|
|
|
468
466
|
]) ||
|
|
469
467
|
value.contract_version !== RESULT_CONTRACT_VERSION ||
|
|
470
468
|
typeof value.result_id !== "string" ||
|
|
471
|
-
value.result_id.length === 0
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
469
|
+
value.result_id.length === 0) {
|
|
470
|
+
return refuse(`result envelope is not ${RESULT_CONTRACT_VERSION} with exactly contract_version, ` +
|
|
471
|
+
`result_id, run_id, work_item_id, prompt_sha256, file_coverage and findings`);
|
|
472
|
+
}
|
|
473
|
+
if (value.run_id !== runId) {
|
|
474
|
+
return refuse(`identity binding: run_id is not this run's '${runId}'`);
|
|
475
|
+
}
|
|
476
|
+
if (value.work_item_id !== item.id) {
|
|
477
|
+
return refuse(`identity binding: work_item_id is not '${item.id}'`);
|
|
479
478
|
}
|
|
479
|
+
if (value.prompt_sha256 !== item.prompt.sha256) {
|
|
480
|
+
return refuse("prompt binding: prompt_sha256 is not the sha256 of this work item's prompt");
|
|
481
|
+
}
|
|
482
|
+
if (!Array.isArray(value.file_coverage)) {
|
|
483
|
+
return refuse("file coverage: file_coverage must be an array");
|
|
484
|
+
}
|
|
485
|
+
if (!Array.isArray(value.findings)) {
|
|
486
|
+
return refuse("findings failed the audit finding contract: findings must be an array");
|
|
487
|
+
}
|
|
488
|
+
const findingRefusal = parseFindings(value.findings);
|
|
489
|
+
if (findingRefusal !== null)
|
|
490
|
+
return findingRefusal;
|
|
480
491
|
const coveragePaths = new Set();
|
|
481
492
|
for (const coverage of value.file_coverage) {
|
|
482
493
|
if (!isRecord(coverage) ||
|
|
483
494
|
!hasExactKeys(coverage, ["path", "reviewed_lines", "total_lines"]) ||
|
|
484
|
-
typeof coverage.path !== "string"
|
|
485
|
-
|
|
486
|
-
|
|
495
|
+
typeof coverage.path !== "string") {
|
|
496
|
+
return refuse("file coverage: every entry must contain exactly path, reviewed_lines and total_lines");
|
|
497
|
+
}
|
|
498
|
+
if (coveragePaths.has(coverage.path)) {
|
|
499
|
+
return refuse(`file coverage: '${coverage.path}' is covered twice`);
|
|
500
|
+
}
|
|
501
|
+
if (!Number.isInteger(coverage.reviewed_lines) ||
|
|
487
502
|
!Number.isInteger(coverage.total_lines) ||
|
|
488
503
|
coverage.reviewed_lines < 0 ||
|
|
489
|
-
coverage.reviewed_lines !== coverage.total_lines
|
|
490
|
-
|
|
491
|
-
|
|
504
|
+
coverage.reviewed_lines !== coverage.total_lines) {
|
|
505
|
+
return refuse(`file coverage: '${coverage.path}' must report reviewed_lines equal to total_lines`);
|
|
506
|
+
}
|
|
507
|
+
const boundLines = binding.file_line_counts[coverage.path];
|
|
508
|
+
if (coverage.total_lines !== boundLines) {
|
|
509
|
+
return refuse(boundLines === undefined
|
|
510
|
+
? `file coverage: '${coverage.path}' is not one of this work item's bound files`
|
|
511
|
+
: `file coverage: '${coverage.path}' reports ${String(coverage.total_lines)} ` +
|
|
512
|
+
`total_lines, not the bound ${String(boundLines)}`);
|
|
492
513
|
}
|
|
493
514
|
coveragePaths.add(coverage.path);
|
|
494
515
|
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
return
|
|
516
|
+
const uncovered = item.scope.files.filter((path) => !coveragePaths.has(path));
|
|
517
|
+
if (uncovered.length > 0 || coveragePaths.size !== item.scope.files.length) {
|
|
518
|
+
return refuse(uncovered.length > 0
|
|
519
|
+
? `file coverage: the assigned scope is not fully covered (missing ${uncovered.join(", ")})`
|
|
520
|
+
: "file coverage: entries do not match the assigned scope exactly");
|
|
498
521
|
}
|
|
499
|
-
return
|
|
522
|
+
return {
|
|
523
|
+
ok: true,
|
|
524
|
+
result: JSON.parse(stableStringify(value)),
|
|
525
|
+
};
|
|
500
526
|
}
|
|
501
527
|
function toAuditResult(result, binding) {
|
|
502
528
|
const parsed = AuditResultSchema.safeParse({
|
|
@@ -514,17 +540,59 @@ function toAuditResult(result, binding) {
|
|
|
514
540
|
reviewed_clean: result.findings.length === 0,
|
|
515
541
|
run_id: result.run_id,
|
|
516
542
|
});
|
|
517
|
-
|
|
543
|
+
if (parsed.success)
|
|
544
|
+
return { ok: true, auditResult: parsed.data };
|
|
545
|
+
const issue = parsed.error.issues[0];
|
|
546
|
+
return {
|
|
547
|
+
ok: false,
|
|
548
|
+
detail: issue === undefined
|
|
549
|
+
? "the converted AuditResult is invalid"
|
|
550
|
+
: `${issueLocation("audit_result", issue.path)}: ${issue.message}`,
|
|
551
|
+
};
|
|
518
552
|
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
553
|
+
/**
|
|
554
|
+
* Read one bound submission and CLASSIFY the outcome. Every failure names
|
|
555
|
+
* itself and the bound path it looked at; nothing collapses to `null`.
|
|
556
|
+
*/
|
|
557
|
+
async function readSubmittedResult(absolutePath, boundPath, runId, item, binding) {
|
|
558
|
+
const locators = { work_item_id: item.id, result_path: boundPath };
|
|
559
|
+
const read = await readSubmissionDocument(absolutePath);
|
|
560
|
+
if (read.kind === "missing") {
|
|
561
|
+
return {
|
|
562
|
+
ok: false,
|
|
563
|
+
issue: {
|
|
564
|
+
code: "submission_missing",
|
|
565
|
+
message: `work item '${item.id}' submitted nothing at its bound path`,
|
|
566
|
+
...locators,
|
|
567
|
+
},
|
|
568
|
+
};
|
|
522
569
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
570
|
+
if (read.kind === "malformed") {
|
|
571
|
+
return {
|
|
572
|
+
ok: false,
|
|
573
|
+
issue: {
|
|
574
|
+
code: "submission_malformed",
|
|
575
|
+
message: `work item '${item.id}' submitted bytes that are not JSON: ${read.detail}`,
|
|
576
|
+
...locators,
|
|
577
|
+
},
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
const parsed = parseHostResult(read.value, runId, item, binding);
|
|
581
|
+
if (!parsed.ok) {
|
|
582
|
+
return {
|
|
583
|
+
ok: false,
|
|
584
|
+
issue: {
|
|
585
|
+
code: "submission_contract_invalid",
|
|
586
|
+
// The detail NAMES its own category. The message must never enumerate
|
|
587
|
+
// categories the submission satisfied — that is how four correct-identity
|
|
588
|
+
// results read as an identity problem for a whole lap.
|
|
589
|
+
message: `work item '${item.id}' submitted JSON that does not satisfy the audit host ` +
|
|
590
|
+
`result contract: ${parsed.detail}`,
|
|
591
|
+
...locators,
|
|
592
|
+
},
|
|
593
|
+
};
|
|
527
594
|
}
|
|
595
|
+
return { ok: true, result: parsed.result };
|
|
528
596
|
}
|
|
529
597
|
export async function ingestAuditHostResults(params) {
|
|
530
598
|
const paths = resolveBoundaryPaths(params);
|
|
@@ -536,6 +604,7 @@ export async function ingestAuditHostResults(params) {
|
|
|
536
604
|
const acceptedBindings = new Set(accepted.entries.map(bindingIdentity));
|
|
537
605
|
const resultIds = new Set(accepted.entries.map((entry) => entry.result_id));
|
|
538
606
|
const additions = [];
|
|
607
|
+
const issues = [];
|
|
539
608
|
for (const entry of resultMap.entries) {
|
|
540
609
|
if (acceptedBindings.has(bindingIdentity(entry)))
|
|
541
610
|
continue;
|
|
@@ -543,22 +612,43 @@ export async function ingestAuditHostResults(params) {
|
|
|
543
612
|
const binding = taskBindings.get(entry.work_item_id);
|
|
544
613
|
if (item === undefined || binding === undefined)
|
|
545
614
|
continue;
|
|
546
|
-
const absoluteResultPath =
|
|
547
|
-
const
|
|
548
|
-
if (
|
|
615
|
+
const absoluteResultPath = resolveContainedPath(paths.root, entry.result_path, `result path for ${entry.work_item_id}`);
|
|
616
|
+
const outcome = await readSubmittedResult(absoluteResultPath, entry.result_path, params.runId, item, binding);
|
|
617
|
+
if (!outcome.ok) {
|
|
618
|
+
issues.push(outcome.issue);
|
|
549
619
|
continue;
|
|
550
|
-
|
|
551
|
-
|
|
620
|
+
}
|
|
621
|
+
const result = outcome.result;
|
|
622
|
+
if (resultIds.has(result.result_id)) {
|
|
623
|
+
issues.push({
|
|
624
|
+
code: "duplicate_submission_id",
|
|
625
|
+
message: `work item '${entry.work_item_id}' submitted result id '${result.result_id}', ` +
|
|
626
|
+
`which this run has already accepted`,
|
|
627
|
+
work_item_id: entry.work_item_id,
|
|
628
|
+
result_path: entry.result_path,
|
|
629
|
+
});
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
632
|
+
const converted = toAuditResult(result, binding);
|
|
633
|
+
if (!converted.ok) {
|
|
634
|
+
issues.push({
|
|
635
|
+
code: "submission_contract_invalid",
|
|
636
|
+
message: `work item '${entry.work_item_id}' submitted a result that does not convert to ` +
|
|
637
|
+
`an AuditResult: ${converted.detail}`,
|
|
638
|
+
work_item_id: entry.work_item_id,
|
|
639
|
+
result_path: entry.result_path,
|
|
640
|
+
});
|
|
552
641
|
continue;
|
|
642
|
+
}
|
|
553
643
|
resultIds.add(result.result_id);
|
|
554
644
|
additions.push({
|
|
555
645
|
work_item_id: entry.work_item_id,
|
|
556
646
|
prompt_sha256: entry.prompt_sha256,
|
|
557
647
|
result_path: entry.result_path,
|
|
558
648
|
result_id: result.result_id,
|
|
559
|
-
result_sha256:
|
|
649
|
+
result_sha256: hashContent(stableStringify(result)),
|
|
560
650
|
result,
|
|
561
|
-
audit_result: auditResult,
|
|
651
|
+
audit_result: converted.auditResult,
|
|
562
652
|
});
|
|
563
653
|
}
|
|
564
654
|
let ledger = accepted;
|
|
@@ -583,6 +673,7 @@ export async function ingestAuditHostResults(params) {
|
|
|
583
673
|
completed_work_item_ids: [
|
|
584
674
|
...new Set(ledger.entries.map((entry) => entry.work_item_id)),
|
|
585
675
|
].sort(compareCodeUnits),
|
|
676
|
+
issues,
|
|
586
677
|
};
|
|
587
678
|
}
|
|
588
679
|
//# sourceMappingURL=hostHandoff.js.map
|