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.
Files changed (133) hide show
  1. package/dist/audit/cli/auditStep.d.ts +1 -1
  2. package/dist/audit/cli/conceptualDispatch.d.ts +3 -0
  3. package/dist/audit/cli/conceptualDispatch.d.ts.map +1 -1
  4. package/dist/audit/cli/conceptualDispatch.js +82 -24
  5. package/dist/audit/cli/conceptualDispatch.js.map +1 -1
  6. package/dist/audit/cli/dispatch/hostHandoff.d.ts +12 -0
  7. package/dist/audit/cli/dispatch/hostHandoff.d.ts.map +1 -1
  8. package/dist/audit/cli/dispatch/hostHandoff.js +169 -78
  9. package/dist/audit/cli/dispatch/hostHandoff.js.map +1 -1
  10. package/dist/audit/cli/fanoutLanes.d.ts +47 -11
  11. package/dist/audit/cli/fanoutLanes.d.ts.map +1 -1
  12. package/dist/audit/cli/fanoutLanes.js +15 -7
  13. package/dist/audit/cli/fanoutLanes.js.map +1 -1
  14. package/dist/audit/cli/laneSubmissions.d.ts +241 -0
  15. package/dist/audit/cli/laneSubmissions.d.ts.map +1 -0
  16. package/dist/audit/cli/laneSubmissions.js +438 -0
  17. package/dist/audit/cli/laneSubmissions.js.map +1 -0
  18. package/dist/audit/cli/laneValidators.d.ts +65 -0
  19. package/dist/audit/cli/laneValidators.d.ts.map +1 -0
  20. package/dist/audit/cli/laneValidators.js +145 -0
  21. package/dist/audit/cli/laneValidators.js.map +1 -0
  22. package/dist/audit/cli/nextStepCommand.d.ts +1 -1
  23. package/dist/audit/cli/nextStepCommand.d.ts.map +1 -1
  24. package/dist/audit/cli/nextStepCommand.js +118 -69
  25. package/dist/audit/cli/nextStepCommand.js.map +1 -1
  26. package/dist/audit/cli/nextStepHelpers.d.ts +73 -42
  27. package/dist/audit/cli/nextStepHelpers.d.ts.map +1 -1
  28. package/dist/audit/cli/nextStepHelpers.js +389 -253
  29. package/dist/audit/cli/nextStepHelpers.js.map +1 -1
  30. package/dist/audit/cli/recoverSubmissionCommand.d.ts +16 -0
  31. package/dist/audit/cli/recoverSubmissionCommand.d.ts.map +1 -0
  32. package/dist/audit/cli/recoverSubmissionCommand.js +73 -0
  33. package/dist/audit/cli/recoverSubmissionCommand.js.map +1 -0
  34. package/dist/audit/cli/semanticReviewStep.d.ts +3 -0
  35. package/dist/audit/cli/semanticReviewStep.d.ts.map +1 -1
  36. package/dist/audit/cli/semanticReviewStep.js +30 -1
  37. package/dist/audit/cli/semanticReviewStep.js.map +1 -1
  38. package/dist/audit/cli/steps.d.ts +75 -2
  39. package/dist/audit/cli/steps.d.ts.map +1 -1
  40. package/dist/audit/cli/steps.js +14 -0
  41. package/dist/audit/cli/steps.js.map +1 -1
  42. package/dist/audit/cli.d.ts.map +1 -1
  43. package/dist/audit/cli.js +5 -1
  44. package/dist/audit/cli.js.map +1 -1
  45. package/dist/audit/contracts/wrapperResponse.d.ts +7 -7
  46. package/dist/audit/contracts/wrapperResponse.js +1 -1
  47. package/dist/audit/contracts/wrapperResponse.js.map +1 -1
  48. package/dist/audit/io/artifacts.d.ts +12 -1
  49. package/dist/audit/io/artifacts.d.ts.map +1 -1
  50. package/dist/audit/io/artifacts.js +28 -1
  51. package/dist/audit/io/artifacts.js.map +1 -1
  52. package/dist/audit/orchestrator/ingestionExecutors.d.ts.map +1 -1
  53. package/dist/audit/orchestrator/ingestionExecutors.js +13 -16
  54. package/dist/audit/orchestrator/ingestionExecutors.js.map +1 -1
  55. package/dist/audit/orchestrator/lensSelection.d.ts +19 -0
  56. package/dist/audit/orchestrator/lensSelection.d.ts.map +1 -1
  57. package/dist/audit/orchestrator/lensSelection.js +24 -0
  58. package/dist/audit/orchestrator/lensSelection.js.map +1 -1
  59. package/dist/audit/orchestrator/planningExecutors.d.ts +1 -12
  60. package/dist/audit/orchestrator/planningExecutors.d.ts.map +1 -1
  61. package/dist/audit/orchestrator/planningExecutors.js +14 -64
  62. package/dist/audit/orchestrator/planningExecutors.js.map +1 -1
  63. package/dist/audit/orchestrator/requeueFold.d.ts +43 -0
  64. package/dist/audit/orchestrator/requeueFold.d.ts.map +1 -0
  65. package/dist/audit/orchestrator/requeueFold.js +50 -0
  66. package/dist/audit/orchestrator/requeueFold.js.map +1 -0
  67. package/dist/audit/orchestrator/synthesisExecutors.d.ts.map +1 -1
  68. package/dist/audit/orchestrator/synthesisExecutors.js +2 -0
  69. package/dist/audit/orchestrator/synthesisExecutors.js.map +1 -1
  70. package/dist/audit/reporting/synthesis.d.ts +9 -1
  71. package/dist/audit/reporting/synthesis.d.ts.map +1 -1
  72. package/dist/audit/reporting/synthesis.js +69 -1
  73. package/dist/audit/reporting/synthesis.js.map +1 -1
  74. package/dist/audit/supervisor/operatorHandoff.d.ts +9 -2
  75. package/dist/audit/supervisor/operatorHandoff.d.ts.map +1 -1
  76. package/dist/audit/supervisor/operatorHandoff.js +17 -10
  77. package/dist/audit/supervisor/operatorHandoff.js.map +1 -1
  78. package/dist/audit/types/designAssessment.d.ts +9 -5
  79. package/dist/audit/types/designAssessment.d.ts.map +1 -1
  80. package/dist/remediate/index.d.ts.map +1 -1
  81. package/dist/remediate/index.js +48 -1
  82. package/dist/remediate/index.js.map +1 -1
  83. package/dist/remediate/steps/dispatch/hostHandoff.d.ts +38 -6
  84. package/dist/remediate/steps/dispatch/hostHandoff.d.ts.map +1 -1
  85. package/dist/remediate/steps/dispatch/hostHandoff.js +87 -75
  86. package/dist/remediate/steps/dispatch/hostHandoff.js.map +1 -1
  87. package/dist/shared/decompose/charterClarification.d.ts +1 -1
  88. package/dist/shared/decompose/charterClarification.js +1 -1
  89. package/dist/shared/decompose/charterExtraction.js +1 -1
  90. package/dist/shared/decompose/charterExtraction.js.map +1 -1
  91. package/dist/shared/decompose/systemicChallenge.js +1 -1
  92. package/dist/shared/decompose/systemicChallenge.js.map +1 -1
  93. package/dist/shared/index.d.ts +12 -2
  94. package/dist/shared/index.d.ts.map +1 -1
  95. package/dist/shared/index.js +7 -2
  96. package/dist/shared/index.js.map +1 -1
  97. package/dist/shared/io/auditToolsPaths.d.ts +24 -4
  98. package/dist/shared/io/auditToolsPaths.d.ts.map +1 -1
  99. package/dist/shared/io/auditToolsPaths.js +29 -5
  100. package/dist/shared/io/auditToolsPaths.js.map +1 -1
  101. package/dist/shared/io/schemaVersion.d.ts +5 -4
  102. package/dist/shared/io/schemaVersion.d.ts.map +1 -1
  103. package/dist/shared/io/schemaVersion.js +17 -5
  104. package/dist/shared/io/schemaVersion.js.map +1 -1
  105. package/dist/shared/loopCorePaths.d.ts.map +1 -1
  106. package/dist/shared/loopCorePaths.js +8 -2
  107. package/dist/shared/loopCorePaths.js.map +1 -1
  108. package/dist/shared/submission/expectedSubmissions.d.ts +88 -0
  109. package/dist/shared/submission/expectedSubmissions.d.ts.map +1 -0
  110. package/dist/shared/submission/expectedSubmissions.js +84 -0
  111. package/dist/shared/submission/expectedSubmissions.js.map +1 -0
  112. package/dist/shared/submission/handRecovery.d.ts +37 -0
  113. package/dist/shared/submission/handRecovery.d.ts.map +1 -0
  114. package/dist/shared/submission/handRecovery.js +123 -0
  115. package/dist/shared/submission/handRecovery.js.map +1 -0
  116. package/dist/shared/submission/submissionClassifier.d.ts +48 -0
  117. package/dist/shared/submission/submissionClassifier.d.ts.map +1 -0
  118. package/dist/shared/submission/submissionClassifier.js +83 -0
  119. package/dist/shared/submission/submissionClassifier.js.map +1 -0
  120. package/dist/shared/submission/submissionIdentity.d.ts +49 -0
  121. package/dist/shared/submission/submissionIdentity.d.ts.map +1 -0
  122. package/dist/shared/submission/submissionIdentity.js +90 -0
  123. package/dist/shared/submission/submissionIdentity.js.map +1 -0
  124. package/dist/shared/submission/submissionLedger.d.ts +37 -0
  125. package/dist/shared/submission/submissionLedger.d.ts.map +1 -0
  126. package/dist/shared/submission/submissionLedger.js +81 -0
  127. package/dist/shared/submission/submissionLedger.js.map +1 -0
  128. package/dist/shared/types/finding.d.ts +16 -0
  129. package/dist/shared/types/finding.d.ts.map +1 -1
  130. package/dist/shared/types/finding.js +60 -0
  131. package/dist/shared/types/finding.js.map +1 -1
  132. package/docs/audit-pkg/product.md +0 -2
  133. 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
