audit-tools 0.40.1 → 0.41.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/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 +84 -56
- 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 +26 -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/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 +11 -1
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js +6 -1
- 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/docs/audit-pkg/product.md +0 -2
- package/package.json +1 -1
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The audit draw of the shared submission core: how a GATE lane's bound path is
|
|
3
|
+
* computed, and where the expected-set / ledger for those lanes are persisted.
|
|
4
|
+
*
|
|
5
|
+
* Two facts about the audit gates shape everything here:
|
|
6
|
+
*
|
|
7
|
+
* 1. **They carry no run id.** `NextStepParams` has none, and threading one
|
|
8
|
+
* into every gate would change ten signatures to carry a value the gates
|
|
9
|
+
* never use. Their submissions are therefore ARTIFACTS-DIR-scoped: the
|
|
10
|
+
* constant `AUDIT_GATE_SUBMISSION_SCOPE` stands in for run identity, so the
|
|
11
|
+
* same gate lane in the same artifacts dir denotes the same submission
|
|
12
|
+
* across `next-step` calls. That is not a shortcut — it is exactly the
|
|
13
|
+
* K-of-N resume property, which requires a re-emitted step to re-declare
|
|
14
|
+
* the identical bound path rather than mint a new one and re-ask for work
|
|
15
|
+
* the host already delivered.
|
|
16
|
+
*
|
|
17
|
+
* 2. **The lane id is the only join key.** The emitter and the gate reader
|
|
18
|
+
* never meet; they agree because both derive the id from the lane id
|
|
19
|
+
* through this module. A lane id is declared once in
|
|
20
|
+
* `HOST_GATE_DESCRIPTORS` and used verbatim on both sides.
|
|
21
|
+
*
|
|
22
|
+
* The bound path is DERIVED, not looked up. The persisted expected set states
|
|
23
|
+
* what is owed (and feeds the diff and the ledger), but a gate that could only
|
|
24
|
+
* read a submission when a bookkeeping file happened to exist would lose a
|
|
25
|
+
* valid submission the first time that file was absent — so derivation is the
|
|
26
|
+
* mechanism and the record is the record.
|
|
27
|
+
*/
|
|
28
|
+
import { z } from "zod";
|
|
29
|
+
import { CharterKindSchema, absoluteSubmissionPath, buildExpectedSubmissionSet, diffExpectedSet, discardOnSchemaVersionMismatch, expectedSubmissionsPath, hashContent, mergeExpectedSets, mintSubmissionId, outputDirFor, readOptionalJsonFile, readSubmissionDocument, readSubmissionLedger, submissionsDir, withoutExpectedSubmissions, writeJsonFile, EXPECTED_SET_CONTRACT_VERSION, SUBMISSION_LEDGER_EVENT_CONTRACT_VERSION, appendSubmissionEvent, } from "audit-tools/shared";
|
|
30
|
+
/**
|
|
31
|
+
* Gate lane ids — the single join key between an emitter and its gate reader.
|
|
32
|
+
*
|
|
33
|
+
* The two never meet: an emitter writes a lane's prompt and declares where the
|
|
34
|
+
* answer goes, and (possibly several `next-step` calls later) the gate reader
|
|
35
|
+
* looks for it. They agree because both derive the bound path from the lane id
|
|
36
|
+
* through this module. Declared once, here, so no site can spell a lane one way
|
|
37
|
+
* on the emit side and another on the read side.
|
|
38
|
+
*/
|
|
39
|
+
export const GATE_LANES = {
|
|
40
|
+
analyzer_consent: "analyzer_consent",
|
|
41
|
+
analyzer_decisions: "analyzer_decisions",
|
|
42
|
+
edge_reasoning: "edge_reasoning",
|
|
43
|
+
design_review_legacy: "design_review_legacy",
|
|
44
|
+
design_review_contract: "design_review_contract",
|
|
45
|
+
design_review_conceptual: "design_review_conceptual",
|
|
46
|
+
critical_flow_fallback: "critical_flow_fallback",
|
|
47
|
+
intent_equivalence: "intent_equivalence",
|
|
48
|
+
synthesis_narrative: "synthesis_narrative",
|
|
49
|
+
charter_delta: "charter_delta",
|
|
50
|
+
charter_clarification: "charter_clarification",
|
|
51
|
+
systemic_challenge: "systemic_challenge",
|
|
52
|
+
};
|
|
53
|
+
/** The blind per-kind charter lanes (one per estimator channel). */
|
|
54
|
+
export function charterExtractionLane(kind) {
|
|
55
|
+
return `charter_extraction_${kind}`;
|
|
56
|
+
}
|
|
57
|
+
/** Recover the charter kind a `charter_extraction_*` lane id denotes. */
|
|
58
|
+
export function charterKindForLane(lane) {
|
|
59
|
+
if (!lane.startsWith(CHARTER_EXTRACTION_LANE_PREFIX))
|
|
60
|
+
return undefined;
|
|
61
|
+
const parsed = CharterKindSchema.safeParse(lane.slice(CHARTER_EXTRACTION_LANE_PREFIX.length));
|
|
62
|
+
return parsed.success ? parsed.data : undefined;
|
|
63
|
+
}
|
|
64
|
+
const CHARTER_EXTRACTION_LANE_PREFIX = "charter_extraction_";
|
|
65
|
+
export const CONCEPTUAL_PERSPECTIVE_LANE_PREFIX = "design_review_conceptual_p";
|
|
66
|
+
/**
|
|
67
|
+
* The deep conceptual pass's independent perspective lanes. Their COUNT is
|
|
68
|
+
* resolved at emit from confirmed intent, so the ids are generated rather than
|
|
69
|
+
* enumerated.
|
|
70
|
+
*
|
|
71
|
+
* The id carries the ROUND — a digest of the upstream content the round asks
|
|
72
|
+
* about — because a perspective is the one lane class whose reuse is WRONG.
|
|
73
|
+
* Every other lane's identity is deliberately stable so a re-emitted step
|
|
74
|
+
* re-declares the same bound path (K-of-N resume); a perspective, though, is a
|
|
75
|
+
* fresh independent reading of the artifacts as they now stand. Keyed on the
|
|
76
|
+
* index alone, a re-review after staleness would find the PREVIOUS round's
|
|
77
|
+
* submission at the bound path, skip the lane, leave its prompt unrewritten,
|
|
78
|
+
* and hand the judge the old round's findings as if they were this round's.
|
|
79
|
+
* Same round, same digest, same id — so resume WITHIN a round still works.
|
|
80
|
+
*/
|
|
81
|
+
export function conceptualPerspectiveLane(index, roundToken) {
|
|
82
|
+
return `${CONCEPTUAL_PERSPECTIVE_LANE_PREFIX}${index}_${roundToken}`;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The round token every perspective lane in one deep conceptual emission
|
|
86
|
+
* shares: a digest of exactly what this round asks. Deterministic in its inputs
|
|
87
|
+
* — never a timestamp or a counter, which would mint new ids (and re-ask for
|
|
88
|
+
* already-delivered work) on every re-emission of an unchanged round.
|
|
89
|
+
*/
|
|
90
|
+
export function conceptualRoundToken(inputs) {
|
|
91
|
+
return hashContent(inputs.join("\n"), { length: 12 });
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The per-kind evidence packet a charter lane reads. TOOL-written, so it lives
|
|
95
|
+
* under the lane-asset dir with the lane prompts — a host only ever reads it.
|
|
96
|
+
*/
|
|
97
|
+
export function charterExtractionPacketFilename(kind) {
|
|
98
|
+
return `charter-extraction-${kind}-packet.md`;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The tool-side merge of the per-kind charter lanes, handed to the extraction
|
|
102
|
+
* executor by path and deleted once ingested. Tool-written, so it is a lane
|
|
103
|
+
* asset and not a submission.
|
|
104
|
+
*/
|
|
105
|
+
export const CHARTER_EXTRACTION_MERGED_FILENAME = "charter-extraction-merged.json";
|
|
106
|
+
/**
|
|
107
|
+
* The submission FAMILY every audit gate lane belongs to. Distinguishes these
|
|
108
|
+
* from the host-handoff work-item submissions, which mint through the same rule
|
|
109
|
+
* under their own run id.
|
|
110
|
+
*/
|
|
111
|
+
export const AUDIT_LANE_SUBMISSION_KIND = "audit_host_lane";
|
|
112
|
+
/** See the module comment: the audit gates' stand-in for run identity. */
|
|
113
|
+
export const AUDIT_GATE_SUBMISSION_SCOPE = "audit-host-gates";
|
|
114
|
+
/**
|
|
115
|
+
* Bound paths for gate lanes are expressed relative to the artifact tree root
|
|
116
|
+
* (`.audit-tools/`), not the repository root: the gates are handed an artifacts
|
|
117
|
+
* dir and nothing else, and a recorded path must be derivable from exactly what
|
|
118
|
+
* the reader has.
|
|
119
|
+
*/
|
|
120
|
+
export function laneSubmissionRoots(artifactsDir) {
|
|
121
|
+
return {
|
|
122
|
+
root: outputDirFor(artifactsDir),
|
|
123
|
+
submissionDir: submissionsDir(artifactsDir),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/** The tool-minted id for one lane. Deterministic in the lane id alone. */
|
|
127
|
+
export function laneSubmissionId(lane, runId = AUDIT_GATE_SUBMISSION_SCOPE) {
|
|
128
|
+
return mintSubmissionId({ kind: AUDIT_LANE_SUBMISSION_KIND, lane, runId });
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Absolute on-disk path a lane's submission must land at.
|
|
132
|
+
*
|
|
133
|
+
* `runId` is threaded rather than defaulted-and-forgotten: the bound path and
|
|
134
|
+
* the recorded expectation must come from ONE derivation. They were two — the
|
|
135
|
+
* path taking the module constant while the record took the caller's scope —
|
|
136
|
+
* which coincided only because every caller happened to pass the constant, i.e.
|
|
137
|
+
* the invariant held by the caller remembering.
|
|
138
|
+
*/
|
|
139
|
+
export function laneSubmissionPath(artifactsDir, lane, runId = AUDIT_GATE_SUBMISSION_SCOPE) {
|
|
140
|
+
return absoluteSubmissionPath(laneSubmissionRoots(artifactsDir), laneSubmissionId(lane, runId));
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* The current statement of what is owed, or `undefined` when there isn't one.
|
|
144
|
+
*
|
|
145
|
+
* REGENERABLE state: the set is rewritten at every emit from the lanes the
|
|
146
|
+
* emission declares, so a set left by another release is DISCARDED rather than
|
|
147
|
+
* reinterpreted under this release's field semantics. The fail-shape is the one
|
|
148
|
+
* this reader already has for an absent file — the merge below starts from
|
|
149
|
+
* nothing, every declared lane counts as newly added, and the carried-lane diff
|
|
150
|
+
* therefore sees no prior entries and reports no shortfall. That is exactly
|
|
151
|
+
* right after an upgrade: nothing was carried into this emission that this
|
|
152
|
+
* release ever asked for, so the emission is first-emission-silent instead of
|
|
153
|
+
* accusing the host of dropping lanes it was never coherently asked for.
|
|
154
|
+
*/
|
|
155
|
+
async function loadExpectedSet(artifactsDir) {
|
|
156
|
+
try {
|
|
157
|
+
return discardOnSchemaVersionMismatch(await readOptionalJsonFile(expectedSubmissionsPath(artifactsDir)), EXPECTED_SET_CONTRACT_VERSION);
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
// Corrupt bookkeeping must never fail the emission it is recording; the
|
|
161
|
+
// merge below simply starts from nothing.
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* What a re-emission is still owed, stated by name.
|
|
167
|
+
*
|
|
168
|
+
* Persisted on the step contract and rendered into the step prompt, so "the
|
|
169
|
+
* host dropped a lane" is a fact the run REPORTS rather than one an operator
|
|
170
|
+
* has to infer from an identical step arriving twice.
|
|
171
|
+
*/
|
|
172
|
+
const OutstandingLaneSubmissionSchema = z
|
|
173
|
+
.object({
|
|
174
|
+
lane: z.string(),
|
|
175
|
+
submission_id: z.string(),
|
|
176
|
+
/**
|
|
177
|
+
* The tool-computed bound path, ABSOLUTE — the same form (and the same
|
|
178
|
+
* file) as the step's `access.write_paths` entry for this lane, so the two
|
|
179
|
+
* compare directly. Deliberately NOT the expected set's recorded form:
|
|
180
|
+
* that one is relative to the artifact tree root, a base the step contract
|
|
181
|
+
* declares nowhere, so a consumer joining it against `repo_root` or
|
|
182
|
+
* `artifacts_dir` would build a path that never existed. `extraFields` ride
|
|
183
|
+
* through `writeStepContract` un-normalized (only prompt_path / repo_root /
|
|
184
|
+
* artifacts_dir / artifact_paths are), exactly as `access` does.
|
|
185
|
+
*/
|
|
186
|
+
submission_path: z.string(),
|
|
187
|
+
issue_code: z.string(),
|
|
188
|
+
message: z.string(),
|
|
189
|
+
})
|
|
190
|
+
.strict();
|
|
191
|
+
export const LaneSubmissionShortfallSchema = z
|
|
192
|
+
.object({
|
|
193
|
+
/** Lanes CARRIED into this emission (a prior emission already asked). */
|
|
194
|
+
expected: z.number().int(),
|
|
195
|
+
/** How many of those have a readable submission at their bound path. */
|
|
196
|
+
accepted: z.number().int(),
|
|
197
|
+
outstanding: z.array(OutstandingLaneSubmissionSchema),
|
|
198
|
+
})
|
|
199
|
+
.strict();
|
|
200
|
+
const NO_SHORTFALL = {
|
|
201
|
+
expected: 0,
|
|
202
|
+
accepted: 0,
|
|
203
|
+
outstanding: [],
|
|
204
|
+
};
|
|
205
|
+
/** Read every carried member's bound path once, for the diff below. */
|
|
206
|
+
async function observeLanes(artifactsDir, entries) {
|
|
207
|
+
const roots = laneSubmissionRoots(artifactsDir);
|
|
208
|
+
return new Map(await Promise.all(entries.map(async (entry) => [
|
|
209
|
+
entry.submission_id,
|
|
210
|
+
await readSubmissionDocument(absoluteSubmissionPath(roots, entry.submission_id)),
|
|
211
|
+
])));
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Record what this emission owes, and report what a PREVIOUS one is still owed.
|
|
215
|
+
*
|
|
216
|
+
* Merges into the current statement (a step that materializes several lane
|
|
217
|
+
* groups accumulates them) and appends one `expected` event per NEWLY declared
|
|
218
|
+
* lane, so a re-emission does not spam the arrival record.
|
|
219
|
+
*
|
|
220
|
+
* The returned shortfall diffs only the lanes CARRIED into this emission — the
|
|
221
|
+
* ones an earlier emission already asked for and that are still not on disk.
|
|
222
|
+
* Restricting it to carried lanes is what makes the report meaningful: on a
|
|
223
|
+
* first emission every lane is legitimately absent (it is being asked for right
|
|
224
|
+
* now), so counting those would make every fan-out look like a failure.
|
|
225
|
+
*/
|
|
226
|
+
export async function recordExpectedLanes(artifactsDir, runId, lanes) {
|
|
227
|
+
if (lanes.length === 0)
|
|
228
|
+
return NO_SHORTFALL;
|
|
229
|
+
const declared = buildExpectedSubmissionSet({
|
|
230
|
+
runId,
|
|
231
|
+
paths: laneSubmissionRoots(artifactsDir),
|
|
232
|
+
lanes: lanes.map((lane) => ({
|
|
233
|
+
lane: lane.lane,
|
|
234
|
+
submissionId: laneSubmissionId(lane.lane, runId),
|
|
235
|
+
promptSha256: hashContent(lane.promptText),
|
|
236
|
+
})),
|
|
237
|
+
});
|
|
238
|
+
const { set, addedIds } = mergeExpectedSets(await loadExpectedSet(artifactsDir), declared);
|
|
239
|
+
await writeJsonFile(expectedSubmissionsPath(artifactsDir), set);
|
|
240
|
+
const added = new Set(addedIds);
|
|
241
|
+
for (const entry of set.entries) {
|
|
242
|
+
if (!added.has(entry.submission_id))
|
|
243
|
+
continue;
|
|
244
|
+
await appendSubmissionEvent(artifactsDir, {
|
|
245
|
+
contract_version: SUBMISSION_LEDGER_EVENT_CONTRACT_VERSION,
|
|
246
|
+
run_id: runId,
|
|
247
|
+
submission_id: entry.submission_id,
|
|
248
|
+
lane: entry.lane,
|
|
249
|
+
kind: "expected",
|
|
250
|
+
recorded_at: new Date().toISOString(),
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
const carried = {
|
|
254
|
+
...declared,
|
|
255
|
+
entries: declared.entries.filter((entry) => !added.has(entry.submission_id)),
|
|
256
|
+
};
|
|
257
|
+
if (carried.entries.length === 0)
|
|
258
|
+
return NO_SHORTFALL;
|
|
259
|
+
const byId = new Map(carried.entries.map((entry) => [entry.submission_id, entry]));
|
|
260
|
+
const diff = diffExpectedSet(carried, await observeLanes(artifactsDir, carried.entries));
|
|
261
|
+
const outstanding = diff.members.flatMap((member) => member.status === "issue" ? [member] : []);
|
|
262
|
+
// A REFUSED lane also reads as ENOENT, because quarantining moves the file
|
|
263
|
+
// off the bound path and only an ACCEPTED lane is dropped from the set. The
|
|
264
|
+
// disk cannot tell the two apart, so the record does: without this, a host
|
|
265
|
+
// whose submission was received and rejected is told it "submitted nothing",
|
|
266
|
+
// which is false and points it at the wrong repair.
|
|
267
|
+
const refusals = outstanding.length > 0
|
|
268
|
+
? await lastRefusals(artifactsDir, outstanding.map((member) => member.submission_id))
|
|
269
|
+
: new Map();
|
|
270
|
+
const roots = laneSubmissionRoots(artifactsDir);
|
|
271
|
+
return {
|
|
272
|
+
expected: diff.expected,
|
|
273
|
+
accepted: diff.accepted,
|
|
274
|
+
outstanding: outstanding.map((member) => {
|
|
275
|
+
const entry = byId.get(member.submission_id);
|
|
276
|
+
const lane = entry?.lane ?? member.submission_id;
|
|
277
|
+
const refusal = refusals.get(member.submission_id);
|
|
278
|
+
return {
|
|
279
|
+
lane,
|
|
280
|
+
submission_id: member.submission_id,
|
|
281
|
+
// Absolute, matching this step's `access.write_paths` entry — see the
|
|
282
|
+
// schema note; the expected set's own record stays artifact-relative.
|
|
283
|
+
submission_path: absoluteSubmissionPath(roots, member.submission_id),
|
|
284
|
+
issue_code: refusal ? "submission_rejected" : member.issue.code,
|
|
285
|
+
message: refusal
|
|
286
|
+
? `lane '${lane}' submitted, and the submission was refused` +
|
|
287
|
+
`${refusal.message ? `: ${refusal.message}` : ""}` +
|
|
288
|
+
" — fix it and resubmit at the bound path"
|
|
289
|
+
: member.issue.message,
|
|
290
|
+
};
|
|
291
|
+
}),
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* The last ledger event per submission id, kept only where it is a REFUSAL.
|
|
296
|
+
* A later acceptance or hand recovery ends the refusal, so only the trailing
|
|
297
|
+
* state counts: this answers "is this lane outstanding BECAUSE it was refused",
|
|
298
|
+
* never "was it ever refused".
|
|
299
|
+
*/
|
|
300
|
+
async function lastRefusals(artifactsDir, submissionIds) {
|
|
301
|
+
const wanted = new Set(submissionIds);
|
|
302
|
+
const last = new Map();
|
|
303
|
+
for (const event of await readSubmissionLedger(artifactsDir)) {
|
|
304
|
+
if (!wanted.has(event.submission_id))
|
|
305
|
+
continue;
|
|
306
|
+
if (event.kind === "expected")
|
|
307
|
+
continue;
|
|
308
|
+
last.set(event.submission_id, event);
|
|
309
|
+
}
|
|
310
|
+
for (const [id, event] of [...last.entries()]) {
|
|
311
|
+
if (event.kind !== "rejected")
|
|
312
|
+
last.delete(id);
|
|
313
|
+
}
|
|
314
|
+
return last;
|
|
315
|
+
}
|
|
316
|
+
/** Merge the shortfalls of a step that materializes several lane groups. */
|
|
317
|
+
export function mergeLaneShortfalls(shortfalls) {
|
|
318
|
+
return {
|
|
319
|
+
expected: shortfalls.reduce((total, one) => total + one.expected, 0),
|
|
320
|
+
accepted: shortfalls.reduce((total, one) => total + one.accepted, 0),
|
|
321
|
+
outstanding: shortfalls.flatMap((one) => one.outstanding),
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* The host-facing statement of an unmet expectation, by lane and issue code.
|
|
326
|
+
* Empty when nothing was carried or everything carried has arrived — a clean
|
|
327
|
+
* emission says nothing, so the notice's presence is itself the signal.
|
|
328
|
+
*/
|
|
329
|
+
export function renderLaneShortfallLines(shortfall) {
|
|
330
|
+
if (shortfall.outstanding.length === 0)
|
|
331
|
+
return [];
|
|
332
|
+
return [
|
|
333
|
+
"## Submissions still outstanding",
|
|
334
|
+
"",
|
|
335
|
+
`A previous emission asked for ${shortfall.expected} lane submission(s); ${shortfall.accepted} arrived. ` +
|
|
336
|
+
"These are still unsatisfied at the bound paths the tool declared — nothing was lost, and the paths are unchanged:",
|
|
337
|
+
"",
|
|
338
|
+
...shortfall.outstanding.map((entry) => `- lane \`${entry.lane}\` (${entry.issue_code}): ${entry.message}`),
|
|
339
|
+
"",
|
|
340
|
+
];
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Record the outcome of one lane. An accepted lane stops being owed; a rejected
|
|
344
|
+
* one stays owed (the host is asked again) but the refusal is on the record
|
|
345
|
+
* with its reason, which is what makes a repaired run distinguishable from a
|
|
346
|
+
* clean one.
|
|
347
|
+
*/
|
|
348
|
+
export async function recordLaneOutcome(artifactsDir, lane, outcome) {
|
|
349
|
+
// ONE derivation of the scope: the id and the event's run field are the same
|
|
350
|
+
// value by construction, not two sites spelling the same constant.
|
|
351
|
+
const runId = AUDIT_GATE_SUBMISSION_SCOPE;
|
|
352
|
+
const submissionId = laneSubmissionId(lane, runId);
|
|
353
|
+
await appendSubmissionEvent(artifactsDir, {
|
|
354
|
+
contract_version: SUBMISSION_LEDGER_EVENT_CONTRACT_VERSION,
|
|
355
|
+
run_id: runId,
|
|
356
|
+
submission_id: submissionId,
|
|
357
|
+
lane,
|
|
358
|
+
kind: outcome.kind,
|
|
359
|
+
...(outcome.kind === "rejected"
|
|
360
|
+
? { issue_code: outcome.issueCode, message: outcome.message }
|
|
361
|
+
: {}),
|
|
362
|
+
...(outcome.kind === "accepted" && outcome.message
|
|
363
|
+
? { message: outcome.message }
|
|
364
|
+
: {}),
|
|
365
|
+
recorded_at: new Date().toISOString(),
|
|
366
|
+
});
|
|
367
|
+
if (outcome.kind !== "accepted")
|
|
368
|
+
return;
|
|
369
|
+
const set = await loadExpectedSet(artifactsDir);
|
|
370
|
+
if (!set)
|
|
371
|
+
return;
|
|
372
|
+
await writeJsonFile(expectedSubmissionsPath(artifactsDir), withoutExpectedSubmissions(set, [submissionId]));
|
|
373
|
+
}
|
|
374
|
+
/** How an event reads for dedupe: kind, code, and message, in one string. */
|
|
375
|
+
function eventSignature(kind, issueCode, message) {
|
|
376
|
+
return [kind, issueCode ?? "", message ?? ""].join("|");
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Record what the host-handoff ingest just decided about each work item, on the
|
|
380
|
+
* same ledger the gate lanes use — so a submission that never arrived (or
|
|
381
|
+
* arrived unreadable) is a durable fact rather than a value that died inside
|
|
382
|
+
* the call that computed it.
|
|
383
|
+
*
|
|
384
|
+
* Two rules keep the record drift-focused and arithmetically honest:
|
|
385
|
+
*
|
|
386
|
+
* • Deduped against the LAST recorded event for each submission. Ingest runs
|
|
387
|
+
* on every `next-step`, so a host still working through its workload would
|
|
388
|
+
* otherwise append the same "missing" line every poll, burying the state
|
|
389
|
+
* CHANGES the ledger exists to preserve. A changed classification still
|
|
390
|
+
* appends, in arrival order.
|
|
391
|
+
* • An acceptance is recorded ONLY where a refusal precedes it. A work item
|
|
392
|
+
* the host got right first try says nothing (the ledger is not an inventory
|
|
393
|
+
* of work), but one that was refused and later accepted must close its own
|
|
394
|
+
* story — otherwise a run where every failure was repaired reports its
|
|
395
|
+
* refusals with no matching repairs, and the report reads as a run that
|
|
396
|
+
* never recovered.
|
|
397
|
+
*/
|
|
398
|
+
export async function recordHostResultOutcomes(artifactsDir, runId, outcomes) {
|
|
399
|
+
if (outcomes.issues.length === 0 && outcomes.acceptedIds.length === 0)
|
|
400
|
+
return;
|
|
401
|
+
const last = new Map();
|
|
402
|
+
for (const event of await readSubmissionLedger(artifactsDir)) {
|
|
403
|
+
last.set(event.submission_id, eventSignature(event.kind, event.issue_code, event.message));
|
|
404
|
+
}
|
|
405
|
+
const append = async (submissionId, event) => {
|
|
406
|
+
const signature = eventSignature(event.kind, event.issue_code, event.message);
|
|
407
|
+
if (last.get(submissionId) === signature)
|
|
408
|
+
return;
|
|
409
|
+
last.set(submissionId, signature);
|
|
410
|
+
await appendSubmissionEvent(artifactsDir, {
|
|
411
|
+
contract_version: SUBMISSION_LEDGER_EVENT_CONTRACT_VERSION,
|
|
412
|
+
run_id: runId,
|
|
413
|
+
submission_id: submissionId,
|
|
414
|
+
// A host work item's id IS its submission identity: the bound path is
|
|
415
|
+
// derived from it through the same rule the gate lanes use.
|
|
416
|
+
lane: submissionId,
|
|
417
|
+
...event,
|
|
418
|
+
recorded_at: new Date().toISOString(),
|
|
419
|
+
});
|
|
420
|
+
};
|
|
421
|
+
for (const submissionId of outcomes.acceptedIds) {
|
|
422
|
+
// Nothing on the record for this item means it was clean on the first try.
|
|
423
|
+
if (!last.has(submissionId))
|
|
424
|
+
continue;
|
|
425
|
+
await append(submissionId, { kind: "accepted" });
|
|
426
|
+
}
|
|
427
|
+
for (const issue of outcomes.issues) {
|
|
428
|
+
const submissionId = issue.work_item_id ?? issue.submission_id;
|
|
429
|
+
if (submissionId === undefined)
|
|
430
|
+
continue;
|
|
431
|
+
await append(submissionId, {
|
|
432
|
+
kind: "rejected",
|
|
433
|
+
issue_code: issue.code,
|
|
434
|
+
message: issue.message,
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
//# sourceMappingURL=laneSubmissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"laneSubmissions.js","sourceRoot":"","sources":["../../../src/audit/cli/laneSubmissions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE registry of what a lane's submission must satisfy.
|
|
3
|
+
*
|
|
4
|
+
* Every gate validated its submission inline, which was fine while the only
|
|
5
|
+
* reader was the gate itself. The hand-recovery verb is a SECOND reader of the
|
|
6
|
+
* same contract, and a second reader is exactly where a weaker copy grows: an
|
|
7
|
+
* operator rescue that skipped the schema would be a door into the tool the
|
|
8
|
+
* normal lane does not have. So the rule lives here once, and both the gate and
|
|
9
|
+
* `recover-submission` resolve it from this table.
|
|
10
|
+
*
|
|
11
|
+
* Two shapes of rule, because two shapes of lane exist: those whose contract IS
|
|
12
|
+
* a zod schema, and those whose contract is a tolerated JSON shape (an array of
|
|
13
|
+
* findings, a decisions map). Both are expressed as the same
|
|
14
|
+
* `SubmissionIssue | null` validator so a caller never has to know which.
|
|
15
|
+
*/
|
|
16
|
+
import type { ZodTypeAny } from "zod";
|
|
17
|
+
import { type CharterKind, type SubmissionIssue } from "audit-tools/shared";
|
|
18
|
+
/** Human-readable description of why a submission is neither an array nor a single-array-wrapped object. */
|
|
19
|
+
export declare function describeSubmissionShapeMismatch(value: unknown): string;
|
|
20
|
+
/**
|
|
21
|
+
* The single tolerant-unwrap rule: a bare array is accepted as-is; a top-level
|
|
22
|
+
* object wrapping exactly one array-valued property is unambiguous and is
|
|
23
|
+
* accepted as that array. Anything else fails with a shape description.
|
|
24
|
+
* Single-sourced so the design-review gate, the edge-reasoning gate, and the
|
|
25
|
+
* recovery verb cannot drift on what shapes are accepted.
|
|
26
|
+
*/
|
|
27
|
+
export declare function unwrapSubmissionArray(value: unknown): {
|
|
28
|
+
ok: true;
|
|
29
|
+
array: unknown[];
|
|
30
|
+
} | {
|
|
31
|
+
ok: false;
|
|
32
|
+
reason: string;
|
|
33
|
+
};
|
|
34
|
+
/** True for a plain top-level key → value map (the decisions-file shape). */
|
|
35
|
+
export declare function isSubmissionObjectMap(value: unknown): value is Record<string, unknown>;
|
|
36
|
+
/**
|
|
37
|
+
* The charter lane schema: the submission shape PLUS the two refinements that
|
|
38
|
+
* make a blind lane trustworthy — kind purity (a lane may only carry its own
|
|
39
|
+
* kind; anything else is a mis-routed submission) and scope grounding (a
|
|
40
|
+
* teleology node citing files the repo does not contain is refused whole,
|
|
41
|
+
* naming them, never silently narrowed).
|
|
42
|
+
*
|
|
43
|
+
* `repoFiles` is the manifest's path set. It is a parameter rather than a
|
|
44
|
+
* capture so the gate and the recovery verb apply the identical refinement
|
|
45
|
+
* against the identical universe.
|
|
46
|
+
*/
|
|
47
|
+
export declare function charterLaneSchema(kind: CharterKind, repoFiles: ReadonlySet<string>): ZodTypeAny;
|
|
48
|
+
/**
|
|
49
|
+
* Lanes whose contract is a zod schema, keyed by lane id. The gate descriptors
|
|
50
|
+
* read this table; so does the recovery verb.
|
|
51
|
+
*/
|
|
52
|
+
export declare const LANE_SUBMISSION_SCHEMAS: Readonly<Record<string, ZodTypeAny>>;
|
|
53
|
+
/** What the recovery verb needs in order to apply the FULL lane contract. */
|
|
54
|
+
export interface LaneValidationContext {
|
|
55
|
+
/** The repo manifest's path set — the charter lanes' scope grounding. */
|
|
56
|
+
readonly repoFiles: ReadonlySet<string>;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The validator the normal lane applies to `lane`, or `null` when the lane id
|
|
60
|
+
* is not one this tool knows. Callers that cannot supply a validator must
|
|
61
|
+
* REFUSE rather than accept — an unknown lane has no contract to check against,
|
|
62
|
+
* and "no contract" must never read as "passes".
|
|
63
|
+
*/
|
|
64
|
+
export declare function laneSubmissionValidator(lane: string, context: LaneValidationContext): ((value: unknown) => SubmissionIssue | null) | null;
|
|
65
|
+
//# sourceMappingURL=laneValidators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"laneValidators.d.ts","sourceRoot":"","sources":["../../../src/audit/cli/laneValidators.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAEtC,OAAO,EAOL,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,oBAAoB,CAAC;AAQ5B,4GAA4G;AAC5G,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAiBtE;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,GACb;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,OAAO,EAAE,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAShE;AAED,6EAA6E;AAC7E,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAElC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,WAAW,EACjB,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,GAC7B,UAAU,CAsBZ;AAED;;;GAGG;AACH,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAOxE,CAAC;AA6BF,6EAA6E;AAC7E,MAAM,WAAW,qBAAqB;IACpC,yEAAyE;IACzE,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACzC;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,qBAAqB,GAC7B,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,eAAe,GAAG,IAAI,CAAC,GAAG,IAAI,CA4BrD"}
|