@cleocode/contracts 2026.4.70 → 2026.4.73
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/evidence-record.test.d.ts +14 -0
- package/dist/__tests__/evidence-record.test.d.ts.map +1 -0
- package/dist/__tests__/evidence-record.test.js +362 -0
- package/dist/__tests__/evidence-record.test.js.map +1 -0
- package/dist/__tests__/invariants.test.d.ts +19 -0
- package/dist/__tests__/invariants.test.d.ts.map +1 -0
- package/dist/__tests__/invariants.test.js +351 -0
- package/dist/__tests__/invariants.test.js.map +1 -0
- package/dist/acceptance-gate-schema.d.ts +81 -4
- package/dist/acceptance-gate-schema.d.ts.map +1 -1
- package/dist/acceptance-gate-schema.js +60 -1
- package/dist/acceptance-gate-schema.js.map +1 -1
- package/dist/acceptance-gate.d.ts +99 -2
- package/dist/acceptance-gate.d.ts.map +1 -1
- package/dist/evidence-record-schema.d.ts +202 -0
- package/dist/evidence-record-schema.d.ts.map +1 -0
- package/dist/evidence-record-schema.js +130 -0
- package/dist/evidence-record-schema.js.map +1 -0
- package/dist/evidence-record.d.ts +167 -0
- package/dist/evidence-record.d.ts.map +1 -0
- package/dist/evidence-record.js +21 -0
- package/dist/evidence-record.js.map +1 -0
- package/dist/index.d.ts +10 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/task-evidence.d.ts +251 -0
- package/dist/task-evidence.d.ts.map +1 -0
- package/dist/task-evidence.js +89 -0
- package/dist/task-evidence.js.map +1 -0
- package/package.json +8 -2
- package/schemas/acceptance-gate.schema.json +9 -0
- package/schemas/attachment.schema.json +9 -0
- package/schemas/gate-result-details.schema.json +9 -0
- package/schemas/gate-result.schema.json +9 -0
- package/schemas/manifest-v1.json +176 -0
- package/schemas/task-evidence.schema.json +9 -0
- package/schemas/task.schema.json +9 -0
- package/src/__tests__/evidence-record.test.ts +412 -0
- package/src/__tests__/invariants.test.ts +445 -0
- package/src/acceptance-gate-schema.ts +65 -1
- package/src/acceptance-gate.ts +108 -2
- package/src/evidence-record-schema.ts +158 -0
- package/src/evidence-record.ts +182 -0
- package/src/index.ts +65 -1
- package/src/task-evidence.ts +239 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod validation schemas for {@link EvidenceRecord} and its variants.
|
|
3
|
+
*
|
|
4
|
+
* Kept in a separate file from the plain TypeScript types so that consumers
|
|
5
|
+
* that do not need runtime validation (e.g. type-only imports) pay zero cost.
|
|
6
|
+
*
|
|
7
|
+
* All schemas are named `*RecordSchema` and derive their inferred types from
|
|
8
|
+
* the canonical TypeScript interfaces in `./evidence-record.ts`.
|
|
9
|
+
*
|
|
10
|
+
* The top-level {@link evidenceRecordSchema} is a `z.discriminatedUnion` on
|
|
11
|
+
* `"kind"` so Zod can route to the correct variant in O(1).
|
|
12
|
+
*
|
|
13
|
+
* @epic T810
|
|
14
|
+
* @task T816
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { z } from 'zod';
|
|
18
|
+
|
|
19
|
+
// ─── Shared base fields ───────────────────────────────────────────────────────
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Zod schema for the provenance fields shared by every EvidenceRecord variant.
|
|
23
|
+
*
|
|
24
|
+
* Not exported as a standalone validator; always composed into a full record
|
|
25
|
+
* schema via `.extend()`.
|
|
26
|
+
*/
|
|
27
|
+
const evidenceBaseSchema = z.object({
|
|
28
|
+
/** Identity string of the agent that produced this record. */
|
|
29
|
+
agentIdentity: z.string().min(1),
|
|
30
|
+
/** SHA-256 hex digest (64 chars) of the attached artifact. */
|
|
31
|
+
attachmentSha256: z.string().length(64),
|
|
32
|
+
/** ISO 8601 timestamp at which the action ran. */
|
|
33
|
+
ranAt: z.string().datetime(),
|
|
34
|
+
/** Wall-clock duration of the action in milliseconds. */
|
|
35
|
+
durationMs: z.number().nonnegative(),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// ─── Individual variant schemas ───────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Zod schema for {@link ImplDiffRecord}.
|
|
42
|
+
*
|
|
43
|
+
* Validates that `filesChanged` is a non-empty array and that `linesAdded` /
|
|
44
|
+
* `linesRemoved` are non-negative integers.
|
|
45
|
+
*/
|
|
46
|
+
export const implDiffRecordSchema = evidenceBaseSchema.extend({
|
|
47
|
+
kind: z.literal('impl-diff'),
|
|
48
|
+
phase: z.literal('implement'),
|
|
49
|
+
filesChanged: z.array(z.string().min(1)).min(1),
|
|
50
|
+
linesAdded: z.number().int().nonnegative(),
|
|
51
|
+
linesRemoved: z.number().int().nonnegative(),
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
/** Inferred TypeScript type from {@link implDiffRecordSchema}. */
|
|
55
|
+
export type ImplDiffRecordInput = z.input<typeof implDiffRecordSchema>;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Zod schema for {@link ValidateSpecCheckRecord}.
|
|
59
|
+
*
|
|
60
|
+
* Validates that `reqIdsChecked` is non-empty and `details` is non-blank.
|
|
61
|
+
*/
|
|
62
|
+
export const validateSpecCheckRecordSchema = evidenceBaseSchema.extend({
|
|
63
|
+
kind: z.literal('validate-spec-check'),
|
|
64
|
+
phase: z.literal('validate'),
|
|
65
|
+
reqIdsChecked: z.array(z.string().min(1)).min(1),
|
|
66
|
+
passed: z.boolean(),
|
|
67
|
+
details: z.string().min(1),
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
/** Inferred TypeScript type from {@link validateSpecCheckRecordSchema}. */
|
|
71
|
+
export type ValidateSpecCheckRecordInput = z.input<typeof validateSpecCheckRecordSchema>;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Zod schema for {@link TestOutputRecord}.
|
|
75
|
+
*
|
|
76
|
+
* Validates that `command` is non-blank and test counts are non-negative.
|
|
77
|
+
*/
|
|
78
|
+
export const testOutputRecordSchema = evidenceBaseSchema.extend({
|
|
79
|
+
kind: z.literal('test-output'),
|
|
80
|
+
phase: z.literal('test'),
|
|
81
|
+
command: z.string().min(1),
|
|
82
|
+
exitCode: z.number().int(),
|
|
83
|
+
testsPassed: z.number().int().nonnegative(),
|
|
84
|
+
testsFailed: z.number().int().nonnegative(),
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
/** Inferred TypeScript type from {@link testOutputRecordSchema}. */
|
|
88
|
+
export type TestOutputRecordInput = z.input<typeof testOutputRecordSchema>;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Zod schema for {@link LintReportRecord}.
|
|
92
|
+
*
|
|
93
|
+
* `phase` is restricted to `'implement' | 'test'`.
|
|
94
|
+
* `warnings` and `errors` are non-negative integers.
|
|
95
|
+
*/
|
|
96
|
+
export const lintReportRecordSchema = evidenceBaseSchema.extend({
|
|
97
|
+
kind: z.literal('lint-report'),
|
|
98
|
+
phase: z.enum(['implement', 'test']),
|
|
99
|
+
tool: z.string().min(1),
|
|
100
|
+
passed: z.boolean(),
|
|
101
|
+
warnings: z.number().int().nonnegative(),
|
|
102
|
+
errors: z.number().int().nonnegative(),
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
/** Inferred TypeScript type from {@link lintReportRecordSchema}. */
|
|
106
|
+
export type LintReportRecordInput = z.input<typeof lintReportRecordSchema>;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Zod schema for {@link CommandOutputRecord}.
|
|
110
|
+
*
|
|
111
|
+
* `phase` can be `'implement'`, `'validate'`, or `'test'`.
|
|
112
|
+
* `cmd` must be non-blank.
|
|
113
|
+
*/
|
|
114
|
+
export const commandOutputRecordSchema = evidenceBaseSchema.extend({
|
|
115
|
+
kind: z.literal('command-output'),
|
|
116
|
+
phase: z.enum(['implement', 'validate', 'test']),
|
|
117
|
+
cmd: z.string().min(1),
|
|
118
|
+
exitCode: z.number().int(),
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
/** Inferred TypeScript type from {@link commandOutputRecordSchema}. */
|
|
122
|
+
export type CommandOutputRecordInput = z.input<typeof commandOutputRecordSchema>;
|
|
123
|
+
|
|
124
|
+
// ─── Discriminated union ──────────────────────────────────────────────────────
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Zod discriminated-union schema for {@link EvidenceRecord}.
|
|
128
|
+
*
|
|
129
|
+
* Uses `z.discriminatedUnion('kind', [...])` for O(1) variant lookup.
|
|
130
|
+
* Parse with `evidenceRecordSchema.parse(input)` or
|
|
131
|
+
* `evidenceRecordSchema.safeParse(input)`.
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```ts
|
|
135
|
+
* const rec = evidenceRecordSchema.parse({
|
|
136
|
+
* kind: 'test-output',
|
|
137
|
+
* phase: 'test',
|
|
138
|
+
* agentIdentity: 'T816-worker',
|
|
139
|
+
* attachmentSha256: 'a'.repeat(64),
|
|
140
|
+
* command: 'pnpm test',
|
|
141
|
+
* exitCode: 0,
|
|
142
|
+
* testsPassed: 10,
|
|
143
|
+
* testsFailed: 0,
|
|
144
|
+
* ranAt: '2026-04-16T00:00:00.000Z',
|
|
145
|
+
* durationMs: 1234,
|
|
146
|
+
* });
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
export const evidenceRecordSchema = z.discriminatedUnion('kind', [
|
|
150
|
+
implDiffRecordSchema,
|
|
151
|
+
validateSpecCheckRecordSchema,
|
|
152
|
+
testOutputRecordSchema,
|
|
153
|
+
lintReportRecordSchema,
|
|
154
|
+
commandOutputRecordSchema,
|
|
155
|
+
]);
|
|
156
|
+
|
|
157
|
+
/** Inferred TypeScript type from {@link evidenceRecordSchema}. */
|
|
158
|
+
export type EvidenceRecordInput = z.input<typeof evidenceRecordSchema>;
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EvidenceRecord discriminated union — typed proof artifacts produced by IVTR agents.
|
|
3
|
+
*
|
|
4
|
+
* Each variant represents a specific kind of evidence that an IVTR-phase agent
|
|
5
|
+
* (implement, validate, test) can emit. All variants share a common set of
|
|
6
|
+
* provenance fields (`agentIdentity`, `attachmentSha256`, `ranAt`, `durationMs`)
|
|
7
|
+
* so that evidence rows can be queried, correlated, and archived uniformly.
|
|
8
|
+
*
|
|
9
|
+
* Five kinds are defined:
|
|
10
|
+
* - `impl-diff` — a code change produced by an implement-phase agent
|
|
11
|
+
* - `validate-spec-check` — a spec-requirements check by a validate-phase agent
|
|
12
|
+
* - `test-output` — the output of a test command run by a test-phase agent
|
|
13
|
+
* - `lint-report` — a static-analysis run (biome, tsc, etc.)
|
|
14
|
+
* - `command-output` — a generic CLI command invocation with exit code
|
|
15
|
+
*
|
|
16
|
+
* @epic T810
|
|
17
|
+
* @task T816
|
|
18
|
+
* @see {@link EvidenceRecordKind} for all discriminant values
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
// ─── Variants ────────────────────────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Evidence that an implement-phase agent produced a code diff.
|
|
25
|
+
*
|
|
26
|
+
* `filesChanged` lists the relative paths of every modified file.
|
|
27
|
+
* `attachmentSha256` is the SHA-256 hex digest of the serialised diff attachment.
|
|
28
|
+
*/
|
|
29
|
+
export interface ImplDiffRecord {
|
|
30
|
+
kind: 'impl-diff';
|
|
31
|
+
/** RCASD lifecycle phase that produced this record. */
|
|
32
|
+
phase: 'implement';
|
|
33
|
+
/** Identity string of the agent that ran this action (e.g. `"T816-worker"`). */
|
|
34
|
+
agentIdentity: string;
|
|
35
|
+
/** SHA-256 hex digest (64 chars) of the attached diff blob. */
|
|
36
|
+
attachmentSha256: string;
|
|
37
|
+
/** Relative paths of every file the diff touches. */
|
|
38
|
+
filesChanged: string[];
|
|
39
|
+
/** Net lines added across all changed files. */
|
|
40
|
+
linesAdded: number;
|
|
41
|
+
/** Net lines removed across all changed files. */
|
|
42
|
+
linesRemoved: number;
|
|
43
|
+
/** ISO 8601 timestamp at which the diff was captured. */
|
|
44
|
+
ranAt: string;
|
|
45
|
+
/** Wall-clock duration of the implement action in milliseconds. */
|
|
46
|
+
durationMs: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Evidence that a validate-phase agent checked one or more REQ-IDs against
|
|
51
|
+
* the implementation and recorded a pass/fail verdict.
|
|
52
|
+
*/
|
|
53
|
+
export interface ValidateSpecCheckRecord {
|
|
54
|
+
kind: 'validate-spec-check';
|
|
55
|
+
/** RCASD lifecycle phase that produced this record. */
|
|
56
|
+
phase: 'validate';
|
|
57
|
+
/** Identity string of the agent that ran this action. */
|
|
58
|
+
agentIdentity: string;
|
|
59
|
+
/** SHA-256 hex digest (64 chars) of the spec-check report attachment. */
|
|
60
|
+
attachmentSha256: string;
|
|
61
|
+
/** REQ-IDs checked in this run (e.g. `["IVTR-01", "IVTR-02"]`). */
|
|
62
|
+
reqIdsChecked: string[];
|
|
63
|
+
/** `true` when all checked REQ-IDs passed; `false` if any failed. */
|
|
64
|
+
passed: boolean;
|
|
65
|
+
/** Human-readable summary of results per REQ-ID. */
|
|
66
|
+
details: string;
|
|
67
|
+
/** ISO 8601 timestamp at which the check ran. */
|
|
68
|
+
ranAt: string;
|
|
69
|
+
/** Wall-clock duration of the validation check in milliseconds. */
|
|
70
|
+
durationMs: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Evidence that a test-phase agent ran a test command and recorded counts.
|
|
75
|
+
*/
|
|
76
|
+
export interface TestOutputRecord {
|
|
77
|
+
kind: 'test-output';
|
|
78
|
+
/** RCASD lifecycle phase that produced this record. */
|
|
79
|
+
phase: 'test';
|
|
80
|
+
/** Identity string of the agent that ran this action. */
|
|
81
|
+
agentIdentity: string;
|
|
82
|
+
/** SHA-256 hex digest (64 chars) of the test-output attachment. */
|
|
83
|
+
attachmentSha256: string;
|
|
84
|
+
/** The full test command that was executed (e.g. `"pnpm --filter @cleocode/contracts run test"`). */
|
|
85
|
+
command: string;
|
|
86
|
+
/** Exit code returned by the test command. */
|
|
87
|
+
exitCode: number;
|
|
88
|
+
/** Number of individual test cases that passed. */
|
|
89
|
+
testsPassed: number;
|
|
90
|
+
/** Number of individual test cases that failed. */
|
|
91
|
+
testsFailed: number;
|
|
92
|
+
/** ISO 8601 timestamp at which the test command started. */
|
|
93
|
+
ranAt: string;
|
|
94
|
+
/** Wall-clock duration of the full test run in milliseconds. */
|
|
95
|
+
durationMs: number;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Evidence that a lint / static-analysis tool was run.
|
|
100
|
+
*
|
|
101
|
+
* The `phase` field is `'implement' | 'test'` because lint is commonly run
|
|
102
|
+
* after a code change (implement) or as part of a test suite (test).
|
|
103
|
+
*/
|
|
104
|
+
export interface LintReportRecord {
|
|
105
|
+
kind: 'lint-report';
|
|
106
|
+
/** RCASD lifecycle phase that produced this record. */
|
|
107
|
+
phase: 'implement' | 'test';
|
|
108
|
+
/** Identity string of the agent that ran this action. */
|
|
109
|
+
agentIdentity: string;
|
|
110
|
+
/** SHA-256 hex digest (64 chars) of the lint-output attachment. */
|
|
111
|
+
attachmentSha256: string;
|
|
112
|
+
/** Name of the lint tool that was invoked (e.g. `"biome"`, `"tsc"`). */
|
|
113
|
+
tool: string;
|
|
114
|
+
/** `true` when the lint run produced zero errors. */
|
|
115
|
+
passed: boolean;
|
|
116
|
+
/** Number of warnings emitted (may be > 0 even when `passed` is `true`). */
|
|
117
|
+
warnings: number;
|
|
118
|
+
/** Number of errors emitted. Non-zero means `passed` is `false`. */
|
|
119
|
+
errors: number;
|
|
120
|
+
/** ISO 8601 timestamp at which the lint tool was invoked. */
|
|
121
|
+
ranAt: string;
|
|
122
|
+
/** Wall-clock duration of the lint run in milliseconds. */
|
|
123
|
+
durationMs: number;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Evidence that an agent ran an arbitrary CLI command and recorded its exit code.
|
|
128
|
+
*
|
|
129
|
+
* Use this as the catch-all when none of the other variants fit.
|
|
130
|
+
*/
|
|
131
|
+
export interface CommandOutputRecord {
|
|
132
|
+
kind: 'command-output';
|
|
133
|
+
/** RCASD lifecycle phase that produced this record. */
|
|
134
|
+
phase: 'implement' | 'validate' | 'test';
|
|
135
|
+
/** Identity string of the agent that ran this action. */
|
|
136
|
+
agentIdentity: string;
|
|
137
|
+
/** SHA-256 hex digest (64 chars) of the command-output attachment. */
|
|
138
|
+
attachmentSha256: string;
|
|
139
|
+
/** The CLI command that was executed. */
|
|
140
|
+
cmd: string;
|
|
141
|
+
/** Exit code returned by the command. */
|
|
142
|
+
exitCode: number;
|
|
143
|
+
/** ISO 8601 timestamp at which the command was invoked. */
|
|
144
|
+
ranAt: string;
|
|
145
|
+
/** Wall-clock duration of the command in milliseconds. */
|
|
146
|
+
durationMs: number;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ─── Discriminated union ──────────────────────────────────────────────────────
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* A typed evidence record produced by an IVTR-phase agent.
|
|
153
|
+
*
|
|
154
|
+
* The `kind` discriminant selects the variant. All variants carry
|
|
155
|
+
* `agentIdentity`, `attachmentSha256`, `ranAt`, and `durationMs` for
|
|
156
|
+
* uniform provenance tracking.
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```ts
|
|
160
|
+
* const rec: EvidenceRecord = {
|
|
161
|
+
* kind: 'test-output',
|
|
162
|
+
* phase: 'test',
|
|
163
|
+
* agentIdentity: 'T816-worker',
|
|
164
|
+
* attachmentSha256: 'a'.repeat(64),
|
|
165
|
+
* command: 'pnpm --filter @cleocode/contracts run test',
|
|
166
|
+
* exitCode: 0,
|
|
167
|
+
* testsPassed: 10,
|
|
168
|
+
* testsFailed: 0,
|
|
169
|
+
* ranAt: '2026-04-16T00:00:00.000Z',
|
|
170
|
+
* durationMs: 1234,
|
|
171
|
+
* };
|
|
172
|
+
* ```
|
|
173
|
+
*/
|
|
174
|
+
export type EvidenceRecord =
|
|
175
|
+
| ImplDiffRecord
|
|
176
|
+
| ValidateSpecCheckRecord
|
|
177
|
+
| TestOutputRecord
|
|
178
|
+
| LintReportRecord
|
|
179
|
+
| CommandOutputRecord;
|
|
180
|
+
|
|
181
|
+
/** All valid `kind` discriminants for {@link EvidenceRecord}. */
|
|
182
|
+
export type EvidenceRecordKind = EvidenceRecord['kind'];
|
package/src/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ export type {
|
|
|
15
15
|
FileAssertion,
|
|
16
16
|
FileGate,
|
|
17
17
|
GateBase,
|
|
18
|
+
GateResultDetails,
|
|
18
19
|
HttpGate,
|
|
19
20
|
LintGate,
|
|
20
21
|
ManualGate,
|
|
@@ -26,6 +27,7 @@ export type {
|
|
|
26
27
|
AcceptanceGateSchemaInput,
|
|
27
28
|
AcceptanceItemInput,
|
|
28
29
|
FileAssertionInput,
|
|
30
|
+
GateResultDetailsInput,
|
|
29
31
|
} from './acceptance-gate-schema.js';
|
|
30
32
|
// === Acceptance Gate Zod Schemas (runtime validation) ===
|
|
31
33
|
export {
|
|
@@ -37,6 +39,7 @@ export {
|
|
|
37
39
|
fileAssertionSchema,
|
|
38
40
|
fileGateSchema,
|
|
39
41
|
gateBaseSchema,
|
|
42
|
+
gateResultDetailsSchema,
|
|
40
43
|
httpGateSchema,
|
|
41
44
|
lintGateSchema,
|
|
42
45
|
manualGateSchema,
|
|
@@ -82,6 +85,22 @@ export type {
|
|
|
82
85
|
LocalFileAttachment,
|
|
83
86
|
UrlAttachment,
|
|
84
87
|
} from './attachment.js';
|
|
88
|
+
// === Attachment Zod Schemas (runtime validation) ===
|
|
89
|
+
export type {
|
|
90
|
+
AttachmentMetadataSchemaInput,
|
|
91
|
+
AttachmentRefSchemaInput,
|
|
92
|
+
AttachmentSchemaInput,
|
|
93
|
+
} from './attachment-schema.js';
|
|
94
|
+
export {
|
|
95
|
+
attachmentMetadataSchema,
|
|
96
|
+
attachmentRefSchema,
|
|
97
|
+
attachmentSchema,
|
|
98
|
+
blobAttachmentSchema,
|
|
99
|
+
llmsTxtAttachmentSchema,
|
|
100
|
+
llmtxtDocAttachmentSchema,
|
|
101
|
+
localFileAttachmentSchema,
|
|
102
|
+
urlAttachmentSchema,
|
|
103
|
+
} from './attachment-schema.js';
|
|
85
104
|
// === Backup Manifest Types ===
|
|
86
105
|
export type {
|
|
87
106
|
BackupDatabaseEntry,
|
|
@@ -182,6 +201,33 @@ export {
|
|
|
182
201
|
isErrorType,
|
|
183
202
|
normalizeError,
|
|
184
203
|
} from './errors.js';
|
|
204
|
+
// === Evidence Record Types (IVTR typed proof artifacts) ===
|
|
205
|
+
export type {
|
|
206
|
+
CommandOutputRecord,
|
|
207
|
+
EvidenceRecord,
|
|
208
|
+
EvidenceRecordKind,
|
|
209
|
+
ImplDiffRecord,
|
|
210
|
+
LintReportRecord,
|
|
211
|
+
TestOutputRecord,
|
|
212
|
+
ValidateSpecCheckRecord,
|
|
213
|
+
} from './evidence-record.js';
|
|
214
|
+
export type {
|
|
215
|
+
CommandOutputRecordInput,
|
|
216
|
+
EvidenceRecordInput,
|
|
217
|
+
ImplDiffRecordInput,
|
|
218
|
+
LintReportRecordInput,
|
|
219
|
+
TestOutputRecordInput,
|
|
220
|
+
ValidateSpecCheckRecordInput,
|
|
221
|
+
} from './evidence-record-schema.js';
|
|
222
|
+
// === Evidence Record Zod Schemas (runtime validation) ===
|
|
223
|
+
export {
|
|
224
|
+
commandOutputRecordSchema,
|
|
225
|
+
evidenceRecordSchema,
|
|
226
|
+
implDiffRecordSchema,
|
|
227
|
+
lintReportRecordSchema,
|
|
228
|
+
testOutputRecordSchema,
|
|
229
|
+
validateSpecCheckRecordSchema,
|
|
230
|
+
} from './evidence-record-schema.js';
|
|
185
231
|
// === Exit Codes ===
|
|
186
232
|
export {
|
|
187
233
|
ExitCode,
|
|
@@ -397,6 +443,25 @@ export type {
|
|
|
397
443
|
VerificationFailure,
|
|
398
444
|
VerificationGate,
|
|
399
445
|
} from './task.js';
|
|
446
|
+
// === Task Evidence Types (T801) ===
|
|
447
|
+
export type {
|
|
448
|
+
CommandOutputEvidence,
|
|
449
|
+
FileEvidence,
|
|
450
|
+
LogEvidence,
|
|
451
|
+
ScreenshotEvidence,
|
|
452
|
+
TaskEvidence,
|
|
453
|
+
TaskEvidenceInput,
|
|
454
|
+
TaskEvidenceKind,
|
|
455
|
+
TestOutputEvidence,
|
|
456
|
+
} from './task-evidence.js';
|
|
457
|
+
export {
|
|
458
|
+
commandOutputEvidenceSchema,
|
|
459
|
+
fileEvidenceSchema,
|
|
460
|
+
logEvidenceSchema,
|
|
461
|
+
screenshotEvidenceSchema,
|
|
462
|
+
taskEvidenceSchema,
|
|
463
|
+
testOutputEvidenceSchema,
|
|
464
|
+
} from './task-evidence.js';
|
|
400
465
|
// === TaskRecord Types (string-widened for dispatch/LAFS) ===
|
|
401
466
|
export type {
|
|
402
467
|
MinimalTaskRecord,
|
|
@@ -445,5 +510,4 @@ export type {
|
|
|
445
510
|
WarpLink,
|
|
446
511
|
WarpStage,
|
|
447
512
|
} from './warp-chain.js';
|
|
448
|
-
|
|
449
513
|
// === WASM SDK (Rust crate bindings) ===
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TaskEvidence discriminated union — typed evidence references for verification records.
|
|
3
|
+
*
|
|
4
|
+
* Replaces free-text evidence fields in verification records with structured,
|
|
5
|
+
* kind-specific evidence artifacts. Each variant carries a SHA-256 attachment
|
|
6
|
+
* reference, a timestamp, and optional description.
|
|
7
|
+
*
|
|
8
|
+
* Five evidence kinds are supported:
|
|
9
|
+
* - `file` — a file artifact (source file, output artifact, config)
|
|
10
|
+
* - `log` — a log stream captured from a process
|
|
11
|
+
* - `screenshot` — a visual capture (PNG/JPEG/WEBP)
|
|
12
|
+
* - `test-output` — structured test-runner output
|
|
13
|
+
* - `command-output` — raw stdout/stderr from a shell command
|
|
14
|
+
*
|
|
15
|
+
* @epic T760
|
|
16
|
+
* @task T801
|
|
17
|
+
* @see {@link AcceptanceGateResult} — `evidence` field
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { z } from 'zod';
|
|
21
|
+
|
|
22
|
+
// ─── Variant interfaces ───────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Evidence for a file artifact produced or inspected during verification.
|
|
26
|
+
*
|
|
27
|
+
* The `sha256` is the content hash of the file at capture time, used to
|
|
28
|
+
* look up the blob in the attachment store.
|
|
29
|
+
*/
|
|
30
|
+
export interface FileEvidence {
|
|
31
|
+
kind: 'file';
|
|
32
|
+
/** SHA-256 hex digest of the file at capture time (attachment ref). */
|
|
33
|
+
sha256: string;
|
|
34
|
+
/** ISO 8601 timestamp when evidence was captured. */
|
|
35
|
+
timestamp: string;
|
|
36
|
+
/** Path to the file, relative to the project root. */
|
|
37
|
+
path: string;
|
|
38
|
+
/** IANA MIME type of the file (e.g. `"text/typescript"`, `"application/pdf"`). */
|
|
39
|
+
mime?: string;
|
|
40
|
+
/** Optional human-readable note about this evidence artifact. */
|
|
41
|
+
description?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Evidence for a log stream captured from a running process.
|
|
46
|
+
*
|
|
47
|
+
* The `sha256` is the content hash of the captured log text.
|
|
48
|
+
*/
|
|
49
|
+
export interface LogEvidence {
|
|
50
|
+
kind: 'log';
|
|
51
|
+
/** SHA-256 hex digest of the captured log content. */
|
|
52
|
+
sha256: string;
|
|
53
|
+
/** ISO 8601 timestamp when evidence was captured. */
|
|
54
|
+
timestamp: string;
|
|
55
|
+
/**
|
|
56
|
+
* Source process name or description (e.g. `"pnpm test"`, `"node server.js"`).
|
|
57
|
+
*/
|
|
58
|
+
source: string;
|
|
59
|
+
/** Optional human-readable note about this log artifact. */
|
|
60
|
+
description?: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Evidence for a screenshot or visual capture taken during verification.
|
|
65
|
+
*
|
|
66
|
+
* Used for manual gates and UI smoke tests. The `sha256` references the
|
|
67
|
+
* image blob in the attachment store.
|
|
68
|
+
*/
|
|
69
|
+
export interface ScreenshotEvidence {
|
|
70
|
+
kind: 'screenshot';
|
|
71
|
+
/** SHA-256 hex digest of the image file. */
|
|
72
|
+
sha256: string;
|
|
73
|
+
/** ISO 8601 timestamp when evidence was captured. */
|
|
74
|
+
timestamp: string;
|
|
75
|
+
/**
|
|
76
|
+
* MIME type of the image.
|
|
77
|
+
*
|
|
78
|
+
* @defaultValue "image/png"
|
|
79
|
+
*/
|
|
80
|
+
mime?: 'image/png' | 'image/jpeg' | 'image/webp';
|
|
81
|
+
/** Optional human-readable note (e.g. `"dark mode toggle on macOS Chrome"`). */
|
|
82
|
+
description?: string;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Evidence for structured test-runner output.
|
|
87
|
+
*
|
|
88
|
+
* Carries the summary metrics from the test run alongside the SHA-256
|
|
89
|
+
* reference to the full output blob.
|
|
90
|
+
*/
|
|
91
|
+
export interface TestOutputEvidence {
|
|
92
|
+
kind: 'test-output';
|
|
93
|
+
/** SHA-256 hex digest of the full test-runner output. */
|
|
94
|
+
sha256: string;
|
|
95
|
+
/** ISO 8601 timestamp when evidence was captured. */
|
|
96
|
+
timestamp: string;
|
|
97
|
+
/** Number of tests that passed. */
|
|
98
|
+
passed: number;
|
|
99
|
+
/** Number of tests that failed. */
|
|
100
|
+
failed: number;
|
|
101
|
+
/** Number of tests skipped or pending. */
|
|
102
|
+
skipped: number;
|
|
103
|
+
/** Exit code of the test process. */
|
|
104
|
+
exitCode: number;
|
|
105
|
+
/** Optional human-readable note about the test run. */
|
|
106
|
+
description?: string;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Evidence for raw stdout/stderr output from a shell command.
|
|
111
|
+
*
|
|
112
|
+
* The `sha256` references the full output blob in the attachment store.
|
|
113
|
+
*/
|
|
114
|
+
export interface CommandOutputEvidence {
|
|
115
|
+
kind: 'command-output';
|
|
116
|
+
/** SHA-256 hex digest of the full command output. */
|
|
117
|
+
sha256: string;
|
|
118
|
+
/** ISO 8601 timestamp when evidence was captured. */
|
|
119
|
+
timestamp: string;
|
|
120
|
+
/** The command that was run (e.g. `"pnpm run build"`). */
|
|
121
|
+
cmd: string;
|
|
122
|
+
/** Exit code of the command process. */
|
|
123
|
+
exitCode: number;
|
|
124
|
+
/** Optional human-readable note about the command run. */
|
|
125
|
+
description?: string;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ─── Discriminated union ──────────────────────────────────────────────────────
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* A typed evidence artifact attached to a verification record.
|
|
132
|
+
*
|
|
133
|
+
* Replaces the bare `evidence?: string` field on {@link AcceptanceGateResult}
|
|
134
|
+
* with structured, kind-specific references backed by the attachment store.
|
|
135
|
+
*
|
|
136
|
+
* The `kind` field is the discriminant. All variants carry `sha256` (the
|
|
137
|
+
* attachment store ref), `timestamp`, and optional `description`.
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```ts
|
|
141
|
+
* const ev: TaskEvidence = {
|
|
142
|
+
* kind: 'test-output',
|
|
143
|
+
* sha256: 'a1b2c3...ff',
|
|
144
|
+
* timestamp: '2026-04-15T10:00:00.000Z',
|
|
145
|
+
* passed: 42,
|
|
146
|
+
* failed: 0,
|
|
147
|
+
* skipped: 2,
|
|
148
|
+
* exitCode: 0,
|
|
149
|
+
* };
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
export type TaskEvidence =
|
|
153
|
+
| FileEvidence
|
|
154
|
+
| LogEvidence
|
|
155
|
+
| ScreenshotEvidence
|
|
156
|
+
| TestOutputEvidence
|
|
157
|
+
| CommandOutputEvidence;
|
|
158
|
+
|
|
159
|
+
/** All valid `kind` discriminants for `TaskEvidence`. */
|
|
160
|
+
export type TaskEvidenceKind = TaskEvidence['kind'];
|
|
161
|
+
|
|
162
|
+
// ─── Zod schemas ─────────────────────────────────────────────────────────────
|
|
163
|
+
|
|
164
|
+
/** Zod schema for {@link FileEvidence}. */
|
|
165
|
+
export const fileEvidenceSchema = z.object({
|
|
166
|
+
kind: z.literal('file'),
|
|
167
|
+
sha256: z.string().length(64),
|
|
168
|
+
timestamp: z.string().datetime(),
|
|
169
|
+
path: z.string().min(1),
|
|
170
|
+
mime: z.string().optional(),
|
|
171
|
+
description: z.string().optional(),
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
/** Zod schema for {@link LogEvidence}. */
|
|
175
|
+
export const logEvidenceSchema = z.object({
|
|
176
|
+
kind: z.literal('log'),
|
|
177
|
+
sha256: z.string().length(64),
|
|
178
|
+
timestamp: z.string().datetime(),
|
|
179
|
+
source: z.string().min(1),
|
|
180
|
+
description: z.string().optional(),
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
/** Zod schema for {@link ScreenshotEvidence}. */
|
|
184
|
+
export const screenshotEvidenceSchema = z.object({
|
|
185
|
+
kind: z.literal('screenshot'),
|
|
186
|
+
sha256: z.string().length(64),
|
|
187
|
+
timestamp: z.string().datetime(),
|
|
188
|
+
mime: z.enum(['image/png', 'image/jpeg', 'image/webp']).optional(),
|
|
189
|
+
description: z.string().optional(),
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
/** Zod schema for {@link TestOutputEvidence}. */
|
|
193
|
+
export const testOutputEvidenceSchema = z.object({
|
|
194
|
+
kind: z.literal('test-output'),
|
|
195
|
+
sha256: z.string().length(64),
|
|
196
|
+
timestamp: z.string().datetime(),
|
|
197
|
+
passed: z.number().int().nonnegative(),
|
|
198
|
+
failed: z.number().int().nonnegative(),
|
|
199
|
+
skipped: z.number().int().nonnegative(),
|
|
200
|
+
exitCode: z.number().int(),
|
|
201
|
+
description: z.string().optional(),
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
/** Zod schema for {@link CommandOutputEvidence}. */
|
|
205
|
+
export const commandOutputEvidenceSchema = z.object({
|
|
206
|
+
kind: z.literal('command-output'),
|
|
207
|
+
sha256: z.string().length(64),
|
|
208
|
+
timestamp: z.string().datetime(),
|
|
209
|
+
cmd: z.string().min(1),
|
|
210
|
+
exitCode: z.number().int(),
|
|
211
|
+
description: z.string().optional(),
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Zod discriminated-union schema for {@link TaskEvidence}.
|
|
216
|
+
*
|
|
217
|
+
* Uses `z.discriminatedUnion('kind', [...])` for O(1) variant lookup.
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* ```ts
|
|
221
|
+
* const ev = taskEvidenceSchema.parse({
|
|
222
|
+
* kind: 'command-output',
|
|
223
|
+
* sha256: 'a'.repeat(64),
|
|
224
|
+
* timestamp: '2026-04-15T10:00:00.000Z',
|
|
225
|
+
* cmd: 'pnpm run build',
|
|
226
|
+
* exitCode: 0,
|
|
227
|
+
* });
|
|
228
|
+
* ```
|
|
229
|
+
*/
|
|
230
|
+
export const taskEvidenceSchema = z.discriminatedUnion('kind', [
|
|
231
|
+
fileEvidenceSchema,
|
|
232
|
+
logEvidenceSchema,
|
|
233
|
+
screenshotEvidenceSchema,
|
|
234
|
+
testOutputEvidenceSchema,
|
|
235
|
+
commandOutputEvidenceSchema,
|
|
236
|
+
]);
|
|
237
|
+
|
|
238
|
+
/** Inferred TypeScript type from {@link taskEvidenceSchema}. */
|
|
239
|
+
export type TaskEvidenceInput = z.input<typeof taskEvidenceSchema>;
|