@agent-delivery-harness/conformance 0.1.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/LICENSE +202 -0
- package/NOTICE +5 -0
- package/README.md +159 -0
- package/fixtures/repo-config-adapter.ts +250 -0
- package/package.json +24 -0
- package/src/generate.ts +1013 -0
- package/src/index.ts +36 -0
- package/src/json-schema.ts +222 -0
- package/src/runner.ts +687 -0
- package/vectors/context/environment.json +21 -0
- package/vectors/context/repo-config.json +22 -0
- package/vectors/kit.json +1250 -0
- package/vectors/vectors/accept/a-completed-order-differs.json +112 -0
- package/vectors/vectors/accept/a-cost-fractional.json +116 -0
- package/vectors/vectors/accept/a-cost-tokens.json +120 -0
- package/vectors/vectors/accept/a-deferred-expansion.json +124 -0
- package/vectors/vectors/accept/a-idempotent-resubmission.json +115 -0
- package/vectors/vectors/accept/a-minimal-green.json +97 -0
- package/vectors/vectors/accept/a-resolved-and-advisory.json +129 -0
- package/vectors/vectors/accept/a-three-reviewers.json +113 -0
- package/vectors/vectors/reject/env-1-unregistered-provider.json +114 -0
- package/vectors/vectors/reject/env-10-artifact-duplicate.json +103 -0
- package/vectors/vectors/reject/env-10-artifact-missing-file.json +104 -0
- package/vectors/vectors/reject/env-10-artifact-traversal.json +99 -0
- package/vectors/vectors/reject/env-11-artifact-digest-mismatch.json +98 -0
- package/vectors/vectors/reject/env-12-unknown-attestation-level.json +114 -0
- package/vectors/vectors/reject/env-13-nonempty-signatures.json +118 -0
- package/vectors/vectors/reject/env-14-duplicate-claim.json +149 -0
- package/vectors/vectors/reject/env-14-no-claims.json +78 -0
- package/vectors/vectors/reject/env-14-unconfigured-obligation.json +114 -0
- package/vectors/vectors/reject/env-14-unsupported-payload-spec.json +114 -0
- package/vectors/vectors/reject/env-2-run-id-1.json +114 -0
- package/vectors/vectors/reject/env-2-run-id-2.json +114 -0
- package/vectors/vectors/reject/env-2-run-id-3.json +114 -0
- package/vectors/vectors/reject/env-2-run-id-4.json +114 -0
- package/vectors/vectors/reject/env-2-run-id-5.json +114 -0
- package/vectors/vectors/reject/env-4-unsupported-vcs.json +114 -0
- package/vectors/vectors/reject/env-5-malformed-object-id.json +114 -0
- package/vectors/vectors/reject/env-6-missing-identity.json +111 -0
- package/vectors/vectors/reject/env-6-unknown-identity-version.json +114 -0
- package/vectors/vectors/reject/env-8-repository-required.json +116 -0
- package/vectors/vectors/reject/env-9-empty-run-history.json +107 -0
- package/vectors/vectors/reject/env-9-final-pass-mismatch.json +110 -0
- package/vectors/vectors/reject/env-9-final-tree-mismatch.json +110 -0
- package/vectors/vectors/reject/gen-1-legacy-count-field.json +115 -0
- package/vectors/vectors/reject/gen-1-unknown-envelope-member.json +117 -0
- package/vectors/vectors/reject/gen-2-unsupported-spec.json +114 -0
- package/vectors/vectors/reject/rg-1-edited-after-final-pass.json +114 -0
- package/vectors/vectors/reject/rg-1-not-finalized.json +114 -0
- package/vectors/vectors/reject/rg-1-verdict-not-green.json +114 -0
- package/vectors/vectors/reject/rg-10-cost-by-reviewer-exceeds-total.json +115 -0
- package/vectors/vectors/reject/rg-10-cost-empty-reported-by.json +111 -0
- package/vectors/vectors/reject/rg-10-cost-empty-unit.json +111 -0
- package/vectors/vectors/reject/rg-10-cost-missing-unit.json +110 -0
- package/vectors/vectors/reject/rg-10-cost-negative-by-reviewer.json +114 -0
- package/vectors/vectors/reject/rg-10-cost-negative-total.json +111 -0
- package/vectors/vectors/reject/rg-10-cost-null-total.json +111 -0
- package/vectors/vectors/reject/rg-10-cost-unknown-reviewer-in-breakdown.json +114 -0
- package/vectors/vectors/reject/rg-2-duplicate-selected.json +99 -0
- package/vectors/vectors/reject/rg-3-completed-missing.json +96 -0
- package/vectors/vectors/reject/rg-3-completed-unrelated.json +99 -0
- package/vectors/vectors/reject/rg-3-failed-reviewer.json +100 -0
- package/vectors/vectors/reject/rg-3-timed-out-reviewer.json +100 -0
- package/vectors/vectors/reject/rg-4-approval-extra.json +104 -0
- package/vectors/vectors/reject/rg-4-approval-malformed.json +98 -0
- package/vectors/vectors/reject/rg-4-approval-missing.json +100 -0
- package/vectors/vectors/reject/rg-4-approval-not-approved.json +98 -0
- package/vectors/vectors/reject/rg-4-approval-wrong-candidate.json +98 -0
- package/vectors/vectors/reject/rg-4-approval-wrong-pass.json +98 -0
- package/vectors/vectors/reject/rg-4-approval-wrong-provider.json +98 -0
- package/vectors/vectors/reject/rg-4-approval-wrong-reviewer.json +98 -0
- package/vectors/vectors/reject/rg-4-approval-wrong-run.json +98 -0
- package/vectors/vectors/reject/rg-4-approval-wrong-workspace.json +98 -0
- package/vectors/vectors/reject/rg-5-duplicate-finding-id.json +131 -0
- package/vectors/vectors/reject/rg-5-unknown-disposition.json +123 -0
- package/vectors/vectors/reject/rg-5-unknown-scope.json +123 -0
- package/vectors/vectors/reject/rg-5-unknown-severity.json +123 -0
- package/vectors/vectors/reject/rg-6-actionable-ignored.json +123 -0
- package/vectors/vectors/reject/rg-6-actionable-unresolved.json +123 -0
- package/vectors/vectors/reject/rg-6-blocking-finding.json +123 -0
- package/vectors/vectors/reject/rg-7-defer-adjacent.json +126 -0
- package/vectors/vectors/reject/rg-7-defer-blocking.json +126 -0
- package/vectors/vectors/reject/rg-7-defer-in-contract.json +126 -0
- package/vectors/vectors/reject/rg-7-defer-lowercase-issue-id.json +126 -0
- package/vectors/vectors/reject/rg-7-defer-missing-issue-id.json +125 -0
- package/vectors/vectors/reject/rg-7-defer-non-actionable.json +126 -0
- package/vectors/vectors/reject/rg-7-defer-p0.json +126 -0
- package/vectors/vectors/reject/rg-7-defer-p1.json +126 -0
- package/vectors/vectors/reject/rg-7-defer-placeholder-issue-id.json +126 -0
- package/vectors/vectors/reject/rg-7-issue-id-on-resolved.json +124 -0
- package/vectors/vectors/reject/rg-8-counts-contradict-findings.json +126 -0
- package/vectors/vectors/reject/rg-8-deferral-count-disagrees.json +124 -0
- package/vectors/vectors/reject/rg-8-deferral-ids-disagree.json +126 -0
- package/vectors/vectors/reject/rg-9-iteration-count-mismatch.json +114 -0
- package/vectors/vectors/reject/sub-1-base-tip-moved.json +131 -0
- package/vectors/vectors/reject/sub-1-deliverable-changed.json +131 -0
- package/vectors/vectors/reject/sub-1-merge-base-moved.json +131 -0
- package/vectors/vectors/reject/sub-1-raw-tree-changed.json +131 -0
- package/vectors/vectors/reject/sub-2-unprepared.json +117 -0
- package/vectors/vectors/reject/sub-3-manifest-outside-run-root.json +117 -0
- package/vectors/vectors/reject/sub-4-record-conflict.json +220 -0
package/src/generate.ts
ADDED
|
@@ -0,0 +1,1013 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generator for the delivery-evidence/1 conformance kit.
|
|
3
|
+
*
|
|
4
|
+
* Emits golden vectors derived from Athena's production recorder test corpus
|
|
5
|
+
* (scripts/harness-review-evidence.test.ts), restated against the
|
|
6
|
+
* delivery-evidence/1 envelope. Run with: bun generate.ts <outDir>
|
|
7
|
+
*
|
|
8
|
+
* Every vector is self-contained: environment overrides, artifact file
|
|
9
|
+
* contents (exact bytes), the manifest, and the expected outcome. Accept
|
|
10
|
+
* vectors carry correct artifact digests, computed here; digest-mismatch
|
|
11
|
+
* vectors carry deliberately wrong ones.
|
|
12
|
+
*/
|
|
13
|
+
import { createHash } from "node:crypto";
|
|
14
|
+
import { mkdirSync, writeFileSync, rmSync } from "node:fs";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
|
|
17
|
+
const OUT = process.argv[2] ?? "kit-out";
|
|
18
|
+
|
|
19
|
+
const sha256 = (s: string) => createHash("sha256").update(s).digest("hex");
|
|
20
|
+
const oid = (label: string) => sha256(`oid:${label}`).slice(0, 40);
|
|
21
|
+
const digest64 = (label: string) => sha256(`digest:${label}`);
|
|
22
|
+
|
|
23
|
+
// ── Shared context ─────────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
const PROVIDER = "claude-code.ce-code-review";
|
|
26
|
+
const OBLIGATION = "review.green";
|
|
27
|
+
const PAYLOAD_SPEC = "review.green/1";
|
|
28
|
+
const IDENTITY = "deliverable-tree/v1";
|
|
29
|
+
const WORKSPACE = "w-" + sha256("workspace-a").slice(0, 16);
|
|
30
|
+
|
|
31
|
+
const CANDIDATE = {
|
|
32
|
+
vcs: "git",
|
|
33
|
+
treeSha: oid("tree-final"),
|
|
34
|
+
headSha: oid("head-final"),
|
|
35
|
+
deliverable: { digest: digest64("deliverable-final"), identity: IDENTITY },
|
|
36
|
+
base: {
|
|
37
|
+
ref: "origin/main",
|
|
38
|
+
tipSha: oid("base-tip"),
|
|
39
|
+
mergeBaseSha: oid("merge-base"),
|
|
40
|
+
},
|
|
41
|
+
workspaceId: WORKSPACE,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const REPO_CONFIG = {
|
|
45
|
+
configVersion: 1,
|
|
46
|
+
gateId: "example.pr-validation",
|
|
47
|
+
acceptedEnvelopeSpecs: ["delivery-evidence/1"],
|
|
48
|
+
identityVersions: [IDENTITY],
|
|
49
|
+
obligations: {
|
|
50
|
+
[OBLIGATION]: {
|
|
51
|
+
acceptedPayloadSpecs: [PAYLOAD_SPEC],
|
|
52
|
+
providers: [PROVIDER, "example.second-provider"],
|
|
53
|
+
minimumAttestationLevel: "self",
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const ENVIRONMENT = {
|
|
59
|
+
environmentVersion: 1,
|
|
60
|
+
description:
|
|
61
|
+
"State the validator harness must establish before running a vector. " +
|
|
62
|
+
"currentCandidate is what the recorder's candidate capture returns at " +
|
|
63
|
+
"submission; prepared=false simulates a missing/failed preparation. The " +
|
|
64
|
+
"harness materializes each vector's artifact contents (exact bytes) " +
|
|
65
|
+
"inside the run root it allocates for provider.runId, and places the " +
|
|
66
|
+
"manifest at that run root unless the vector overrides manifestLocation.",
|
|
67
|
+
currentCandidate: CANDIDATE,
|
|
68
|
+
workspaceId: WORKSPACE,
|
|
69
|
+
prepared: true,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// ── Builders ───────────────────────────────────────────────────────────────
|
|
73
|
+
|
|
74
|
+
type Json = Record<string, unknown>;
|
|
75
|
+
|
|
76
|
+
function approval(reviewerId: string, over: Json = {}): string {
|
|
77
|
+
const doc = {
|
|
78
|
+
schemaVersion: 1,
|
|
79
|
+
reviewerId,
|
|
80
|
+
result: "approved",
|
|
81
|
+
provider: { id: PROVIDER, runId: "r-conformance-01", finalPassId: "pass-2" },
|
|
82
|
+
workspaceId: WORKSPACE,
|
|
83
|
+
candidate: CANDIDATE,
|
|
84
|
+
...over,
|
|
85
|
+
};
|
|
86
|
+
return JSON.stringify(doc, null, 2) + "\n";
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function baseArtifacts(reviewers: string[]): {
|
|
90
|
+
files: Record<string, string>;
|
|
91
|
+
entries: Array<{ path: string; sha256: string; role: string }>;
|
|
92
|
+
} {
|
|
93
|
+
const files: Record<string, string> = {};
|
|
94
|
+
const entries = reviewers.map((r) => {
|
|
95
|
+
const p = `reviewers/${r}.json`;
|
|
96
|
+
files[p] = approval(r);
|
|
97
|
+
return { path: p, sha256: sha256(files[p]), role: "reviewer-approval" };
|
|
98
|
+
});
|
|
99
|
+
return { files, entries };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function baseManifest(over: {
|
|
103
|
+
reviewers?: string[];
|
|
104
|
+
findings?: Json[];
|
|
105
|
+
telemetry?: Json;
|
|
106
|
+
runHistory?: Json[];
|
|
107
|
+
claims?: Json[];
|
|
108
|
+
envelope?: Json;
|
|
109
|
+
payload?: Json;
|
|
110
|
+
artifactEntries?: Array<{ path: string; sha256: string; role: string }>;
|
|
111
|
+
} = {}): { manifest: Json; files: Record<string, string> } {
|
|
112
|
+
const reviewers = over.reviewers ?? ["correctness", "security", "tests"];
|
|
113
|
+
const { files, entries } = baseArtifacts(reviewers);
|
|
114
|
+
const findings = over.findings ?? [];
|
|
115
|
+
const counts = { P0: 0, P1: 0, P2: 0, P3: 0 } as Record<string, number>;
|
|
116
|
+
for (const f of findings) counts[f.severity as string] += 1;
|
|
117
|
+
const deferred = findings.filter((f) => f.disposition === "deferred");
|
|
118
|
+
const runHistory =
|
|
119
|
+
over.runHistory ??
|
|
120
|
+
[
|
|
121
|
+
{ preparedTreeSha: oid("tree-pass-1"), evaluatedInPassId: "pass-1" },
|
|
122
|
+
{ preparedTreeSha: CANDIDATE.treeSha, evaluatedInPassId: "pass-2" },
|
|
123
|
+
];
|
|
124
|
+
const payload = {
|
|
125
|
+
verdict: "green",
|
|
126
|
+
finalized: true,
|
|
127
|
+
editedAfterFinalPass: false,
|
|
128
|
+
reviewers: {
|
|
129
|
+
selected: reviewers,
|
|
130
|
+
completed: [...reviewers],
|
|
131
|
+
failed: [],
|
|
132
|
+
timedOut: [],
|
|
133
|
+
},
|
|
134
|
+
findings,
|
|
135
|
+
telemetry: {
|
|
136
|
+
iterationCount: runHistory.length,
|
|
137
|
+
findingCounts: counts,
|
|
138
|
+
deferredExpansionCount: deferred.length,
|
|
139
|
+
deferredIssueIds: deferred.map((f) => f.deferredIssueId).sort(),
|
|
140
|
+
...((over.telemetry as Json) ?? {}),
|
|
141
|
+
},
|
|
142
|
+
...(over.payload ?? {}),
|
|
143
|
+
};
|
|
144
|
+
const manifest: Json = {
|
|
145
|
+
spec: "delivery-evidence/1",
|
|
146
|
+
provider: {
|
|
147
|
+
id: PROVIDER,
|
|
148
|
+
version: "1.0.0",
|
|
149
|
+
runId: "r-conformance-01",
|
|
150
|
+
finalPassId: "pass-2",
|
|
151
|
+
},
|
|
152
|
+
candidate: CANDIDATE,
|
|
153
|
+
repository: null,
|
|
154
|
+
runHistory,
|
|
155
|
+
artifacts: over.artifactEntries ?? entries,
|
|
156
|
+
attestation: { level: "self", signatures: [] },
|
|
157
|
+
recordedAt: "2026-08-25T00:00:00Z",
|
|
158
|
+
claims: over.claims ?? [
|
|
159
|
+
{ obligation: OBLIGATION, payloadSpec: PAYLOAD_SPEC, payload },
|
|
160
|
+
],
|
|
161
|
+
...(over.envelope ?? {}),
|
|
162
|
+
};
|
|
163
|
+
return { manifest, files };
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const DEFERRED_OK = {
|
|
167
|
+
id: "f-def-1",
|
|
168
|
+
severity: "P2",
|
|
169
|
+
scope: "expansion",
|
|
170
|
+
actionable: true,
|
|
171
|
+
blocking: false,
|
|
172
|
+
disposition: "deferred",
|
|
173
|
+
deferredIssueId: "EX-1300",
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
// ── Vector table ───────────────────────────────────────────────────────────
|
|
177
|
+
|
|
178
|
+
type Vector = {
|
|
179
|
+
id: string;
|
|
180
|
+
title: string;
|
|
181
|
+
rules: string[];
|
|
182
|
+
expect:
|
|
183
|
+
| { result: "accepted"; notes?: string }
|
|
184
|
+
| { result: "rejected"; codes: string[] };
|
|
185
|
+
provenance: string;
|
|
186
|
+
environment?: Json;
|
|
187
|
+
build: () => { manifest: Json; files: Record<string, string>; extra?: Json };
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const ATHENA = "athena:scripts/harness-review-evidence.test.ts";
|
|
191
|
+
const SPEC = "delivery-evidence/1 (new in spec; no Athena antecedent)";
|
|
192
|
+
const TIGHTENED = "delivery-evidence/1 (spec-tightened; Athena accepted a looser form)";
|
|
193
|
+
|
|
194
|
+
const vectors: Vector[] = [
|
|
195
|
+
// ---- accepts ----
|
|
196
|
+
{
|
|
197
|
+
id: "a-minimal-green",
|
|
198
|
+
title: "Minimal green manifest with one reviewer",
|
|
199
|
+
rules: ["GEN-2", "ENV-9", "RG-1"],
|
|
200
|
+
expect: { result: "accepted" },
|
|
201
|
+
provenance: `${ATHENA} "records the same final-green contract"`,
|
|
202
|
+
build: () => baseManifest({ reviewers: ["correctness"] }),
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
id: "a-three-reviewers",
|
|
206
|
+
title: "Green manifest with a three-reviewer set",
|
|
207
|
+
rules: ["RG-2", "RG-3", "RG-4"],
|
|
208
|
+
expect: { result: "accepted" },
|
|
209
|
+
provenance: `${ATHENA} fixture shape`,
|
|
210
|
+
build: () => baseManifest(),
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
id: "a-completed-order-differs",
|
|
214
|
+
title: "completed lists the same reviewers in a different order",
|
|
215
|
+
rules: ["RG-3"],
|
|
216
|
+
expect: { result: "accepted", notes: "Set equality, not sequence equality." },
|
|
217
|
+
provenance: SPEC,
|
|
218
|
+
build: () => {
|
|
219
|
+
const b = baseManifest();
|
|
220
|
+
const p = (b.manifest.claims as Json[])[0].payload as Json;
|
|
221
|
+
(p.reviewers as Json).completed = ["tests", "correctness", "security"];
|
|
222
|
+
return b;
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
id: "a-deferred-expansion",
|
|
227
|
+
title: "Deferred P2 expansion finding with a tracker id and matching telemetry",
|
|
228
|
+
rules: ["RG-7", "RG-8"],
|
|
229
|
+
expect: { result: "accepted" },
|
|
230
|
+
provenance: `${ATHENA} "records a deferred expansion finding"`,
|
|
231
|
+
build: () => baseManifest({ findings: [DEFERRED_OK] }),
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
id: "a-resolved-and-advisory",
|
|
235
|
+
title: "Resolved P1 and advisory non-actionable finding",
|
|
236
|
+
rules: ["RG-5", "RG-6"],
|
|
237
|
+
expect: { result: "accepted" },
|
|
238
|
+
provenance: `${ATHENA} disposition enum`,
|
|
239
|
+
build: () =>
|
|
240
|
+
baseManifest({
|
|
241
|
+
findings: [
|
|
242
|
+
{ id: "f-1", severity: "P1", scope: "in_contract", actionable: true, blocking: false, disposition: "resolved" },
|
|
243
|
+
{ id: "f-2", severity: "P3", scope: "adjacent", actionable: false, blocking: false, disposition: "advisory" },
|
|
244
|
+
],
|
|
245
|
+
}),
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
id: "a-cost-tokens",
|
|
249
|
+
title: "Self-reported token cost with per-reviewer breakdown summing below total",
|
|
250
|
+
rules: ["RG-10"],
|
|
251
|
+
expect: { result: "accepted" },
|
|
252
|
+
provenance: `${ATHENA} "records a self-reported review cost"`,
|
|
253
|
+
build: () =>
|
|
254
|
+
baseManifest({
|
|
255
|
+
telemetry: {
|
|
256
|
+
cost: { unit: "tokens", total: 512345, reportedBy: "claude-code", byReviewer: { correctness: 190000, security: 150000 } },
|
|
257
|
+
},
|
|
258
|
+
}),
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
id: "a-cost-fractional",
|
|
262
|
+
title: "Fractional cost units from a platform's own metering",
|
|
263
|
+
rules: ["RG-10"],
|
|
264
|
+
expect: { result: "accepted" },
|
|
265
|
+
provenance: `${ATHENA} "platform metering fractional units"`,
|
|
266
|
+
build: () =>
|
|
267
|
+
baseManifest({
|
|
268
|
+
telemetry: { cost: { unit: "credits", total: 12.5, reportedBy: "some-other-runtime" } },
|
|
269
|
+
}),
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
id: "a-idempotent-resubmission",
|
|
273
|
+
title: "Identical resubmission is an idempotent success with the same record ids",
|
|
274
|
+
rules: ["SUB-4"],
|
|
275
|
+
expect: {
|
|
276
|
+
result: "accepted",
|
|
277
|
+
notes: "Submit twice; both succeed and record ids are identical across submissions.",
|
|
278
|
+
},
|
|
279
|
+
provenance: `${ATHENA} "is idempotent for the same provider run, pass, and candidate"`,
|
|
280
|
+
build: () => ({ ...baseManifest(), extra: { submitTwice: true } }),
|
|
281
|
+
},
|
|
282
|
+
|
|
283
|
+
// ---- GEN ----
|
|
284
|
+
{
|
|
285
|
+
id: "gen-1-unknown-envelope-member",
|
|
286
|
+
title: "Unknown member at the envelope root",
|
|
287
|
+
rules: ["GEN-1"],
|
|
288
|
+
expect: { result: "rejected", codes: ["unknown_member"] },
|
|
289
|
+
provenance: SPEC,
|
|
290
|
+
build: () => {
|
|
291
|
+
const b = baseManifest();
|
|
292
|
+
b.manifest.vendorExtension = { anything: true };
|
|
293
|
+
return b;
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
id: "gen-1-legacy-count-field",
|
|
298
|
+
title: "Legacy summary-count field from the pre-spec contract",
|
|
299
|
+
rules: ["GEN-1"],
|
|
300
|
+
expect: { result: "rejected", codes: ["unknown_member"] },
|
|
301
|
+
provenance: `${ATHENA} unresolvedActionableCount (field removed by spec; presence is now unknown_member)`,
|
|
302
|
+
build: () => {
|
|
303
|
+
const b = baseManifest();
|
|
304
|
+
const p = (b.manifest.claims as Json[])[0].payload as Json;
|
|
305
|
+
p.unresolvedActionableCount = 0;
|
|
306
|
+
return b;
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
id: "gen-2-unsupported-spec",
|
|
311
|
+
title: "Unsupported envelope spec version",
|
|
312
|
+
rules: ["GEN-2"],
|
|
313
|
+
expect: { result: "rejected", codes: ["unsupported_envelope_spec"] },
|
|
314
|
+
provenance: SPEC,
|
|
315
|
+
build: () => {
|
|
316
|
+
const b = baseManifest();
|
|
317
|
+
b.manifest.spec = "delivery-evidence/0";
|
|
318
|
+
return b;
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
|
|
322
|
+
// ---- ENV ----
|
|
323
|
+
{
|
|
324
|
+
id: "env-1-unregistered-provider",
|
|
325
|
+
title: "Provider not registered for the claimed obligation",
|
|
326
|
+
rules: ["ENV-1"],
|
|
327
|
+
expect: { result: "rejected", codes: ["unregistered_provider"] },
|
|
328
|
+
provenance: `${ATHENA} provider allowlist`,
|
|
329
|
+
build: () => {
|
|
330
|
+
const b = baseManifest();
|
|
331
|
+
(b.manifest.provider as Json).id = "unknown.provider";
|
|
332
|
+
return b;
|
|
333
|
+
},
|
|
334
|
+
},
|
|
335
|
+
...["../run-a", "nested/run-a", "nested\\run-a", ".", ".."].map(
|
|
336
|
+
(runId, i): Vector => ({
|
|
337
|
+
id: `env-2-run-id-${i + 1}`,
|
|
338
|
+
title: `Unsafe or non-single-component run id ${JSON.stringify(runId)}`,
|
|
339
|
+
rules: ["ENV-2"],
|
|
340
|
+
expect: { result: "rejected", codes: ["invalid_run_id"] },
|
|
341
|
+
provenance: `${ATHENA} "rejects unsafe or non-single-component run ID"`,
|
|
342
|
+
build: () => {
|
|
343
|
+
const b = baseManifest();
|
|
344
|
+
(b.manifest.provider as Json).runId = runId;
|
|
345
|
+
return b;
|
|
346
|
+
},
|
|
347
|
+
}),
|
|
348
|
+
),
|
|
349
|
+
{
|
|
350
|
+
id: "env-4-unsupported-vcs",
|
|
351
|
+
title: "Non-git vcs value",
|
|
352
|
+
rules: ["ENV-4"],
|
|
353
|
+
expect: { result: "rejected", codes: ["unsupported_vcs"] },
|
|
354
|
+
provenance: SPEC,
|
|
355
|
+
build: () => {
|
|
356
|
+
const b = baseManifest();
|
|
357
|
+
(b.manifest.candidate as Json) = { ...CANDIDATE, vcs: "hg" };
|
|
358
|
+
return b;
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
id: "env-5-malformed-object-id",
|
|
363
|
+
title: "treeSha that is not a 40-hex git object id",
|
|
364
|
+
rules: ["ENV-5"],
|
|
365
|
+
expect: { result: "rejected", codes: ["invalid_object_id"] },
|
|
366
|
+
provenance: SPEC,
|
|
367
|
+
build: () => {
|
|
368
|
+
const b = baseManifest();
|
|
369
|
+
(b.manifest.candidate as Json) = { ...CANDIDATE, treeSha: "tree-a" };
|
|
370
|
+
return b;
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
id: "env-6-unknown-identity-version",
|
|
375
|
+
title: "Unknown deliverable identity version fails closed",
|
|
376
|
+
rules: ["ENV-6"],
|
|
377
|
+
expect: { result: "rejected", codes: ["unsupported_identity_version"] },
|
|
378
|
+
provenance: `${ATHENA} "an unknown identity version"`,
|
|
379
|
+
build: () => {
|
|
380
|
+
const b = baseManifest();
|
|
381
|
+
(b.manifest.candidate as Json) = {
|
|
382
|
+
...CANDIDATE,
|
|
383
|
+
deliverable: { digest: CANDIDATE.deliverable.digest, identity: "deliverable-tree/v0" },
|
|
384
|
+
};
|
|
385
|
+
return b;
|
|
386
|
+
},
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
id: "env-6-missing-identity",
|
|
390
|
+
title: "Candidate missing the deliverable identity block",
|
|
391
|
+
rules: ["ENV-6", "GEN-4"],
|
|
392
|
+
expect: { result: "rejected", codes: ["malformed_field"] },
|
|
393
|
+
provenance: `${ATHENA} "a missing deliverable identity"`,
|
|
394
|
+
build: () => {
|
|
395
|
+
const b = baseManifest();
|
|
396
|
+
const c = { ...CANDIDATE } as Json;
|
|
397
|
+
delete c.deliverable;
|
|
398
|
+
b.manifest.candidate = c;
|
|
399
|
+
return b;
|
|
400
|
+
},
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
id: "env-8-repository-required",
|
|
404
|
+
title: "provider-signed attestation without a repository identifier",
|
|
405
|
+
rules: ["ENV-8", "ENV-13"],
|
|
406
|
+
expect: { result: "rejected", codes: ["repository_required", "unsupported_attestation"] },
|
|
407
|
+
provenance: SPEC,
|
|
408
|
+
build: () => {
|
|
409
|
+
const b = baseManifest();
|
|
410
|
+
b.manifest.attestation = { level: "provider-signed", signatures: [] };
|
|
411
|
+
return b;
|
|
412
|
+
},
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
id: "env-9-final-pass-mismatch",
|
|
416
|
+
title: "runHistory's final entry names an earlier pass",
|
|
417
|
+
rules: ["ENV-9"],
|
|
418
|
+
expect: { result: "rejected", codes: ["run_history_final_mismatch"] },
|
|
419
|
+
provenance: `${ATHENA} "mutation sequence mismatched with the final pass"`,
|
|
420
|
+
build: () =>
|
|
421
|
+
baseManifest({
|
|
422
|
+
runHistory: [{ preparedTreeSha: CANDIDATE.treeSha, evaluatedInPassId: "pass-before" }],
|
|
423
|
+
}),
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
id: "env-9-final-tree-mismatch",
|
|
427
|
+
title: "runHistory's final entry names an earlier tree",
|
|
428
|
+
rules: ["ENV-9"],
|
|
429
|
+
expect: { result: "rejected", codes: ["run_history_final_mismatch"] },
|
|
430
|
+
provenance: `${ATHENA} "mutation sequence mismatched with the final candidate"`,
|
|
431
|
+
build: () =>
|
|
432
|
+
baseManifest({
|
|
433
|
+
runHistory: [{ preparedTreeSha: oid("tree-before"), evaluatedInPassId: "pass-2" }],
|
|
434
|
+
}),
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
id: "env-9-empty-run-history",
|
|
438
|
+
title: "Empty runHistory",
|
|
439
|
+
rules: ["ENV-9", "RG-9"],
|
|
440
|
+
expect: { result: "rejected", codes: ["run_history_final_mismatch", "iteration_count_mismatch"] },
|
|
441
|
+
provenance: TIGHTENED,
|
|
442
|
+
build: () => baseManifest({ runHistory: [], telemetry: { iterationCount: 1 } }),
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
id: "env-10-artifact-traversal",
|
|
446
|
+
title: "Artifact path traversing outside the run root",
|
|
447
|
+
rules: ["ENV-10"],
|
|
448
|
+
expect: { result: "rejected", codes: ["artifact_path_invalid"] },
|
|
449
|
+
provenance: `${ATHENA} "reviewer artifact path that traverses outside the run"`,
|
|
450
|
+
build: () => {
|
|
451
|
+
const b = baseManifest({ reviewers: ["correctness"] });
|
|
452
|
+
(b.manifest.artifacts as Json[])[0].path = "../outside.json";
|
|
453
|
+
b.files["../outside.json"] = approval("correctness");
|
|
454
|
+
return b;
|
|
455
|
+
},
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
id: "env-10-artifact-duplicate",
|
|
459
|
+
title: "Duplicate artifact path entries",
|
|
460
|
+
rules: ["ENV-10"],
|
|
461
|
+
expect: { result: "rejected", codes: ["artifact_path_duplicate"] },
|
|
462
|
+
provenance: `${ATHENA} "rejects a duplicate artifact entry"`,
|
|
463
|
+
build: () => {
|
|
464
|
+
const b = baseManifest({ reviewers: ["correctness"] });
|
|
465
|
+
const first = (b.manifest.artifacts as Json[])[0];
|
|
466
|
+
(b.manifest.artifacts as Json[]).push({ ...first });
|
|
467
|
+
return b;
|
|
468
|
+
},
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
id: "env-10-artifact-missing-file",
|
|
472
|
+
title: "Artifact entry whose file does not exist in the run root",
|
|
473
|
+
rules: ["ENV-10", "ENV-11"],
|
|
474
|
+
expect: { result: "rejected", codes: ["artifact_digest_mismatch"] },
|
|
475
|
+
provenance: `${ATHENA} "rejects a missing artifact entry"`,
|
|
476
|
+
build: () => {
|
|
477
|
+
const b = baseManifest({ reviewers: ["correctness"] });
|
|
478
|
+
(b.manifest.artifacts as Json[]).push({
|
|
479
|
+
path: "reviewers/missing.json",
|
|
480
|
+
sha256: digest64("missing"),
|
|
481
|
+
role: "reviewer-approval",
|
|
482
|
+
});
|
|
483
|
+
return b;
|
|
484
|
+
},
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
id: "env-11-artifact-digest-mismatch",
|
|
488
|
+
title: "Artifact digest that does not match the file bytes",
|
|
489
|
+
rules: ["ENV-11"],
|
|
490
|
+
expect: { result: "rejected", codes: ["artifact_digest_mismatch"] },
|
|
491
|
+
provenance: SPEC,
|
|
492
|
+
build: () => {
|
|
493
|
+
const b = baseManifest({ reviewers: ["correctness"] });
|
|
494
|
+
(b.manifest.artifacts as Json[])[0].sha256 = digest64("tampered");
|
|
495
|
+
return b;
|
|
496
|
+
},
|
|
497
|
+
},
|
|
498
|
+
{
|
|
499
|
+
id: "env-12-unknown-attestation-level",
|
|
500
|
+
title: "Unknown attestation level",
|
|
501
|
+
rules: ["ENV-12"],
|
|
502
|
+
expect: { result: "rejected", codes: ["unsupported_attestation"] },
|
|
503
|
+
provenance: SPEC,
|
|
504
|
+
build: () => {
|
|
505
|
+
const b = baseManifest();
|
|
506
|
+
b.manifest.attestation = { level: "notarized", signatures: [] };
|
|
507
|
+
return b;
|
|
508
|
+
},
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
id: "env-13-nonempty-signatures",
|
|
512
|
+
title: "Non-empty signatures array before a signing profile exists",
|
|
513
|
+
rules: ["ENV-13"],
|
|
514
|
+
expect: { result: "rejected", codes: ["unsupported_attestation"] },
|
|
515
|
+
provenance: SPEC,
|
|
516
|
+
build: () => {
|
|
517
|
+
const b = baseManifest();
|
|
518
|
+
b.manifest.attestation = { level: "self", signatures: [{ signer: "x" }] };
|
|
519
|
+
return b;
|
|
520
|
+
},
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
id: "env-14-no-claims",
|
|
524
|
+
title: "Empty claims array",
|
|
525
|
+
rules: ["ENV-14"],
|
|
526
|
+
expect: { result: "rejected", codes: ["no_claims"] },
|
|
527
|
+
provenance: SPEC,
|
|
528
|
+
build: () => baseManifest({ claims: [] }),
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
id: "env-14-duplicate-claim",
|
|
532
|
+
title: "Two claims for the same obligation",
|
|
533
|
+
rules: ["ENV-14"],
|
|
534
|
+
expect: { result: "rejected", codes: ["duplicate_claim"] },
|
|
535
|
+
provenance: SPEC,
|
|
536
|
+
build: () => {
|
|
537
|
+
const b = baseManifest();
|
|
538
|
+
const claim = (b.manifest.claims as Json[])[0];
|
|
539
|
+
(b.manifest.claims as Json[]).push(JSON.parse(JSON.stringify(claim)));
|
|
540
|
+
return b;
|
|
541
|
+
},
|
|
542
|
+
},
|
|
543
|
+
{
|
|
544
|
+
id: "env-14-unconfigured-obligation",
|
|
545
|
+
title: "Claim for an obligation the repository has not configured",
|
|
546
|
+
rules: ["ENV-14"],
|
|
547
|
+
expect: { result: "rejected", codes: ["obligation_not_configured"] },
|
|
548
|
+
provenance: SPEC,
|
|
549
|
+
build: () => {
|
|
550
|
+
const b = baseManifest();
|
|
551
|
+
((b.manifest.claims as Json[])[0] as Json).obligation = "qa.exercised";
|
|
552
|
+
return b;
|
|
553
|
+
},
|
|
554
|
+
},
|
|
555
|
+
{
|
|
556
|
+
id: "env-14-unsupported-payload-spec",
|
|
557
|
+
title: "Payload spec version the repository does not accept",
|
|
558
|
+
rules: ["ENV-14"],
|
|
559
|
+
expect: { result: "rejected", codes: ["unsupported_payload_spec"] },
|
|
560
|
+
provenance: SPEC,
|
|
561
|
+
build: () => {
|
|
562
|
+
const b = baseManifest();
|
|
563
|
+
((b.manifest.claims as Json[])[0] as Json).payloadSpec = "review.green/0";
|
|
564
|
+
return b;
|
|
565
|
+
},
|
|
566
|
+
},
|
|
567
|
+
|
|
568
|
+
// ---- SUB ----
|
|
569
|
+
...(
|
|
570
|
+
[
|
|
571
|
+
["deliverable-changed", "deliverable", { deliverable: { digest: digest64("deliverable-after"), identity: IDENTITY } }],
|
|
572
|
+
["raw-tree-changed", "raw tree", { treeSha: oid("tree-after") }],
|
|
573
|
+
["base-tip-moved", "base tip", { base: { ...CANDIDATE.base, tipSha: oid("base-b") } }],
|
|
574
|
+
["merge-base-moved", "merge base", { base: { ...CANDIDATE.base, mergeBaseSha: oid("merge-base-b") } }],
|
|
575
|
+
] as Array<[string, string, Json]>
|
|
576
|
+
).map(
|
|
577
|
+
([slug, label, over]): Vector => ({
|
|
578
|
+
id: `sub-1-${slug}`,
|
|
579
|
+
title: `Current candidate no longer matches: ${label} changed after review`,
|
|
580
|
+
rules: ["SUB-1"],
|
|
581
|
+
expect: { result: "rejected", codes: ["candidate_mismatch"] },
|
|
582
|
+
provenance: `${ATHENA} "candidate no longer matches" / "stays strict on the raw tree"`,
|
|
583
|
+
environment: { currentCandidate: { ...CANDIDATE, ...over } },
|
|
584
|
+
build: () => baseManifest(),
|
|
585
|
+
}),
|
|
586
|
+
),
|
|
587
|
+
{
|
|
588
|
+
id: "sub-2-unprepared",
|
|
589
|
+
title: "Submission without a current preparation (dirty or unprepared tree)",
|
|
590
|
+
rules: ["SUB-2"],
|
|
591
|
+
expect: { result: "rejected", codes: ["candidate_unprepared"] },
|
|
592
|
+
provenance: `${ATHENA} "refuses to hand out a review context without a current preparation receipt"`,
|
|
593
|
+
environment: { prepared: false },
|
|
594
|
+
build: () => baseManifest(),
|
|
595
|
+
},
|
|
596
|
+
{
|
|
597
|
+
id: "sub-3-manifest-outside-run-root",
|
|
598
|
+
title: "Manifest copied outside the recorder-allocated run root",
|
|
599
|
+
rules: ["SUB-3"],
|
|
600
|
+
expect: { result: "rejected", codes: ["manifest_outside_run_root"] },
|
|
601
|
+
provenance: `${ATHENA} "rejects copied manifests" / "exact final-manifest location"`,
|
|
602
|
+
environment: { manifestLocation: "outside-run-root" },
|
|
603
|
+
build: () => baseManifest(),
|
|
604
|
+
},
|
|
605
|
+
{
|
|
606
|
+
id: "sub-4-record-conflict",
|
|
607
|
+
title: "Resubmission with identical record identity but different content",
|
|
608
|
+
rules: ["SUB-4"],
|
|
609
|
+
expect: { result: "rejected", codes: ["record_conflict"] },
|
|
610
|
+
provenance: `${ATHENA} conflicting existing obligation record`,
|
|
611
|
+
build: () => {
|
|
612
|
+
const first = baseManifest();
|
|
613
|
+
const second = baseManifest({
|
|
614
|
+
findings: [
|
|
615
|
+
{ id: "f-late", severity: "P3", scope: "in_contract", actionable: true, blocking: false, disposition: "resolved" },
|
|
616
|
+
],
|
|
617
|
+
});
|
|
618
|
+
return {
|
|
619
|
+
manifest: second.manifest,
|
|
620
|
+
files: second.files,
|
|
621
|
+
extra: { submitFirst: first.manifest, note: "Submit extra.submitFirst (accepted), then the vector manifest: same provider/run/pass/candidate, different content." },
|
|
622
|
+
};
|
|
623
|
+
},
|
|
624
|
+
},
|
|
625
|
+
|
|
626
|
+
// ---- RG ----
|
|
627
|
+
{
|
|
628
|
+
id: "rg-1-verdict-not-green",
|
|
629
|
+
title: "Non-green verdict",
|
|
630
|
+
rules: ["RG-1"],
|
|
631
|
+
expect: { result: "rejected", codes: ["verdict_not_green"] },
|
|
632
|
+
provenance: `${ATHENA} "rejects non-green verdict"`,
|
|
633
|
+
build: () => baseManifest({ payload: { verdict: "not_green" } }),
|
|
634
|
+
},
|
|
635
|
+
{
|
|
636
|
+
id: "rg-1-not-finalized",
|
|
637
|
+
title: "Unfinalized manifest",
|
|
638
|
+
rules: ["RG-1"],
|
|
639
|
+
expect: { result: "rejected", codes: ["not_finalized"] },
|
|
640
|
+
provenance: `${ATHENA} "rejects unfinalized manifest"`,
|
|
641
|
+
build: () => baseManifest({ payload: { finalized: false } }),
|
|
642
|
+
},
|
|
643
|
+
{
|
|
644
|
+
id: "rg-1-edited-after-final-pass",
|
|
645
|
+
title: "Post-final-pass edits admitted by the provider",
|
|
646
|
+
rules: ["RG-1"],
|
|
647
|
+
expect: { result: "rejected", codes: ["edited_after_final_pass"] },
|
|
648
|
+
provenance: `${ATHENA} "rejects post-pass edits"`,
|
|
649
|
+
build: () => baseManifest({ payload: { editedAfterFinalPass: true } }),
|
|
650
|
+
},
|
|
651
|
+
{
|
|
652
|
+
id: "rg-2-duplicate-selected",
|
|
653
|
+
title: "Duplicate reviewer in selected",
|
|
654
|
+
rules: ["RG-2"],
|
|
655
|
+
expect: { result: "rejected", codes: ["reviewer_set_invalid"] },
|
|
656
|
+
provenance: `${ATHENA} "duplicate selected reviewer"`,
|
|
657
|
+
build: () => {
|
|
658
|
+
const b = baseManifest({ reviewers: ["correctness"] });
|
|
659
|
+
const p = (b.manifest.claims as Json[])[0].payload as Json;
|
|
660
|
+
(p.reviewers as Json).selected = ["correctness", "correctness"];
|
|
661
|
+
return b;
|
|
662
|
+
},
|
|
663
|
+
},
|
|
664
|
+
{
|
|
665
|
+
id: "rg-3-completed-missing",
|
|
666
|
+
title: "Selected reviewer missing from completed",
|
|
667
|
+
rules: ["RG-3"],
|
|
668
|
+
expect: { result: "rejected", codes: ["reviewer_set_incomplete"] },
|
|
669
|
+
provenance: `${ATHENA} "missing selected reviewer"`,
|
|
670
|
+
build: () => {
|
|
671
|
+
const b = baseManifest({ reviewers: ["correctness"] });
|
|
672
|
+
const p = (b.manifest.claims as Json[])[0].payload as Json;
|
|
673
|
+
(p.reviewers as Json).completed = [];
|
|
674
|
+
return b;
|
|
675
|
+
},
|
|
676
|
+
},
|
|
677
|
+
{
|
|
678
|
+
id: "rg-3-completed-unrelated",
|
|
679
|
+
title: "Completed reviewer never selected",
|
|
680
|
+
rules: ["RG-3"],
|
|
681
|
+
expect: { result: "rejected", codes: ["reviewer_set_incomplete"] },
|
|
682
|
+
provenance: `${ATHENA} "unrelated completed reviewer"`,
|
|
683
|
+
build: () => {
|
|
684
|
+
const b = baseManifest({ reviewers: ["correctness"] });
|
|
685
|
+
const p = (b.manifest.claims as Json[])[0].payload as Json;
|
|
686
|
+
(p.reviewers as Json).completed = ["correctness", "security"];
|
|
687
|
+
return b;
|
|
688
|
+
},
|
|
689
|
+
},
|
|
690
|
+
{
|
|
691
|
+
id: "rg-3-failed-reviewer",
|
|
692
|
+
title: "A failed reviewer in a green manifest",
|
|
693
|
+
rules: ["RG-3"],
|
|
694
|
+
expect: { result: "rejected", codes: ["reviewer_set_incomplete"] },
|
|
695
|
+
provenance: `${ATHENA} "rejects failed reviewers"`,
|
|
696
|
+
build: () => {
|
|
697
|
+
const b = baseManifest({ reviewers: ["correctness"] });
|
|
698
|
+
const p = (b.manifest.claims as Json[])[0].payload as Json;
|
|
699
|
+
(p.reviewers as Json).failed = ["correctness"];
|
|
700
|
+
return b;
|
|
701
|
+
},
|
|
702
|
+
},
|
|
703
|
+
{
|
|
704
|
+
id: "rg-3-timed-out-reviewer",
|
|
705
|
+
title: "A timed-out reviewer in a green manifest",
|
|
706
|
+
rules: ["RG-3"],
|
|
707
|
+
expect: { result: "rejected", codes: ["reviewer_set_incomplete"] },
|
|
708
|
+
provenance: `${ATHENA} "rejects timed out reviewers"`,
|
|
709
|
+
build: () => {
|
|
710
|
+
const b = baseManifest({ reviewers: ["correctness"] });
|
|
711
|
+
const p = (b.manifest.claims as Json[])[0].payload as Json;
|
|
712
|
+
(p.reviewers as Json).timedOut = ["correctness"];
|
|
713
|
+
return b;
|
|
714
|
+
},
|
|
715
|
+
},
|
|
716
|
+
{
|
|
717
|
+
id: "rg-4-approval-missing",
|
|
718
|
+
title: "Selected reviewer with no reviewer-approval artifact",
|
|
719
|
+
rules: ["RG-4"],
|
|
720
|
+
expect: { result: "rejected", codes: ["approval_missing"] },
|
|
721
|
+
provenance: `${ATHENA} "rejects copied manifests and missing reviewer artifacts"`,
|
|
722
|
+
build: () => {
|
|
723
|
+
const b = baseManifest({ reviewers: ["correctness", "security"] });
|
|
724
|
+
b.manifest.artifacts = (b.manifest.artifacts as Json[]).slice(0, 1);
|
|
725
|
+
delete b.files["reviewers/security.json"];
|
|
726
|
+
return b;
|
|
727
|
+
},
|
|
728
|
+
},
|
|
729
|
+
{
|
|
730
|
+
id: "rg-4-approval-extra",
|
|
731
|
+
title: "More reviewer-approval artifacts than selected reviewers",
|
|
732
|
+
rules: ["RG-4"],
|
|
733
|
+
expect: { result: "rejected", codes: ["approval_mismatch"] },
|
|
734
|
+
provenance: `${ATHENA} "exactly one reviewer artifact"`,
|
|
735
|
+
build: () => {
|
|
736
|
+
const b = baseManifest({ reviewers: ["correctness"] });
|
|
737
|
+
const extra = approval("security");
|
|
738
|
+
b.files["reviewers/security.json"] = extra;
|
|
739
|
+
(b.manifest.artifacts as Json[]).push({
|
|
740
|
+
path: "reviewers/security.json",
|
|
741
|
+
sha256: sha256(extra),
|
|
742
|
+
role: "reviewer-approval",
|
|
743
|
+
});
|
|
744
|
+
return b;
|
|
745
|
+
},
|
|
746
|
+
},
|
|
747
|
+
...(
|
|
748
|
+
[
|
|
749
|
+
["wrong-run", { provider: { id: PROVIDER, runId: "r-other", finalPassId: "pass-2" } }],
|
|
750
|
+
["wrong-pass", { provider: { id: PROVIDER, runId: "r-conformance-01", finalPassId: "pass-1" } }],
|
|
751
|
+
["wrong-workspace", { workspaceId: "w-other" }],
|
|
752
|
+
["wrong-candidate", { candidate: { ...CANDIDATE, treeSha: oid("tree-other") } }],
|
|
753
|
+
["wrong-reviewer", { reviewerId: "security" }],
|
|
754
|
+
["not-approved", { result: "advisory" }],
|
|
755
|
+
["wrong-provider", { provider: { id: "example.second-provider", runId: "r-conformance-01", finalPassId: "pass-2" } }],
|
|
756
|
+
] as Array<[string, Json]>
|
|
757
|
+
).map(
|
|
758
|
+
([slug, over]): Vector => ({
|
|
759
|
+
id: `rg-4-approval-${slug}`,
|
|
760
|
+
title: `Reviewer approval stamp with ${slug.replace(/-/g, " ")}`,
|
|
761
|
+
rules: ["RG-4"],
|
|
762
|
+
expect: { result: "rejected", codes: ["approval_mismatch"] },
|
|
763
|
+
provenance: `${ATHENA} "rejects reviewer artifact with ..."`,
|
|
764
|
+
build: () => {
|
|
765
|
+
const b = baseManifest({ reviewers: ["correctness"] });
|
|
766
|
+
const content = approval("correctness", over);
|
|
767
|
+
b.files["reviewers/correctness.json"] = content;
|
|
768
|
+
(b.manifest.artifacts as Json[])[0].sha256 = sha256(content);
|
|
769
|
+
return b;
|
|
770
|
+
},
|
|
771
|
+
}),
|
|
772
|
+
),
|
|
773
|
+
{
|
|
774
|
+
id: "rg-4-approval-malformed",
|
|
775
|
+
title: "Reviewer approval artifact that is not JSON",
|
|
776
|
+
rules: ["RG-4"],
|
|
777
|
+
expect: { result: "rejected", codes: ["approval_mismatch"] },
|
|
778
|
+
provenance: `${ATHENA} "rejects malformed and unrelated reviewer artifacts"`,
|
|
779
|
+
build: () => {
|
|
780
|
+
const b = baseManifest({ reviewers: ["correctness"] });
|
|
781
|
+
b.files["reviewers/correctness.json"] = "not json\n";
|
|
782
|
+
(b.manifest.artifacts as Json[])[0].sha256 = sha256("not json\n");
|
|
783
|
+
return b;
|
|
784
|
+
},
|
|
785
|
+
},
|
|
786
|
+
...(
|
|
787
|
+
[
|
|
788
|
+
["unknown-severity", { severity: "P9" }],
|
|
789
|
+
["unknown-scope", { scope: "someday" }],
|
|
790
|
+
["unknown-disposition", { disposition: "parked" }],
|
|
791
|
+
] as Array<[string, Json]>
|
|
792
|
+
).map(
|
|
793
|
+
([slug, over]): Vector => ({
|
|
794
|
+
id: `rg-5-${slug}`,
|
|
795
|
+
title: `Finding with ${slug.replace(/-/g, " ")}`,
|
|
796
|
+
rules: ["RG-5"],
|
|
797
|
+
expect: { result: "rejected", codes: ["finding_invalid"] },
|
|
798
|
+
provenance: `${ATHENA} "rejects a finding with ..."`,
|
|
799
|
+
build: () =>
|
|
800
|
+
baseManifest({
|
|
801
|
+
findings: [{ id: "f-1", severity: "P2", scope: "in_contract", actionable: true, blocking: false, disposition: "resolved", ...over }],
|
|
802
|
+
telemetry: { findingCounts: { P0: 0, P1: 0, P2: 1, P3: 0 } },
|
|
803
|
+
}),
|
|
804
|
+
}),
|
|
805
|
+
),
|
|
806
|
+
{
|
|
807
|
+
id: "rg-5-duplicate-finding-id",
|
|
808
|
+
title: "Two findings sharing an id",
|
|
809
|
+
rules: ["RG-5"],
|
|
810
|
+
expect: { result: "rejected", codes: ["finding_invalid"] },
|
|
811
|
+
provenance: SPEC,
|
|
812
|
+
build: () =>
|
|
813
|
+
baseManifest({
|
|
814
|
+
findings: [
|
|
815
|
+
{ id: "f-1", severity: "P3", scope: "in_contract", actionable: false, blocking: false, disposition: "advisory" },
|
|
816
|
+
{ id: "f-1", severity: "P3", scope: "adjacent", actionable: false, blocking: false, disposition: "advisory" },
|
|
817
|
+
],
|
|
818
|
+
}),
|
|
819
|
+
},
|
|
820
|
+
{
|
|
821
|
+
id: "rg-6-blocking-finding",
|
|
822
|
+
title: "A blocking finding in a green manifest",
|
|
823
|
+
rules: ["RG-6"],
|
|
824
|
+
expect: { result: "rejected", codes: ["blocking_finding_present"] },
|
|
825
|
+
provenance: `${ATHENA} "rejects blocking findings"`,
|
|
826
|
+
build: () =>
|
|
827
|
+
baseManifest({
|
|
828
|
+
findings: [{ id: "f-1", severity: "P1", scope: "in_contract", actionable: true, blocking: true, disposition: "resolved" }],
|
|
829
|
+
}),
|
|
830
|
+
},
|
|
831
|
+
...(["unresolved", "ignored"] as const).map(
|
|
832
|
+
(disposition): Vector => ({
|
|
833
|
+
id: `rg-6-actionable-${disposition}`,
|
|
834
|
+
title: `Actionable finding left ${disposition} despite green verdict`,
|
|
835
|
+
rules: ["RG-6"],
|
|
836
|
+
expect: { result: "rejected", codes: ["actionable_unresolved"] },
|
|
837
|
+
provenance: `${ATHENA} "rejects an ${disposition} actionable finding despite zero summary counts"`,
|
|
838
|
+
build: () =>
|
|
839
|
+
baseManifest({
|
|
840
|
+
findings: [{ id: "f-1", severity: "P2", scope: "in_contract", actionable: true, blocking: false, disposition }],
|
|
841
|
+
}),
|
|
842
|
+
}),
|
|
843
|
+
),
|
|
844
|
+
...(
|
|
845
|
+
[
|
|
846
|
+
["p0", { severity: "P0" }],
|
|
847
|
+
["p1", { severity: "P1" }],
|
|
848
|
+
["in-contract", { scope: "in_contract" }],
|
|
849
|
+
["adjacent", { scope: "adjacent" }],
|
|
850
|
+
["placeholder-issue-id", { deferredIssueId: "TODO" }],
|
|
851
|
+
["lowercase-issue-id", { deferredIssueId: "ex-1300" }],
|
|
852
|
+
["missing-issue-id", { deferredIssueId: undefined }],
|
|
853
|
+
["blocking", { blocking: true }],
|
|
854
|
+
["non-actionable", { actionable: false }],
|
|
855
|
+
] as Array<[string, Json]>
|
|
856
|
+
).map(
|
|
857
|
+
([slug, over]): Vector => ({
|
|
858
|
+
id: `rg-7-defer-${slug}`,
|
|
859
|
+
title: `Illegal deferral: ${slug.replace(/-/g, " ")}`,
|
|
860
|
+
rules: ["RG-7"],
|
|
861
|
+
expect: { result: "rejected", codes: ["illegal_deferral"] },
|
|
862
|
+
provenance: `${ATHENA} "refuses to defer ... machine-checked rather than trusted"`,
|
|
863
|
+
build: () => {
|
|
864
|
+
const f = { ...DEFERRED_OK, ...over } as Json;
|
|
865
|
+
for (const [k, v] of Object.entries(over)) if (v === undefined) delete f[k];
|
|
866
|
+
return baseManifest({ findings: [f] });
|
|
867
|
+
},
|
|
868
|
+
}),
|
|
869
|
+
),
|
|
870
|
+
{
|
|
871
|
+
id: "rg-7-issue-id-on-resolved",
|
|
872
|
+
title: "deferredIssueId present on a non-deferred finding",
|
|
873
|
+
rules: ["RG-7"],
|
|
874
|
+
expect: { result: "rejected", codes: ["illegal_deferral"] },
|
|
875
|
+
provenance: SPEC,
|
|
876
|
+
build: () =>
|
|
877
|
+
baseManifest({
|
|
878
|
+
findings: [{ id: "f-1", severity: "P2", scope: "in_contract", actionable: true, blocking: false, disposition: "resolved", deferredIssueId: "EX-1" }],
|
|
879
|
+
telemetry: { findingCounts: { P0: 0, P1: 0, P2: 1, P3: 0 } },
|
|
880
|
+
}),
|
|
881
|
+
},
|
|
882
|
+
{
|
|
883
|
+
id: "rg-8-counts-contradict-findings",
|
|
884
|
+
title: "findingCounts claiming zero over findings with real severities",
|
|
885
|
+
rules: ["RG-8"],
|
|
886
|
+
expect: { result: "rejected", codes: ["telemetry_mismatch"] },
|
|
887
|
+
provenance: `${ATHENA} "rejects telemetry claiming finding counts its own findings contradict"`,
|
|
888
|
+
build: () =>
|
|
889
|
+
baseManifest({
|
|
890
|
+
findings: [DEFERRED_OK],
|
|
891
|
+
telemetry: { findingCounts: { P0: 0, P1: 0, P2: 0, P3: 0 } },
|
|
892
|
+
}),
|
|
893
|
+
},
|
|
894
|
+
{
|
|
895
|
+
id: "rg-8-deferral-count-disagrees",
|
|
896
|
+
title: "Deferral count disagreeing with the findings",
|
|
897
|
+
rules: ["RG-8"],
|
|
898
|
+
expect: { result: "rejected", codes: ["telemetry_mismatch"] },
|
|
899
|
+
provenance: `${ATHENA} "deferral count that disagrees with the findings"`,
|
|
900
|
+
build: () =>
|
|
901
|
+
baseManifest({
|
|
902
|
+
findings: [DEFERRED_OK],
|
|
903
|
+
telemetry: { deferredExpansionCount: 0, deferredIssueIds: [] },
|
|
904
|
+
}),
|
|
905
|
+
},
|
|
906
|
+
{
|
|
907
|
+
id: "rg-8-deferral-ids-disagree",
|
|
908
|
+
title: "Deferred issue ids disagreeing with the findings",
|
|
909
|
+
rules: ["RG-8"],
|
|
910
|
+
expect: { result: "rejected", codes: ["telemetry_mismatch"] },
|
|
911
|
+
provenance: `${ATHENA} "issue ids that disagree with the findings"`,
|
|
912
|
+
build: () =>
|
|
913
|
+
baseManifest({
|
|
914
|
+
findings: [DEFERRED_OK],
|
|
915
|
+
telemetry: { deferredIssueIds: ["EX-9999"] },
|
|
916
|
+
}),
|
|
917
|
+
},
|
|
918
|
+
{
|
|
919
|
+
id: "rg-9-iteration-count-mismatch",
|
|
920
|
+
title: "iterationCount disagreeing with runHistory length",
|
|
921
|
+
rules: ["RG-9"],
|
|
922
|
+
expect: { result: "rejected", codes: ["iteration_count_mismatch"] },
|
|
923
|
+
provenance: TIGHTENED,
|
|
924
|
+
build: () => baseManifest({ telemetry: { iterationCount: 7 } }),
|
|
925
|
+
},
|
|
926
|
+
...(
|
|
927
|
+
[
|
|
928
|
+
["missing-unit", { total: 100, reportedBy: "x" }, ["invalid_cost"]],
|
|
929
|
+
["empty-unit", { unit: "", total: 100, reportedBy: "x" }, ["invalid_cost"]],
|
|
930
|
+
["negative-total", { unit: "tokens", total: -1, reportedBy: "x" }, ["invalid_cost"]],
|
|
931
|
+
["null-total", { unit: "tokens", total: null, reportedBy: "x" }, ["invalid_cost"]],
|
|
932
|
+
["by-reviewer-exceeds-total", { unit: "tokens", total: 100, reportedBy: "x", byReviewer: { correctness: 80, security: 40 } }, ["invalid_cost"]],
|
|
933
|
+
["negative-by-reviewer", { unit: "tokens", total: 100, reportedBy: "x", byReviewer: { correctness: -1 } }, ["invalid_cost"]],
|
|
934
|
+
["empty-reported-by", { unit: "tokens", total: 100, reportedBy: "" }, ["invalid_cost"]],
|
|
935
|
+
["unknown-reviewer-in-breakdown", { unit: "tokens", total: 100, reportedBy: "x", byReviewer: { adversarial: 10 } }, ["invalid_cost"]],
|
|
936
|
+
] as Array<[string, Json, string[]]>
|
|
937
|
+
).map(
|
|
938
|
+
([slug, cost, codes]): Vector => ({
|
|
939
|
+
id: `rg-10-cost-${slug}`,
|
|
940
|
+
title: `Cost with ${slug.replace(/-/g, " ")}`,
|
|
941
|
+
rules: ["RG-10"],
|
|
942
|
+
expect: { result: "rejected", codes },
|
|
943
|
+
provenance:
|
|
944
|
+
slug === "unknown-reviewer-in-breakdown"
|
|
945
|
+
? SPEC
|
|
946
|
+
: `${ATHENA} "rejects a review cost with a ..."`,
|
|
947
|
+
build: () => {
|
|
948
|
+
const c = { ...cost } as Json;
|
|
949
|
+
if (c.total === null) c.total = null;
|
|
950
|
+
return baseManifest({ reviewers: ["correctness", "security"], telemetry: { cost: c } });
|
|
951
|
+
},
|
|
952
|
+
}),
|
|
953
|
+
),
|
|
954
|
+
];
|
|
955
|
+
|
|
956
|
+
// ── Emit ───────────────────────────────────────────────────────────────────
|
|
957
|
+
|
|
958
|
+
rmSync(OUT, { recursive: true, force: true });
|
|
959
|
+
for (const d of ["vectors/accept", "vectors/reject", "context"])
|
|
960
|
+
mkdirSync(path.join(OUT, d), { recursive: true });
|
|
961
|
+
|
|
962
|
+
const index: Json[] = [];
|
|
963
|
+
const seen = new Set<string>();
|
|
964
|
+
for (const v of vectors) {
|
|
965
|
+
if (seen.has(v.id)) throw new Error(`duplicate vector id: ${v.id}`);
|
|
966
|
+
seen.add(v.id);
|
|
967
|
+
const built = v.build();
|
|
968
|
+
const doc = {
|
|
969
|
+
vectorVersion: 1,
|
|
970
|
+
id: v.id,
|
|
971
|
+
title: v.title,
|
|
972
|
+
rules: v.rules,
|
|
973
|
+
provenance: v.provenance,
|
|
974
|
+
expect: v.expect,
|
|
975
|
+
...(v.environment ? { environment: v.environment } : {}),
|
|
976
|
+
...(built.extra ? { extra: built.extra } : {}),
|
|
977
|
+
artifacts: built.files,
|
|
978
|
+
manifest: built.manifest,
|
|
979
|
+
};
|
|
980
|
+
const dir = v.expect.result === "accepted" ? "accept" : "reject";
|
|
981
|
+
const file = `vectors/${dir}/${v.id}.json`;
|
|
982
|
+
writeFileSync(path.join(OUT, file), JSON.stringify(doc, null, 2) + "\n");
|
|
983
|
+
index.push({ id: v.id, file, title: v.title, rules: v.rules, expect: v.expect });
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
writeFileSync(
|
|
987
|
+
path.join(OUT, "context/repo-config.json"),
|
|
988
|
+
JSON.stringify(REPO_CONFIG, null, 2) + "\n",
|
|
989
|
+
);
|
|
990
|
+
writeFileSync(
|
|
991
|
+
path.join(OUT, "context/environment.json"),
|
|
992
|
+
JSON.stringify(ENVIRONMENT, null, 2) + "\n",
|
|
993
|
+
);
|
|
994
|
+
writeFileSync(
|
|
995
|
+
path.join(OUT, "kit.json"),
|
|
996
|
+
JSON.stringify(
|
|
997
|
+
{
|
|
998
|
+
kit: "delivery-evidence-conformance/1",
|
|
999
|
+
spec: "delivery-evidence/1",
|
|
1000
|
+
payloadSpecs: [PAYLOAD_SPEC],
|
|
1001
|
+
counts: {
|
|
1002
|
+
total: index.length,
|
|
1003
|
+
accept: index.filter((i) => (i.expect as Json).result === "accepted").length,
|
|
1004
|
+
reject: index.filter((i) => (i.expect as Json).result === "rejected").length,
|
|
1005
|
+
},
|
|
1006
|
+
vectors: index,
|
|
1007
|
+
},
|
|
1008
|
+
null,
|
|
1009
|
+
2,
|
|
1010
|
+
) + "\n",
|
|
1011
|
+
);
|
|
1012
|
+
|
|
1013
|
+
console.log(`wrote ${index.length} vectors to ${OUT}`);
|