@cleocode/contracts 2026.5.121 → 2026.5.122

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 (45) hide show
  1. package/dist/__tests__/satisfies-atom.test.d.ts +24 -0
  2. package/dist/__tests__/satisfies-atom.test.d.ts.map +1 -0
  3. package/dist/__tests__/satisfies-atom.test.js +302 -0
  4. package/dist/__tests__/satisfies-atom.test.js.map +1 -0
  5. package/dist/__tests__/validator-types.test.d.ts +13 -0
  6. package/dist/__tests__/validator-types.test.d.ts.map +1 -0
  7. package/dist/__tests__/validator-types.test.js +293 -0
  8. package/dist/__tests__/validator-types.test.js.map +1 -0
  9. package/dist/config.d.ts +56 -0
  10. package/dist/config.d.ts.map +1 -1
  11. package/dist/data-accessor.d.ts +117 -0
  12. package/dist/data-accessor.d.ts.map +1 -1
  13. package/dist/data-accessor.js.map +1 -1
  14. package/dist/evidence-atom-schema.d.ts +91 -0
  15. package/dist/evidence-atom-schema.d.ts.map +1 -1
  16. package/dist/evidence-atom-schema.js +162 -1
  17. package/dist/evidence-atom-schema.js.map +1 -1
  18. package/dist/exit-codes.d.ts +41 -1
  19. package/dist/exit-codes.d.ts.map +1 -1
  20. package/dist/exit-codes.js +40 -0
  21. package/dist/exit-codes.js.map +1 -1
  22. package/dist/index.d.ts +7 -5
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +4 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/operations/tasks.d.ts +49 -0
  27. package/dist/operations/tasks.d.ts.map +1 -1
  28. package/dist/operations/tasks.js.map +1 -1
  29. package/dist/task.d.ts +38 -0
  30. package/dist/task.d.ts.map +1 -1
  31. package/dist/validator/index.d.ts +375 -0
  32. package/dist/validator/index.d.ts.map +1 -0
  33. package/dist/validator/index.js +162 -0
  34. package/dist/validator/index.js.map +1 -0
  35. package/package.json +2 -2
  36. package/src/__tests__/satisfies-atom.test.ts +363 -0
  37. package/src/__tests__/validator-types.test.ts +359 -0
  38. package/src/config.ts +58 -0
  39. package/src/data-accessor.ts +120 -0
  40. package/src/evidence-atom-schema.ts +188 -1
  41. package/src/exit-codes.ts +42 -0
  42. package/src/index.ts +37 -0
  43. package/src/operations/tasks.ts +50 -0
  44. package/src/task.ts +39 -0
  45. package/src/validator/index.ts +385 -0
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Tests for the ADR-079-r2 `satisfies:<task-id>#<ac-id>` evidence atom
3
+ * grammar (T10506).
4
+ *
5
+ * Coverage:
6
+ * - Schema-level: per-field regex validation (task-id, ac-uuid, ac-alias,
7
+ * version-pin) and discriminated-union acceptance.
8
+ * - Parser-level: full {@link parseEvidenceString} round-trips for both
9
+ * UUID and alias forms, mixed evidence strings, and the optional
10
+ * `@<version-pin>` suffix.
11
+ * - Malformed inputs: missing colon, missing hash, missing T-prefix,
12
+ * mixed-case UUID, non-UUID non-alias ac-id, malformed version-pin.
13
+ *
14
+ * This file covers PARSING ONLY per T10506 acceptance criteria. The 5-check
15
+ * validator semantics (target exists, target not terminal, AC exists, same-
16
+ * saga scope rule, alias drift detection) ship in T10507 and are tested
17
+ * separately in `packages/core/src/tasks/__tests__/satisfies-validator.test.ts`.
18
+ *
19
+ * @task T10506
20
+ * @saga T10377
21
+ * @adr ADR-079-r2
22
+ */
23
+ export {};
24
+ //# sourceMappingURL=satisfies-atom.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"satisfies-atom.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/satisfies-atom.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG"}
@@ -0,0 +1,302 @@
1
+ /**
2
+ * Tests for the ADR-079-r2 `satisfies:<task-id>#<ac-id>` evidence atom
3
+ * grammar (T10506).
4
+ *
5
+ * Coverage:
6
+ * - Schema-level: per-field regex validation (task-id, ac-uuid, ac-alias,
7
+ * version-pin) and discriminated-union acceptance.
8
+ * - Parser-level: full {@link parseEvidenceString} round-trips for both
9
+ * UUID and alias forms, mixed evidence strings, and the optional
10
+ * `@<version-pin>` suffix.
11
+ * - Malformed inputs: missing colon, missing hash, missing T-prefix,
12
+ * mixed-case UUID, non-UUID non-alias ac-id, malformed version-pin.
13
+ *
14
+ * This file covers PARSING ONLY per T10506 acceptance criteria. The 5-check
15
+ * validator semantics (target exists, target not terminal, AC exists, same-
16
+ * saga scope rule, alias drift detection) ship in T10507 and are tested
17
+ * separately in `packages/core/src/tasks/__tests__/satisfies-validator.test.ts`.
18
+ *
19
+ * @task T10506
20
+ * @saga T10377
21
+ * @adr ADR-079-r2
22
+ */
23
+ import { describe, expect, it } from 'vitest';
24
+ import { AC_ALIAS_REGEX, AC_UUID_REGEX, EvidenceAtomSchema, EvidenceParseError, parseEvidenceString, SATISFIES_TASK_ID_REGEX, SATISFIES_VERSION_PIN_REGEX, satisfiesAtomSchema, } from '../index.js';
25
+ // ─── Per-field regex parity (ADR-079-r2 §2.1 ABNF) ────────────────────────
26
+ describe('satisfies atom regexes (ADR-079-r2 §2.1)', () => {
27
+ describe('SATISFIES_TASK_ID_REGEX', () => {
28
+ it('accepts T<1-7 digits>', () => {
29
+ expect(SATISFIES_TASK_ID_REGEX.test('T1')).toBe(true);
30
+ expect(SATISFIES_TASK_ID_REGEX.test('T1234')).toBe(true);
31
+ expect(SATISFIES_TASK_ID_REGEX.test('T1234567')).toBe(true);
32
+ });
33
+ it('rejects T<8+ digits>', () => {
34
+ expect(SATISFIES_TASK_ID_REGEX.test('T12345678')).toBe(false);
35
+ });
36
+ it('rejects missing T prefix', () => {
37
+ expect(SATISFIES_TASK_ID_REGEX.test('1234')).toBe(false);
38
+ });
39
+ it('rejects lowercase t', () => {
40
+ expect(SATISFIES_TASK_ID_REGEX.test('t1234')).toBe(false);
41
+ });
42
+ it('rejects non-digit suffix', () => {
43
+ expect(SATISFIES_TASK_ID_REGEX.test('T12a')).toBe(false);
44
+ });
45
+ });
46
+ describe('AC_UUID_REGEX', () => {
47
+ it('accepts strict lowercase UUIDv4', () => {
48
+ expect(AC_UUID_REGEX.test('a1b2c3d4-5e6f-4890-abcd-ef1234567890')).toBe(true);
49
+ expect(AC_UUID_REGEX.test('00000000-0000-4000-8000-000000000000')).toBe(true);
50
+ });
51
+ it('rejects mixed-case', () => {
52
+ // Council-mandated strictness (ADR-079-r2 §2.2): "Validators MUST
53
+ // reject mixed-case to prevent silent dedupe failures."
54
+ expect(AC_UUID_REGEX.test('A1B2C3D4-5E6F-4890-ABCD-EF1234567890')).toBe(false);
55
+ });
56
+ it('rejects wrong version nibble (not 4)', () => {
57
+ expect(AC_UUID_REGEX.test('a1b2c3d4-5e6f-5890-abcd-ef1234567890')).toBe(false);
58
+ });
59
+ it('rejects wrong variant nibble (not 8/9/a/b)', () => {
60
+ expect(AC_UUID_REGEX.test('a1b2c3d4-5e6f-4890-cbcd-ef1234567890')).toBe(false);
61
+ });
62
+ it('rejects non-UUID strings', () => {
63
+ expect(AC_UUID_REGEX.test('not-a-uuid')).toBe(false);
64
+ expect(AC_UUID_REGEX.test('a1b2c3d45e6f4890abcdef1234567890')).toBe(false);
65
+ });
66
+ });
67
+ describe('AC_ALIAS_REGEX', () => {
68
+ it('accepts AC<1-4 digits>', () => {
69
+ expect(AC_ALIAS_REGEX.test('AC1')).toBe(true);
70
+ expect(AC_ALIAS_REGEX.test('AC9999')).toBe(true);
71
+ });
72
+ it('rejects AC<5+ digits>', () => {
73
+ expect(AC_ALIAS_REGEX.test('AC10000')).toBe(false);
74
+ });
75
+ it('rejects lowercase ac', () => {
76
+ expect(AC_ALIAS_REGEX.test('ac1')).toBe(false);
77
+ });
78
+ it('rejects bare integer', () => {
79
+ expect(AC_ALIAS_REGEX.test('1')).toBe(false);
80
+ });
81
+ });
82
+ describe('SATISFIES_VERSION_PIN_REGEX', () => {
83
+ it('accepts exactly 14 digits', () => {
84
+ expect(SATISFIES_VERSION_PIN_REGEX.test('20260524223045')).toBe(true);
85
+ });
86
+ it('rejects fewer than 14 digits', () => {
87
+ expect(SATISFIES_VERSION_PIN_REGEX.test('2026052422304')).toBe(false);
88
+ });
89
+ it('rejects more than 14 digits', () => {
90
+ expect(SATISFIES_VERSION_PIN_REGEX.test('202605242230451')).toBe(false);
91
+ });
92
+ it('rejects non-digit characters', () => {
93
+ expect(SATISFIES_VERSION_PIN_REGEX.test('2026-05-24T22:30')).toBe(false);
94
+ });
95
+ });
96
+ });
97
+ // ─── Zod schema (post-parse client-side validation) ────────────────────────
98
+ describe('satisfiesAtomSchema (ADR-079-r2 §5.2)', () => {
99
+ it('accepts UUID form without version-pin', () => {
100
+ const a = satisfiesAtomSchema.parse({
101
+ kind: 'satisfies',
102
+ targetTaskId: 'T10495',
103
+ targetAcId: '8f4a2c1e-b09d-4f6a-9c3e-7a1d4f8c0b2e',
104
+ });
105
+ expect(a.targetTaskId).toBe('T10495');
106
+ expect(a.targetAcId).toBe('8f4a2c1e-b09d-4f6a-9c3e-7a1d4f8c0b2e');
107
+ expect(a.targetAcAlias).toBeUndefined();
108
+ expect(a.versionPin).toBeUndefined();
109
+ });
110
+ it('accepts alias form without version-pin', () => {
111
+ const a = satisfiesAtomSchema.parse({
112
+ kind: 'satisfies',
113
+ targetTaskId: 'T10495',
114
+ targetAcAlias: 'AC2',
115
+ });
116
+ expect(a.targetAcAlias).toBe('AC2');
117
+ expect(a.targetAcId).toBeUndefined();
118
+ });
119
+ it('accepts alias form with version-pin', () => {
120
+ const a = satisfiesAtomSchema.parse({
121
+ kind: 'satisfies',
122
+ targetTaskId: 'T10495',
123
+ targetAcAlias: 'AC2',
124
+ versionPin: '20260524223045',
125
+ });
126
+ expect(a.versionPin).toBe('20260524223045');
127
+ });
128
+ it('accepts UUID form with version-pin (highest-trust)', () => {
129
+ const a = satisfiesAtomSchema.parse({
130
+ kind: 'satisfies',
131
+ targetTaskId: 'T10495',
132
+ targetAcId: '8f4a2c1e-b09d-4f6a-9c3e-7a1d4f8c0b2e',
133
+ versionPin: '20260524223045',
134
+ });
135
+ expect(a.targetAcId).toBeDefined();
136
+ expect(a.versionPin).toBe('20260524223045');
137
+ });
138
+ it('rejects malformed targetTaskId via schema', () => {
139
+ const r = satisfiesAtomSchema.safeParse({
140
+ kind: 'satisfies',
141
+ targetTaskId: 'task-1234',
142
+ targetAcAlias: 'AC2',
143
+ });
144
+ expect(r.success).toBe(false);
145
+ });
146
+ it('rejects mixed-case UUID via schema', () => {
147
+ const r = satisfiesAtomSchema.safeParse({
148
+ kind: 'satisfies',
149
+ targetTaskId: 'T10495',
150
+ targetAcId: '8F4A2C1E-B09D-4F6A-9C3E-7A1D4F8C0B2E',
151
+ });
152
+ expect(r.success).toBe(false);
153
+ });
154
+ it('rejects malformed version-pin via schema', () => {
155
+ const r = satisfiesAtomSchema.safeParse({
156
+ kind: 'satisfies',
157
+ targetTaskId: 'T10495',
158
+ targetAcAlias: 'AC2',
159
+ versionPin: '2026-05-24T22:30',
160
+ });
161
+ expect(r.success).toBe(false);
162
+ });
163
+ it('round-trips through the EvidenceAtomSchema discriminated union', () => {
164
+ const a = EvidenceAtomSchema.parse({
165
+ kind: 'satisfies',
166
+ targetTaskId: 'T10495',
167
+ targetAcAlias: 'AC2',
168
+ });
169
+ expect(a.kind).toBe('satisfies');
170
+ });
171
+ });
172
+ // ─── parseEvidenceString (CLI parser) ──────────────────────────────────────
173
+ describe('parseEvidenceString — satisfies atom (T10506)', () => {
174
+ // ─── Valid forms ─────────────────────────────────────────────────────────
175
+ it('parses UUID form', () => {
176
+ const atoms = parseEvidenceString('satisfies:T10495#8f4a2c1e-b09d-4f6a-9c3e-7a1d4f8c0b2e');
177
+ expect(atoms).toHaveLength(1);
178
+ expect(atoms[0]).toEqual({
179
+ kind: 'satisfies',
180
+ targetTaskId: 'T10495',
181
+ targetAcId: '8f4a2c1e-b09d-4f6a-9c3e-7a1d4f8c0b2e',
182
+ });
183
+ });
184
+ it('parses alias form', () => {
185
+ const atoms = parseEvidenceString('satisfies:T10495#AC2');
186
+ expect(atoms).toHaveLength(1);
187
+ expect(atoms[0]).toEqual({
188
+ kind: 'satisfies',
189
+ targetTaskId: 'T10495',
190
+ targetAcAlias: 'AC2',
191
+ });
192
+ });
193
+ it('parses alias form with version-pin', () => {
194
+ const atoms = parseEvidenceString('satisfies:T10495#AC2@20260524223045');
195
+ expect(atoms).toHaveLength(1);
196
+ expect(atoms[0]).toEqual({
197
+ kind: 'satisfies',
198
+ targetTaskId: 'T10495',
199
+ targetAcAlias: 'AC2',
200
+ versionPin: '20260524223045',
201
+ });
202
+ });
203
+ it('parses UUID form with version-pin (canonical highest-trust)', () => {
204
+ const atoms = parseEvidenceString('satisfies:T10495#8f4a2c1e-b09d-4f6a-9c3e-7a1d4f8c0b2e@20260524223045');
205
+ expect(atoms).toHaveLength(1);
206
+ expect(atoms[0]).toEqual({
207
+ kind: 'satisfies',
208
+ targetTaskId: 'T10495',
209
+ targetAcId: '8f4a2c1e-b09d-4f6a-9c3e-7a1d4f8c0b2e',
210
+ versionPin: '20260524223045',
211
+ });
212
+ });
213
+ it('parses multiple satisfies atoms in one evidence string', () => {
214
+ const atoms = parseEvidenceString('satisfies:T10495#AC2;satisfies:T10493#AC1');
215
+ expect(atoms).toHaveLength(2);
216
+ expect(atoms[0]).toMatchObject({
217
+ kind: 'satisfies',
218
+ targetTaskId: 'T10495',
219
+ targetAcAlias: 'AC2',
220
+ });
221
+ expect(atoms[1]).toMatchObject({
222
+ kind: 'satisfies',
223
+ targetTaskId: 'T10493',
224
+ targetAcAlias: 'AC1',
225
+ });
226
+ });
227
+ it('parses mixed evidence: commit + files + satisfies', () => {
228
+ const atoms = parseEvidenceString('commit:abc1234;files:src/foo.ts,src/bar.ts;satisfies:T10495#AC2');
229
+ expect(atoms).toHaveLength(3);
230
+ expect(atoms[0]).toEqual({ kind: 'commit', sha: 'abc1234' });
231
+ expect(atoms[1]).toEqual({ kind: 'files', paths: ['src/foo.ts', 'src/bar.ts'] });
232
+ expect(atoms[2]).toEqual({
233
+ kind: 'satisfies',
234
+ targetTaskId: 'T10495',
235
+ targetAcAlias: 'AC2',
236
+ });
237
+ });
238
+ it('parses mixed evidence: satisfies + pr (single PR landing multiple ACs)', () => {
239
+ const atoms = parseEvidenceString('satisfies:T10506#AC1;satisfies:T10506#AC2;pr:773');
240
+ expect(atoms).toHaveLength(3);
241
+ expect(atoms[2]).toEqual({ kind: 'pr', prNumber: 773 });
242
+ });
243
+ // ─── Malformed: missing colon ────────────────────────────────────────────
244
+ it('rejects atom missing the kind-payload colon', () => {
245
+ // "satisfiesT10495#AC2" — no `:` separator at all
246
+ expect(() => parseEvidenceString('satisfiesT10495#AC2')).toThrow(EvidenceParseError);
247
+ });
248
+ // ─── Malformed: missing hash ─────────────────────────────────────────────
249
+ it('rejects atom missing the # separator between task-id and ac-id', () => {
250
+ expect(() => parseEvidenceString('satisfies:T10495-AC2')).toThrow(EvidenceParseError);
251
+ expect(() => parseEvidenceString('satisfies:T10495AC2')).toThrow(EvidenceParseError);
252
+ });
253
+ it('rejects atom with # at start of payload (empty task-id)', () => {
254
+ expect(() => parseEvidenceString('satisfies:#AC2')).toThrow(EvidenceParseError);
255
+ });
256
+ it('rejects atom with # at end of payload (empty ac-id)', () => {
257
+ expect(() => parseEvidenceString('satisfies:T10495#')).toThrow(EvidenceParseError);
258
+ });
259
+ // ─── Malformed: missing T-prefix on task-id ──────────────────────────────
260
+ it('rejects atom with non-T-prefixed task-id', () => {
261
+ expect(() => parseEvidenceString('satisfies:10495#AC2')).toThrow(EvidenceParseError);
262
+ expect(() => parseEvidenceString('satisfies:task-10495#AC2')).toThrow(EvidenceParseError);
263
+ });
264
+ it('rejects atom with lowercase t prefix', () => {
265
+ expect(() => parseEvidenceString('satisfies:t10495#AC2')).toThrow(EvidenceParseError);
266
+ });
267
+ it('rejects atom with task-id exceeding 7 digits', () => {
268
+ expect(() => parseEvidenceString('satisfies:T12345678#AC2')).toThrow(EvidenceParseError);
269
+ });
270
+ // ─── Malformed: ac-id ────────────────────────────────────────────────────
271
+ it('rejects atom with mixed-case UUID', () => {
272
+ // Council §2.2 strictness — silent dedupe prevention
273
+ expect(() => parseEvidenceString('satisfies:T10495#8F4A2C1E-B09D-4F6A-9C3E-7A1D4F8C0B2E')).toThrow(EvidenceParseError);
274
+ });
275
+ it('rejects atom with ac-id that is neither UUID nor AC<digits> alias', () => {
276
+ expect(() => parseEvidenceString('satisfies:T10495#hello')).toThrow(EvidenceParseError);
277
+ expect(() => parseEvidenceString('satisfies:T10495#2')).toThrow(EvidenceParseError);
278
+ });
279
+ it('rejects atom with alias exceeding 4 digits', () => {
280
+ expect(() => parseEvidenceString('satisfies:T10495#AC10000')).toThrow(EvidenceParseError);
281
+ });
282
+ // ─── Malformed: version-pin ──────────────────────────────────────────────
283
+ it('rejects atom with malformed version-pin (not 14 digits)', () => {
284
+ expect(() => parseEvidenceString('satisfies:T10495#AC2@2026-05-24')).toThrow(EvidenceParseError);
285
+ expect(() => parseEvidenceString('satisfies:T10495#AC2@2026052422304')).toThrow(EvidenceParseError);
286
+ });
287
+ it('rejects atom with @ but empty version-pin payload', () => {
288
+ expect(() => parseEvidenceString('satisfies:T10495#AC2@')).toThrow(EvidenceParseError);
289
+ });
290
+ // ─── Error message smoke: ensures kind name appears in default-case ──────
291
+ it('includes "satisfies" in the unknown-kind error suggestion list', () => {
292
+ try {
293
+ parseEvidenceString('unknownkind:foo');
294
+ throw new Error('expected EvidenceParseError');
295
+ }
296
+ catch (err) {
297
+ expect(err).toBeInstanceOf(EvidenceParseError);
298
+ expect(err.fix).toContain('satisfies');
299
+ }
300
+ });
301
+ });
302
+ //# sourceMappingURL=satisfies-atom.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"satisfies-atom.test.js","sourceRoot":"","sources":["../../src/__tests__/satisfies-atom.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Type-level and runtime shape tests for T10510 Validator role contracts.
3
+ *
4
+ * Covers the AgentRole enum extension and the four envelope types
5
+ * (`ValidatorFinding`, `ValidatorAttestation`, `ValidatorRejection`,
6
+ * `ValidatorVerdict`) plus their Zod schemas and type guards.
7
+ *
8
+ * @task T10510
9
+ * @epic T10383 (E-VALIDATOR-ROLE)
10
+ * @saga T10377 (SG-IVTR-AC-BINDING)
11
+ */
12
+ export {};
13
+ //# sourceMappingURL=validator-types.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator-types.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/validator-types.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
@@ -0,0 +1,293 @@
1
+ /**
2
+ * Type-level and runtime shape tests for T10510 Validator role contracts.
3
+ *
4
+ * Covers the AgentRole enum extension and the four envelope types
5
+ * (`ValidatorFinding`, `ValidatorAttestation`, `ValidatorRejection`,
6
+ * `ValidatorVerdict`) plus their Zod schemas and type guards.
7
+ *
8
+ * @task T10510
9
+ * @epic T10383 (E-VALIDATOR-ROLE)
10
+ * @saga T10377 (SG-IVTR-AC-BINDING)
11
+ */
12
+ import { describe, expect, it } from 'vitest';
13
+ import { AGENT_ROLES, isAgentRole, isValidatorAttestation, isValidatorRejection, isValidatorVerdict, VALIDATOR_ID_REGEX, validatorAttestationSchema, validatorFindingSchema, validatorRejectionSchema, validatorVerdictSchema, } from '../validator/index.js';
14
+ // ============================================================================
15
+ // Test fixtures
16
+ // ============================================================================
17
+ const NOW = '2026-05-24T12:00:00Z';
18
+ const passFinding = {
19
+ acId: '11111111-1111-4111-8111-111111111111',
20
+ status: 'pass',
21
+ reasoning: 'AC satisfied — implementation matches spec',
22
+ checkedAt: NOW,
23
+ };
24
+ const failFinding = {
25
+ acId: '22222222-2222-4222-8222-222222222222',
26
+ status: 'fail',
27
+ reasoning: 'Missing error handling for the null branch',
28
+ evidenceRefs: ['src/foo.ts:42', 'tests/foo.test.ts:17'],
29
+ checkedAt: NOW,
30
+ };
31
+ const inconclusiveFinding = {
32
+ acId: '33333333-3333-4333-8333-333333333333',
33
+ status: 'inconclusive',
34
+ reasoning: 'Cannot reproduce the claimed test — file not present',
35
+ checkedAt: NOW,
36
+ };
37
+ // ============================================================================
38
+ // AgentRole enum
39
+ // ============================================================================
40
+ describe('AgentRole enum (T10510)', () => {
41
+ it('contains the four canonical roles', () => {
42
+ expect(AGENT_ROLES).toEqual(['orchestrator', 'lead', 'worker', 'validator']);
43
+ });
44
+ it('AGENT_ROLES is a readonly tuple of length 4', () => {
45
+ // `as const` is a compile-time readonly marker — there is no runtime
46
+ // freeze. The TS type guard below ensures mutation attempts are rejected
47
+ // by the compiler; runtime length is the structural invariant.
48
+ expect(AGENT_ROLES.length).toBe(4);
49
+ // @ts-expect-error — readonly tuple disallows .push at the type level.
50
+ AGENT_ROLES.push;
51
+ });
52
+ it('AgentRole type compiles for all four values', () => {
53
+ const roles = ['orchestrator', 'lead', 'worker', 'validator'];
54
+ expect(roles).toHaveLength(4);
55
+ });
56
+ it('isAgentRole accepts canonical values', () => {
57
+ for (const r of AGENT_ROLES) {
58
+ expect(isAgentRole(r)).toBe(true);
59
+ }
60
+ });
61
+ it('isAgentRole rejects unknown strings and non-strings', () => {
62
+ expect(isAgentRole('subagent')).toBe(false);
63
+ expect(isAgentRole('Validator')).toBe(false);
64
+ expect(isAgentRole('')).toBe(false);
65
+ expect(isAgentRole(undefined)).toBe(false);
66
+ expect(isAgentRole(null)).toBe(false);
67
+ expect(isAgentRole(42)).toBe(false);
68
+ expect(isAgentRole({})).toBe(false);
69
+ });
70
+ });
71
+ // ============================================================================
72
+ // VALIDATOR_ID_REGEX
73
+ // ============================================================================
74
+ describe('VALIDATOR_ID_REGEX (T10510)', () => {
75
+ it('accepts canonical validator agentIds', () => {
76
+ expect(VALIDATOR_ID_REGEX.test('validator-prime')).toBe(true);
77
+ expect(VALIDATOR_ID_REGEX.test('validator-sec-001')).toBe(true);
78
+ expect(VALIDATOR_ID_REGEX.test('validator-a')).toBe(true);
79
+ expect(VALIDATOR_ID_REGEX.test('validator-9-test')).toBe(true);
80
+ });
81
+ it('rejects malformed validator agentIds', () => {
82
+ expect(VALIDATOR_ID_REGEX.test('validator-')).toBe(false);
83
+ expect(VALIDATOR_ID_REGEX.test('Validator-prime')).toBe(false);
84
+ expect(VALIDATOR_ID_REGEX.test('validator-Prime')).toBe(false);
85
+ expect(VALIDATOR_ID_REGEX.test('worker-prime')).toBe(false);
86
+ expect(VALIDATOR_ID_REGEX.test('validator-_x')).toBe(false);
87
+ });
88
+ });
89
+ // ============================================================================
90
+ // ValidatorFinding
91
+ // ============================================================================
92
+ describe('ValidatorFinding (T10510)', () => {
93
+ it('accepts pass / fail / inconclusive', () => {
94
+ expect(validatorFindingSchema.safeParse(passFinding).success).toBe(true);
95
+ expect(validatorFindingSchema.safeParse(failFinding).success).toBe(true);
96
+ expect(validatorFindingSchema.safeParse(inconclusiveFinding).success).toBe(true);
97
+ });
98
+ it('rejects empty acId', () => {
99
+ const bad = { ...passFinding, acId: '' };
100
+ expect(validatorFindingSchema.safeParse(bad).success).toBe(false);
101
+ });
102
+ it('rejects empty reasoning', () => {
103
+ const bad = { ...passFinding, reasoning: '' };
104
+ expect(validatorFindingSchema.safeParse(bad).success).toBe(false);
105
+ });
106
+ it('rejects unknown status value', () => {
107
+ const bad = { ...passFinding, status: 'warn' };
108
+ expect(validatorFindingSchema.safeParse(bad).success).toBe(false);
109
+ });
110
+ it('accepts optional evidenceRefs array', () => {
111
+ const withRefs = { ...passFinding, evidenceRefs: ['a', 'b'] };
112
+ expect(validatorFindingSchema.safeParse(withRefs).success).toBe(true);
113
+ });
114
+ });
115
+ // ============================================================================
116
+ // ValidatorAttestation
117
+ // ============================================================================
118
+ describe('ValidatorAttestation (T10510)', () => {
119
+ const baseAttestation = {
120
+ verdict: 'attest',
121
+ taskId: 'T10510',
122
+ validatorId: 'validator-prime',
123
+ findings: [passFinding],
124
+ attestedAt: NOW,
125
+ schemaVersion: '1',
126
+ };
127
+ it('accepts a well-formed attestation with all passes', () => {
128
+ expect(validatorAttestationSchema.safeParse(baseAttestation).success).toBe(true);
129
+ });
130
+ it('accepts optional summary', () => {
131
+ const withSummary = { ...baseAttestation, summary: 'All ACs verified' };
132
+ expect(validatorAttestationSchema.safeParse(withSummary).success).toBe(true);
133
+ });
134
+ it('accepts multiple pass findings', () => {
135
+ const multi = {
136
+ ...baseAttestation,
137
+ findings: [passFinding, { ...passFinding, acId: '44444444-4444-4444-8444-444444444444' }],
138
+ };
139
+ expect(validatorAttestationSchema.safeParse(multi).success).toBe(true);
140
+ });
141
+ it('REJECTS attestation containing any fail finding', () => {
142
+ const mixed = { ...baseAttestation, findings: [passFinding, failFinding] };
143
+ const r = validatorAttestationSchema.safeParse(mixed);
144
+ expect(r.success).toBe(false);
145
+ });
146
+ it('REJECTS attestation containing inconclusive finding', () => {
147
+ const mixed = { ...baseAttestation, findings: [passFinding, inconclusiveFinding] };
148
+ expect(validatorAttestationSchema.safeParse(mixed).success).toBe(false);
149
+ });
150
+ it('REJECTS empty findings array', () => {
151
+ const empty = { ...baseAttestation, findings: [] };
152
+ expect(validatorAttestationSchema.safeParse(empty).success).toBe(false);
153
+ });
154
+ it('REJECTS malformed validatorId', () => {
155
+ const bad = { ...baseAttestation, validatorId: 'worker-prime' };
156
+ expect(validatorAttestationSchema.safeParse(bad).success).toBe(false);
157
+ });
158
+ it('REJECTS wrong verdict discriminant', () => {
159
+ const bad = { ...baseAttestation, verdict: 'reject' };
160
+ expect(validatorAttestationSchema.safeParse(bad).success).toBe(false);
161
+ });
162
+ it('REJECTS wrong schemaVersion', () => {
163
+ const bad = { ...baseAttestation, schemaVersion: '2' };
164
+ expect(validatorAttestationSchema.safeParse(bad).success).toBe(false);
165
+ });
166
+ });
167
+ // ============================================================================
168
+ // ValidatorRejection
169
+ // ============================================================================
170
+ describe('ValidatorRejection (T10510)', () => {
171
+ const baseRejection = {
172
+ verdict: 'reject',
173
+ taskId: 'T10510',
174
+ validatorId: 'validator-sec-001',
175
+ findings: [failFinding],
176
+ summary: 'AC#2 fails — null branch unhandled',
177
+ rejectedAt: NOW,
178
+ schemaVersion: '1',
179
+ };
180
+ it('accepts a well-formed rejection with a fail finding', () => {
181
+ expect(validatorRejectionSchema.safeParse(baseRejection).success).toBe(true);
182
+ });
183
+ it('accepts a rejection with only an inconclusive finding', () => {
184
+ const inc = { ...baseRejection, findings: [inconclusiveFinding] };
185
+ expect(validatorRejectionSchema.safeParse(inc).success).toBe(true);
186
+ });
187
+ it('accepts mixed pass + fail findings', () => {
188
+ const mixed = { ...baseRejection, findings: [passFinding, failFinding] };
189
+ expect(validatorRejectionSchema.safeParse(mixed).success).toBe(true);
190
+ });
191
+ it('REJECTS rejection where every finding is pass', () => {
192
+ const allPass = { ...baseRejection, findings: [passFinding, passFinding] };
193
+ const r = validatorRejectionSchema.safeParse(allPass);
194
+ expect(r.success).toBe(false);
195
+ });
196
+ it('REJECTS empty findings array', () => {
197
+ const empty = { ...baseRejection, findings: [] };
198
+ expect(validatorRejectionSchema.safeParse(empty).success).toBe(false);
199
+ });
200
+ it('REJECTS empty summary', () => {
201
+ const bad = { ...baseRejection, summary: '' };
202
+ expect(validatorRejectionSchema.safeParse(bad).success).toBe(false);
203
+ });
204
+ it('accepts optional remediationHints', () => {
205
+ const withHints = {
206
+ ...baseRejection,
207
+ remediationHints: ['Add null guard to foo()', 'Add regression test'],
208
+ };
209
+ expect(validatorRejectionSchema.safeParse(withHints).success).toBe(true);
210
+ });
211
+ });
212
+ // ============================================================================
213
+ // ValidatorVerdict discriminated union
214
+ // ============================================================================
215
+ describe('ValidatorVerdict (T10510)', () => {
216
+ const attestation = {
217
+ verdict: 'attest',
218
+ taskId: 'T10510',
219
+ validatorId: 'validator-prime',
220
+ findings: [passFinding],
221
+ attestedAt: NOW,
222
+ schemaVersion: '1',
223
+ };
224
+ const rejection = {
225
+ verdict: 'reject',
226
+ taskId: 'T10510',
227
+ validatorId: 'validator-prime',
228
+ findings: [failFinding],
229
+ summary: 'fail',
230
+ rejectedAt: NOW,
231
+ schemaVersion: '1',
232
+ };
233
+ it('schema accepts both attest and reject envelopes', () => {
234
+ expect(validatorVerdictSchema.safeParse(attestation).success).toBe(true);
235
+ expect(validatorVerdictSchema.safeParse(rejection).success).toBe(true);
236
+ });
237
+ it('schema rejects envelope with unknown verdict', () => {
238
+ const bad = { ...attestation, verdict: 'maybe' };
239
+ expect(validatorVerdictSchema.safeParse(bad).success).toBe(false);
240
+ });
241
+ it('discriminant narrows in TypeScript at compile time', () => {
242
+ const handle = (v) => {
243
+ if (v.verdict === 'attest') {
244
+ // TS narrows to ValidatorAttestation here
245
+ return `attested ${v.attestedAt}`;
246
+ }
247
+ // TS narrows to ValidatorRejection here
248
+ return `rejected ${v.rejectedAt} — ${v.summary}`;
249
+ };
250
+ expect(handle(attestation)).toContain('attested');
251
+ expect(handle(rejection)).toContain('rejected');
252
+ });
253
+ });
254
+ // ============================================================================
255
+ // Type guards
256
+ // ============================================================================
257
+ describe('Validator type guards (T10510)', () => {
258
+ const attestation = {
259
+ verdict: 'attest',
260
+ taskId: 'T10510',
261
+ validatorId: 'validator-prime',
262
+ findings: [passFinding],
263
+ attestedAt: NOW,
264
+ schemaVersion: '1',
265
+ };
266
+ const rejection = {
267
+ verdict: 'reject',
268
+ taskId: 'T10510',
269
+ validatorId: 'validator-prime',
270
+ findings: [failFinding],
271
+ summary: 'fail',
272
+ rejectedAt: NOW,
273
+ schemaVersion: '1',
274
+ };
275
+ it('isValidatorAttestation returns true only for attestations', () => {
276
+ expect(isValidatorAttestation(attestation)).toBe(true);
277
+ expect(isValidatorAttestation(rejection)).toBe(false);
278
+ expect(isValidatorAttestation(null)).toBe(false);
279
+ expect(isValidatorAttestation({})).toBe(false);
280
+ });
281
+ it('isValidatorRejection returns true only for rejections', () => {
282
+ expect(isValidatorRejection(rejection)).toBe(true);
283
+ expect(isValidatorRejection(attestation)).toBe(false);
284
+ expect(isValidatorRejection(null)).toBe(false);
285
+ });
286
+ it('isValidatorVerdict returns true for both shapes', () => {
287
+ expect(isValidatorVerdict(attestation)).toBe(true);
288
+ expect(isValidatorVerdict(rejection)).toBe(true);
289
+ expect(isValidatorVerdict({ verdict: 'attest' })).toBe(false);
290
+ expect(isValidatorVerdict(null)).toBe(false);
291
+ });
292
+ });
293
+ //# sourceMappingURL=validator-types.test.js.map