- * incoming file) — never a raw file path, so no unvalidated cast here.
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":"AAEA,OAAO,EACL,KAAK,gBAAgB,EAEtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AASzD,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;CACtB;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,CAkH9B"}
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
- const incoming = join(artifactsDir, "incoming");
67
- await mkdir(incoming, { recursive: true });
68
- const conceptualResultsPath = join(incoming, "design-review-conceptual-findings.json");
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 conceptualPromptPath = join(incoming, "design-review-conceptual-prompt.md");
72
- const conceptualPromptText = renderConceptualReviewPrompt(bundle, reviewOptions) + reReviewSuffix;
73
- await writeFile(conceptualPromptPath, conceptualPromptText, "utf8");
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 perspectiveFiles = [];
93
- for (let i = 0; i < total; i++) {
94
- const p = perspectives[i];
95
- const promptPath = join(incoming, `design-review-conceptual-p${i + 1}-prompt.md`);
96
- const resultsPath = join(incoming, `design-review-conceptual-p${i + 1}-findings.json`);
97
- const promptText = renderConceptualPerspectivePrompt(bundle, p, i, total, reviewOptions);
98
- await writeFile(promptPath, promptText, "utf8");
99
- perspectiveFiles.push({ name: p.name, promptPath, resultsPath });
100
- }
101
- const judgePromptPath = join(incoming, "design-review-conceptual-judge-prompt.md");
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
- await writeFile(judgePromptPath, judgePromptText, "utf8");
104
- const perspectiveLines = perspectiveFiles.map((f, i) => ` - Perspective ${i + 1} (${f.name}): prompt \`${f.promptPath}\` → findings \`${f.resultsPath}\``);
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
- perspectiveFiles.forEach((f, i) => {
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
- ...perspectiveFiles.map((f) => f.promptPath),
129
- ...perspectiveFiles.map((f) => f.resultsPath),
185
+ ...perspectivePrompts.map((f) => f.promptPath),
186
+ ...perspectivePrompts.map((f) => f.resultsPath),
130
187
  judgePromptPath,
131
188
  ],
132
189
  writePaths: [
133
- ...perspectiveFiles.map((f) => f.resultsPath),
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":"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"}
1
+ {"version":3,"file":"conceptualDispatch.js","sourceRoot":"","sources":["../../../src/audit/cli/conceptualDispatch.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,wBAAwB,GACzB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAEL,4BAA4B,EAC5B,iCAAiC,EACjC,2BAA2B,EAC3B,kBAAkB,GACnB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,OAAO,EACL,2BAA2B,EAC3B,UAAU,EACV,yBAAyB,EACzB,oBAAoB,EACpB,kBAAkB,GAEnB,MAAM,sBAAsB,CAAC;AA2B9B;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAC/B,UAA0D,EAC1D,WAA+B,EAC/B,aAAiD,EACjD,aAAiC;IAEjC,MAAM,IAAI,GAAG,WAAW,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7E,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5D,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5D,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,SAAS,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClE,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,SAAS,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClE,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;IACzE,MAAM,KAAK,GAAG,UAAU,CAAC,gBAAgB,IAAI,aAAa,CAAC;IAC3D,OAAO,wBAAwB,IAAI,KAAK,MAAM,sBAAsB,KAAK,IAAI,CAAC;AAChF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,+BAA+B,CAC7C,MAAsB;IAEtB,MAAM,UAAU,GAAG,MAAM,CAAC,iBAAiB,EAAE,aAAa,CAAC;IAC3D,6EAA6E;IAC7E,6EAA6E;IAC7E,yEAAyE;IACzE,4CAA4C;IAC5C,MAAM,YAAY,GAAG,CAAC,MAAM,CAAC,gBAAgB,EAAE,UAAU,IAAI,EAAE,CAAC,CAAC,IAAI,CACnE,CAAC,SAAS,EAAE,EAAE,CACZ,SAAS,CAAC,QAAQ,CAAC,IAAI,CACrB,CAAC,OAAO,EAAE,EAAE,CAAC,wBAAwB,CAAC,OAAO,CAAC,KAAK,gBAAgB,CACpE,CACJ,CAAC;IACF,MAAM,eAAe,GACnB,UAAU,EAAE,gBAAgB,IAAI,SAAS,CAAC;IAC5C,+EAA+E;IAC/E,yEAAyE;IACzE,kFAAkF;IAClF,MAAM,WAAW,GAAG,UAAU;QAC5B,CAAC,CAAC,iBAAiB,CACf,UAAU,EACV,MAAM,CAAC,iBAAiB,EAAE,YAAY,EACtC,MAAM,CAAC,iBAAiB,EAAE,cAAc,EACxC,eAAe,CAChB;QACH,CAAC,CAAC,SAAS,CAAC;IACd,OAAO;QACL,gBAAgB,EAAE,eAAe;QACjC,YAAY,EAAE,UAAU,EAAE,YAAY;QACtC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtD,CAAC;AACJ,CAAC;AAqBD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,IAa/C;IACC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IAChD,MAAM,cAAc,GAAG,IAAI,CAAC,eAAe;QACzC,CAAC,CAAC,OAAO,IAAI,CAAC,eAAe,EAAE;QAC/B,CAAC,CAAC,EAAE,CAAC;IACP,6EAA6E;IAC7E,6EAA6E;IAC7E,8EAA8E;IAC9E,0DAA0D;IAC1D,MAAM,qBAAqB,GAAG,kBAAkB,CAC9C,YAAY,EACZ,UAAU,CAAC,wBAAwB,CACpC,CAAC;IACF,MAAM,aAAa,GAAwB,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,CAAC;IAE7E,IAAI,QAAQ,CAAC,gBAAgB,KAAK,MAAM,EAAE,CAAC;QACzC,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC;YAC1C,YAAY;YACZ,KAAK,EAAE,2BAA2B;YAClC,KAAK,EAAE;gBACL;oBACE,EAAE,EAAE,UAAU,CAAC,wBAAwB;oBACvC,KAAK,EAAE,gCAAgC;oBACvC,cAAc,EAAE,oCAAoC;oBACpD,UAAU,EACR,4BAA4B,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,cAAc;iBACvE;aACF;SACF,CAAC,CAAC;QACH,MAAM,oBAAoB,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,UAAU,CAAC;QACzD,OAAO;YACL,IAAI,EAAE,KAAK;YACX,qBAAqB;YACrB,gBAAgB,EAAE;gBAChB,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzD,iKAAiK;aAClK;YACD,aAAa,EAAE;gBACb,iBAAiB,EAAE,oBAAoB;gBACvC,kBAAkB,EAAE,qBAAqB;aAC1C;YACD,SAAS,EAAE,CAAC,oBAAoB,CAAC;YACjC,UAAU,EAAE,CAAC,qBAAqB,CAAC;YACnC,SAAS,EAAE,MAAM,CAAC,SAAS;SAC5B,CAAC;IACJ,CAAC;IAED,uEAAuE;IACvE,4EAA4E;IAC5E,+EAA+E;IAC/E,0EAA0E;IAC1E,iBAAiB;IACjB,MAAM,YAAY,GAAG,kBAAkB,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC;IAClC,MAAM,gBAAgB,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACjD,iCAAiC,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CACtE,CAAC;IACF,2EAA2E;IAC3E,0EAA0E;IAC1E,6EAA6E;IAC7E,6EAA6E;IAC7E,0DAA0D;IAC1D,MAAM,UAAU,GAAG,oBAAoB,CAAC;QACtC,GAAG,gBAAgB;QACnB,IAAI,CAAC,eAAe,IAAI,EAAE;KAC3B,CAAC,CAAC;IACH,MAAM,gBAAgB,GAMjB,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAC7B,MAAM,IAAI,GAAG,yBAAyB,CAAC,CAAC,GAAG,CAAC,EAAE,UAAU,CAAC,CAAC;QAC1D,OAAO;YACL,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,IAAI;YACJ,cAAc,EAAE,6BAA6B,CAAC,GAAG,CAAC,YAAY;YAC9D,UAAU,EAAE,gBAAgB,CAAC,CAAC,CAAE;YAChC,WAAW,EAAE,kBAAkB,CAC7B,YAAY,EACZ,IAAI,EACJ,2BAA2B,CAC5B;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,eAAe,GACnB,2BAA2B,CACzB,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CACrE,GAAG,cAAc,CAAC;IAErB,MAAM,SAAS,GAAqB;QAClC,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC9B,EAAE,EAAE,CAAC,CAAC,IAAI;YACV,KAAK,EAAE,4BAA4B,CAAC,CAAC,IAAI,EAAE;YAC3C,cAAc,EAAE,CAAC,CAAC,cAAc;YAChC,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,uEAAuE;YACvE,yEAAyE;YACzE,yEAAyE;YACzE,QAAQ,EAAE,KAAK;SAChB,CAAC,CAAC;QACH;YACE,uEAAuE;YACvE,gEAAgE;YAChE,EAAE,EAAE,UAAU,CAAC,wBAAwB;YACvC,KAAK,EAAE,6CAA6C;YACpD,cAAc,EAAE,0CAA0C;YAC1D,UAAU,EAAE,eAAe;SAC5B;KACF,CAAC;IACF,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC;QAC1C,YAAY;QACZ,KAAK,EAAE,2BAA2B;QAClC,KAAK,EAAE,SAAS;KACjB,CAAC,CAAC;IACH,MAAM,aAAa,GAAG,CAAC,MAAc,EAAU,EAAE,CAC/C,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,MAAM,CAAE,CAAC,UAAU,CAAC;IAC9D,MAAM,eAAe,GAAG,aAAa,CAAC,UAAU,CAAC,wBAAwB,CAAC,CAAC;IAC3E,MAAM,kBAAkB,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACtD,GAAG,CAAC;QACJ,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC;KAClC,CAAC,CAAC,CAAC;IAEJ,MAAM,gBAAgB,GAAG,kBAAkB,CAAC,GAAG,CAC7C,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,oBAAoB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,eAAe,CAAC,CAAC,UAAU,mBAAmB,CAAC,CAAC,WAAW,IAAI,CACtG,CAAC;IAEF,MAAM,aAAa,GAA2B;QAC5C,kBAAkB,EAAE,qBAAqB;QACzC,uBAAuB,EAAE,eAAe;KACzC,CAAC;IACF,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAClC,aAAa,CAAC,0BAA0B,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC;QACvE,aAAa,CAAC,0BAA0B,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC;IAC3E,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,IAAI,EAAE,IAAI;QACV,qBAAqB;QACrB,gBAAgB,EAAE;YAChB,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACzD,6CAA6C,KAAK,wBAAwB;YAC1E,oBAAoB,KAAK,4NAA4N;YACrP,GAAG,gBAAgB;YACnB,eAAe,KAAK,uVAAuV,eAAe,sCAAsC,qBAAqB,KAAK;YAC1b,gUAAgU;SACjU;QACD,aAAa;QACb,0EAA0E;QAC1E,gEAAgE;QAChE,SAAS,EAAE;YACT,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;YAC9C,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC;YAC/C,eAAe;SAChB;QACD,UAAU,EAAE;YACV,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC;YAC/C,qBAAqB;SACtB;QACD,SAAS,EAAE,MAAM,CAAC,SAAS;KAC5B,CAAC;AACJ,CAAC"}
@@ -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":"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"}
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 { isAbsolute, join, relative, resolve } from "node:path";
4
- import { FindingSchema, isFileMissingError, isJsonParseError, readJsonFile, stableStringify, writeJsonFile, } from "audit-tools/shared";
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
- assertRunId(params.runId);
25
+ assertSubmissionRunId(params.runId, "audit host run id");
57
26
  const root = resolve(params.root);
58
- const artifactsDir = resolveContained(root, params.artifactsDir, "artifactsDir");
59
- const runDir = resolveContained(artifactsDir, join("runs", params.runId), "audit host run directory");
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
- const absolute = join(paths.resultDir, `${sha256(workItemId)}.json`);
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 = resolveContained(root, raw, `${taskId} file path`);
106
- return repoRelative(root, absolute, `${taskId} file path`);
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 = repoRelative(root, resolveContained(root, path, `${taskId} line-count path`), `${taskId} line-count path`);
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; findings must satisfy the audit finding contract.",
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: sha256(promptText),
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 === sha256(stableStringify(value.result)) &&
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
- sha256(value.prompt.text) !== value.prompt.sha256 ||
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
- value.run_id !== runId ||
473
- value.work_item_id !== item.id ||
474
- value.prompt_sha256 !== item.prompt.sha256 ||
475
- !Array.isArray(value.file_coverage) ||
476
- !Array.isArray(value.findings) ||
477
- !value.findings.every((finding) => FindingSchema.safeParse(finding).success)) {
478
- return null;
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
- coveragePaths.has(coverage.path) ||
486
- !Number.isInteger(coverage.reviewed_lines) ||
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
- coverage.total_lines !== binding.file_line_counts[coverage.path]) {
491
- return null;
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
- if (coveragePaths.size !== item.scope.files.length ||
496
- item.scope.files.some((path) => !coveragePaths.has(path))) {
497
- return null;
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 JSON.parse(stableStringify(value));
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
- return parsed.success ? parsed.data : null;
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
- async function readSubmittedResult(absolutePath, runId, item, binding) {
520
- try {
521
- return parseHostResult(await readJsonFile(absolutePath), runId, item, binding);
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
- catch (error) {
524
- if (isFileMissingError(error) || isJsonParseError(error))
525
- return null;
526
- throw error;
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 = resolveContained(paths.root, entry.result_path, `result path for ${entry.work_item_id}`);
547
- const result = await readSubmittedResult(absoluteResultPath, params.runId, item, binding);
548
- if (result === null || resultIds.has(result.result_id))
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
- const auditResult = toAuditResult(result, binding);
551
- if (auditResult === null)
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: sha256(stableStringify(result)),
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