@cat-factory/contracts 0.262.0 → 0.263.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/pr-report.d.ts +29 -1
- package/dist/pr-report.d.ts.map +1 -1
- package/dist/pr-report.js +15 -1
- package/dist/pr-report.js.map +1 -1
- package/dist/routes/_shared.d.ts +16 -0
- package/dist/routes/_shared.d.ts.map +1 -1
- package/dist/routes/_shared.js +15 -0
- package/dist/routes/_shared.js.map +1 -1
- package/dist/routes/debug-api.d.ts +18 -0
- package/dist/routes/debug-api.d.ts.map +1 -1
- package/dist/routes/debug-api.js +19 -19
- package/dist/routes/debug-api.js.map +1 -1
- package/dist/routes/notification-webhooks.d.ts +6 -0
- package/dist/routes/notification-webhooks.d.ts.map +1 -1
- package/dist/routes/notification-webhooks.js +7 -7
- package/dist/routes/notification-webhooks.js.map +1 -1
- package/dist/routes/public-api.d.ts +48 -0
- package/dist/routes/public-api.d.ts.map +1 -1
- package/dist/routes/public-api.js +50 -50
- package/dist/routes/public-api.js.map +1 -1
- package/dist/routes/public-decisions.d.ts +82 -0
- package/dist/routes/public-decisions.d.ts.map +1 -1
- package/dist/routes/public-decisions.js +83 -83
- package/dist/routes/public-decisions.js.map +1 -1
- package/dist/routes/public-evidence.d.ts +125 -0
- package/dist/routes/public-evidence.d.ts.map +1 -1
- package/dist/routes/public-evidence.js +26 -5
- package/dist/routes/public-evidence.js.map +1 -1
- package/dist/routes/spec.d.ts +84 -0
- package/dist/routes/spec.d.ts.map +1 -1
- package/dist/routes/spec.js +15 -0
- package/dist/routes/spec.js.map +1 -1
- package/dist/run-evidence.d.ts +152 -0
- package/dist/run-evidence.d.ts.map +1 -0
- package/dist/run-evidence.js +192 -0
- package/dist/run-evidence.js.map +1 -0
- package/dist/run-outcome.d.ts +370 -0
- package/dist/run-outcome.d.ts.map +1 -0
- package/dist/run-outcome.js +540 -0
- package/dist/run-outcome.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,540 @@
|
|
|
1
|
+
import * as v from 'valibot';
|
|
2
|
+
import { allPullRequests } from './entities.js';
|
|
3
|
+
import { reproductionStatusSchema } from './reproduction.js';
|
|
4
|
+
import { indexRequirementVerdicts, isRequirementRegression, isTesterKind, joinSpecRequirements, selectTesterReportStep, tallyRequirements, tallyTestOutcomes, unmatchedVerdictIds, } from './run-evidence.js';
|
|
5
|
+
import { requirementStateSchema } from './spec.js';
|
|
6
|
+
import { requirementVerdictStatusSchema, testConcernSeveritySchema } from './testing.js';
|
|
7
|
+
import { testEnvironmentSchema } from './testing.js';
|
|
8
|
+
import { UI_TESTER_AGENT_KIND } from './visual-pipeline.js';
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// The RUN OUTCOME summary: the non-code answer to "what did this run change, and what backs
|
|
11
|
+
// that up".
|
|
12
|
+
//
|
|
13
|
+
// Reading a finished run used to mean reading a pull request: a branch name, a title, and a
|
|
14
|
+
// diff. Everything a person who does not read diffs needs was already captured (the tester's
|
|
15
|
+
// structured report, the screenshots it took, the visual-confirmation pairs a human reviewed,
|
|
16
|
+
// the per-requirement verdicts it returned) and each of those sat behind its own window, keyed
|
|
17
|
+
// by the STEP that produced it, so nobody who had not already learned the pipeline could find
|
|
18
|
+
// any of it. This module is the reduction that puts them in one place, keyed by the RUN.
|
|
19
|
+
//
|
|
20
|
+
// It lives in `@cat-factory/contracts` because it has THREE consumers that must agree: the SPA's
|
|
21
|
+
// outcome card, `GET /api/v1/runs/:runId/outcome`, and the engine's PR verification report, which
|
|
22
|
+
// reduces the same evidence for a reviewer. The first two are the same reduction and would be two
|
|
23
|
+
// copies of it anywhere else; the third is a different document, and the RULES it shares with
|
|
24
|
+
// this one (which tester steps count, what a regression is, how coverage is counted) live in
|
|
25
|
+
// `run-evidence.ts` so neither restates them. See that module's header for the three places the
|
|
26
|
+
// two had already drifted before it existed.
|
|
27
|
+
//
|
|
28
|
+
// Three rules shape what is here, and they are the reason it is a pure module rather than
|
|
29
|
+
// computation inside the window that renders it:
|
|
30
|
+
//
|
|
31
|
+
// 1. **Nothing here is asserted.** Every field is read off state a producer already recorded,
|
|
32
|
+
// or COUNTED from it. The one derived judgement (a regression: an `established` requirement
|
|
33
|
+
// the tester observed to fail) is computed in code from the spec's state and the tester's
|
|
34
|
+
// verdict, so a reader can re-derive it from the rows. No model is asked for a headline.
|
|
35
|
+
// 2. **Absent and zero never render the same.** Every section is a discriminated union whose
|
|
36
|
+
// `absent` arm carries a `gap` CODE (mapped to translated copy at the render site, never
|
|
37
|
+
// prose from here), because "no tester ran" and "the tester found nothing wrong" are
|
|
38
|
+
// opposite facts that a blank section states identically.
|
|
39
|
+
// 3. **The join to the spec is optional and says when it did not happen.** Coverage is counted
|
|
40
|
+
// over the service's `spec/`, so a requirement nobody looked at is reported as unchecked
|
|
41
|
+
// rather than being invisible; without the spec there is no such denominator, and
|
|
42
|
+
// `spec: 'not_read'` says the ids the tester keyed its verdicts by are all there is rather
|
|
43
|
+
// than letting an id read as the requirement's name.
|
|
44
|
+
//
|
|
45
|
+
// SINCE THIS SHAPE IS SERVED AT `GET /api/v1/runs/:runId/outcome`, it is part of the STABLE
|
|
46
|
+
// public surface: it grows by ADDITION (a new section, a new optional field, a new enum member)
|
|
47
|
+
// and never by renaming, retyping or removing in place.
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
/**
|
|
50
|
+
* The wire version of the outcome payload. Bumped when the shape gains something an external
|
|
51
|
+
* consumer would want to notice; never a compatibility switch (the surface is additive, so a
|
|
52
|
+
* consumer written against an older number keeps reading the fields it knows).
|
|
53
|
+
*/
|
|
54
|
+
export const RUN_OUTCOME_VERSION = 1;
|
|
55
|
+
/**
|
|
56
|
+
* Where the run stands, in the terms the person reading the outcome cares about. Derived from
|
|
57
|
+
* the BLOCK's status first (it is what the merge lifecycle writes) and from the run only for
|
|
58
|
+
* the states a block cannot distinguish.
|
|
59
|
+
*/
|
|
60
|
+
export const outcomeDispositionSchema = v.picklist([
|
|
61
|
+
'merged',
|
|
62
|
+
'awaiting_merge',
|
|
63
|
+
'in_flight',
|
|
64
|
+
'needs_attention',
|
|
65
|
+
'not_run',
|
|
66
|
+
/**
|
|
67
|
+
* The block names a run nobody resolved (see {@link runUnavailableGap}), and its status is
|
|
68
|
+
* not one the merge lifecycle writes. What the run did is exactly the fact a block alone
|
|
69
|
+
* cannot carry, and `not_run` would be this summary's most visible lie.
|
|
70
|
+
*/
|
|
71
|
+
'unknown',
|
|
72
|
+
]);
|
|
73
|
+
/** One pull request the run opened: the own-service PR, plus a peer PR per connected repo. */
|
|
74
|
+
export const outcomePullRequestSchema = v.object({
|
|
75
|
+
url: v.string(),
|
|
76
|
+
number: v.nullable(v.number()),
|
|
77
|
+
branch: v.nullable(v.string()),
|
|
78
|
+
/** `owner/name` for a PEER repo's PR; null for the task's own service. */
|
|
79
|
+
repo: v.nullable(v.string()),
|
|
80
|
+
});
|
|
81
|
+
// ---- Requirement coverage --------------------------------------------------
|
|
82
|
+
/**
|
|
83
|
+
* The gap EVERY evidence section shares: the block names a run (`block.executionId`) the
|
|
84
|
+
* caller could not resolve, so nothing any step recorded is knowable here.
|
|
85
|
+
*
|
|
86
|
+
* It is kept apart from every other gap in this module, which report what a RESOLVED run did
|
|
87
|
+
* or did not produce. "The store does not have this run" and "this pipeline has no tester
|
|
88
|
+
* step" are opposite facts about opposite things, and a summary that reported the second for
|
|
89
|
+
* the first would blame the pipeline for a read that never happened, on the one surface whose
|
|
90
|
+
* whole job is to say what is known and what is not.
|
|
91
|
+
*/
|
|
92
|
+
export const runUnavailableGap = 'run_unavailable';
|
|
93
|
+
/** Why there is no requirement coverage to show. Each needs a different reaction. */
|
|
94
|
+
export const requirementsGapSchema = v.picklist([
|
|
95
|
+
runUnavailableGap,
|
|
96
|
+
'no_tester_step',
|
|
97
|
+
'tester_not_reported',
|
|
98
|
+
/** No spec to count against, and no verdict either: there is nothing at all to show. */
|
|
99
|
+
'no_verdicts',
|
|
100
|
+
/**
|
|
101
|
+
* The spec WAS read, records no requirements, and no tester verdict stands against it either,
|
|
102
|
+
* so there was nothing to rule on. A spec declaring nothing while the tester DID return
|
|
103
|
+
* verdicts is a reported section instead, counting 0 requirements with every verdict
|
|
104
|
+
* unmatched: those rulings are evidence, and calling them an absence would discard them.
|
|
105
|
+
*/
|
|
106
|
+
'no_requirements',
|
|
107
|
+
]);
|
|
108
|
+
/**
|
|
109
|
+
* Whether the coverage was counted against the service's `spec/`, or only against the ids the
|
|
110
|
+
* tester keyed its verdicts by.
|
|
111
|
+
*
|
|
112
|
+
* `joined` is the real answer: every requirement the service declares is a row, so one nobody
|
|
113
|
+
* looked at is reported as unchecked. `not_read` is the degraded one, and it is a different
|
|
114
|
+
* DENOMINATOR rather than a cosmetic loss of titles: the counts describe what the tester ruled
|
|
115
|
+
* on and say nothing about what it skipped. It is a real state on both consumers (the SPA
|
|
116
|
+
* renders before its spec fetch lands; a deployment with no VCS wired can never read one), so
|
|
117
|
+
* it is stated rather than collapsed into an absence.
|
|
118
|
+
*/
|
|
119
|
+
export const outcomeSpecJoinSchema = v.picklist(['joined', 'not_read']);
|
|
120
|
+
/** One requirement, paired with what the tester observed about it. */
|
|
121
|
+
export const outcomeRequirementSchema = v.object({
|
|
122
|
+
/** The spec requirement id: the join key, and all there is when the spec was not read. */
|
|
123
|
+
id: v.string(),
|
|
124
|
+
/** The requirement's headline from `spec/`; null on an unjoined row. */
|
|
125
|
+
title: v.nullable(v.string()),
|
|
126
|
+
verdict: requirementVerdictStatusSchema,
|
|
127
|
+
/** What the tester observed, when it said. */
|
|
128
|
+
detail: v.nullable(v.string()),
|
|
129
|
+
/** Implementation state as `spec/` recorded it, or null when unjoined. */
|
|
130
|
+
state: v.nullable(requirementStateSchema),
|
|
131
|
+
/**
|
|
132
|
+
* An `established` requirement the tester observed to FAIL: behaviour the platform had
|
|
133
|
+
* previously seen hold and no longer does. Computed here, never read off a report, and the
|
|
134
|
+
* one reading of this section that says the change BROKE something rather than merely not
|
|
135
|
+
* finishing it. An `aspirational` requirement failing is in-flight work, not a regression.
|
|
136
|
+
*/
|
|
137
|
+
regression: v.boolean(),
|
|
138
|
+
});
|
|
139
|
+
export const outcomeRequirementsSchema = v.variant('status', [
|
|
140
|
+
v.object({ status: v.literal('absent'), gap: requirementsGapSchema }),
|
|
141
|
+
v.object({
|
|
142
|
+
status: v.literal('reported'),
|
|
143
|
+
/** What the counts below are counted over. See {@link outcomeSpecJoinSchema}. */
|
|
144
|
+
spec: outcomeSpecJoinSchema,
|
|
145
|
+
met: v.number(),
|
|
146
|
+
notMet: v.number(),
|
|
147
|
+
notCovered: v.number(),
|
|
148
|
+
/** A SUBSET of `notMet`; see {@link outcomeRequirementSchema.entries.regression}. */
|
|
149
|
+
regressions: v.number(),
|
|
150
|
+
/**
|
|
151
|
+
* `met + notMet + notCovered`, and the DENOMINATOR the three are read against. Carried rather
|
|
152
|
+
* than left to the reader to add up, because what it counts depends on `spec`: joined, it is
|
|
153
|
+
* every requirement the service declares; unjoined, only the ones the tester ruled on.
|
|
154
|
+
*/
|
|
155
|
+
total: v.number(),
|
|
156
|
+
/**
|
|
157
|
+
* Verdicts the tester returned against ids the spec does not carry, which the join can
|
|
158
|
+
* neither place nor count. Non-zero means the spec moved on under the tester (or that it
|
|
159
|
+
* keyed its verdicts by something else), and a reader comparing the totals to the tester's
|
|
160
|
+
* own report needs to know the difference is not a miscount. Always 0 on a `not_read`
|
|
161
|
+
* section, where there is nothing to match against.
|
|
162
|
+
*/
|
|
163
|
+
unmatchedVerdicts: v.number(),
|
|
164
|
+
/** Regressions first, then failures, then what was met, then what nobody checked. */
|
|
165
|
+
entries: v.array(outcomeRequirementSchema),
|
|
166
|
+
}),
|
|
167
|
+
]);
|
|
168
|
+
// ---- The tester's report ---------------------------------------------------
|
|
169
|
+
export const testsGapSchema = v.picklist([
|
|
170
|
+
runUnavailableGap,
|
|
171
|
+
'no_tester_step',
|
|
172
|
+
'tester_not_reported',
|
|
173
|
+
]);
|
|
174
|
+
/**
|
|
175
|
+
* The tester's disposition. `could_not_run` is kept apart from `concerns` because they call
|
|
176
|
+
* for opposite reactions: one is a change with bugs in it, the other is a change nobody
|
|
177
|
+
* managed to exercise at all, and a report that collapses them reads as tested either way.
|
|
178
|
+
*/
|
|
179
|
+
export const testsVerdictSchema = v.picklist(['greenlit', 'concerns', 'could_not_run']);
|
|
180
|
+
export const outcomeConcernSchema = v.object({
|
|
181
|
+
title: v.string(),
|
|
182
|
+
severity: testConcernSeveritySchema,
|
|
183
|
+
});
|
|
184
|
+
export const outcomeTestsSchema = v.variant('status', [
|
|
185
|
+
v.object({ status: v.literal('absent'), gap: testsGapSchema }),
|
|
186
|
+
v.object({
|
|
187
|
+
status: v.literal('reported'),
|
|
188
|
+
verdict: testsVerdictSchema,
|
|
189
|
+
/** The tester's own prose about the session, attributed as such at the render site. */
|
|
190
|
+
summary: v.nullable(v.string()),
|
|
191
|
+
/** Verbatim reason the tester could not run at all; null unless `could_not_run`. */
|
|
192
|
+
abortReason: v.nullable(v.string()),
|
|
193
|
+
/** What it exercised, by name. */
|
|
194
|
+
areas: v.array(v.string()),
|
|
195
|
+
passed: v.number(),
|
|
196
|
+
failed: v.number(),
|
|
197
|
+
skipped: v.number(),
|
|
198
|
+
concerns: v.array(outcomeConcernSchema),
|
|
199
|
+
environment: v.nullable(testEnvironmentSchema),
|
|
200
|
+
}),
|
|
201
|
+
]);
|
|
202
|
+
// ---- What it looked like ---------------------------------------------------
|
|
203
|
+
export const visualsGapSchema = v.picklist([runUnavailableGap, 'no_visual_step', 'none_captured']);
|
|
204
|
+
/** One captured view, paired with the reference design it was reviewed against when there is one. */
|
|
205
|
+
export const outcomeVisualSchema = v.object({
|
|
206
|
+
view: v.string(),
|
|
207
|
+
artifactId: v.nullable(v.string()),
|
|
208
|
+
referenceArtifactId: v.nullable(v.string()),
|
|
209
|
+
});
|
|
210
|
+
export const outcomeVisualsSchema = v.variant('status', [
|
|
211
|
+
v.object({
|
|
212
|
+
status: v.literal('absent'),
|
|
213
|
+
gap: visualsGapSchema,
|
|
214
|
+
/** The gate's own verbatim explanation, when it recorded one. Detail, never the headline. */
|
|
215
|
+
detail: v.nullable(v.string()),
|
|
216
|
+
}),
|
|
217
|
+
v.object({
|
|
218
|
+
status: v.literal('reported'),
|
|
219
|
+
/**
|
|
220
|
+
* Which producer the views came from. `visual_confirm` pairs were put in front of a
|
|
221
|
+
* human and carry a verdict; `tester` shots are captures nobody was asked about, and the
|
|
222
|
+
* summary must not let the second read as the first.
|
|
223
|
+
*/
|
|
224
|
+
source: v.picklist(['visual_confirm', 'tester']),
|
|
225
|
+
/** The gate's phase when the views came from it: awaiting a human, fixing, or approved. */
|
|
226
|
+
phase: v.nullable(v.picklist(['awaiting_human', 'fixing', 'approved'])),
|
|
227
|
+
views: v.array(outcomeVisualSchema),
|
|
228
|
+
}),
|
|
229
|
+
]);
|
|
230
|
+
// ---- The machine checks ----------------------------------------------------
|
|
231
|
+
/** The three recorded machine verdicts a non-code reader still needs: did it build, does it work. */
|
|
232
|
+
export const outcomeCheckKindSchema = v.picklist(['ci', 'validation', 'reproduction']);
|
|
233
|
+
export const outcomeCheckStateSchema = v.picklist(['pass', 'fail', 'pending', 'inconclusive']);
|
|
234
|
+
export const outcomeCheckSchema = v.object({
|
|
235
|
+
kind: outcomeCheckKindSchema,
|
|
236
|
+
state: outcomeCheckStateSchema,
|
|
237
|
+
/**
|
|
238
|
+
* The producer's own qualifier, when the state alone would under-report it: the reproduction
|
|
239
|
+
* verdict that earned an `inconclusive`. Rendered through an exhaustive map, never as prose.
|
|
240
|
+
*/
|
|
241
|
+
reproduction: v.nullable(reproductionStatusSchema),
|
|
242
|
+
});
|
|
243
|
+
// ---- The whole summary -----------------------------------------------------
|
|
244
|
+
export const runOutcomeSchema = v.object({
|
|
245
|
+
/** See {@link RUN_OUTCOME_VERSION}. */
|
|
246
|
+
version: v.number(),
|
|
247
|
+
disposition: outcomeDispositionSchema,
|
|
248
|
+
/** The task's title: the product-language name of what was asked for. */
|
|
249
|
+
title: v.string(),
|
|
250
|
+
/** The requester's own description of the ask, trimmed; null when the task carried none. */
|
|
251
|
+
ask: v.nullable(v.string()),
|
|
252
|
+
/** Every PR the run opened, so the diff stays exactly one click from the summary. */
|
|
253
|
+
pullRequests: v.array(outcomePullRequestSchema),
|
|
254
|
+
requirements: outcomeRequirementsSchema,
|
|
255
|
+
tests: outcomeTestsSchema,
|
|
256
|
+
visuals: outcomeVisualsSchema,
|
|
257
|
+
/** Only the checks that actually ran: an absent check is omitted, never rendered as passing. */
|
|
258
|
+
checks: v.array(outcomeCheckSchema),
|
|
259
|
+
/**
|
|
260
|
+
* What a BOUNDED rendering of this summary had to leave out, one note per capped list
|
|
261
|
+
* (`"requirements.entries: showing 200 of 480"`), in the same vocabulary the verification
|
|
262
|
+
* report's own `truncations` uses. Empty whenever nothing was dropped, which is every
|
|
263
|
+
* ordinary run and every composition the SPA does (it renders from state it already holds and
|
|
264
|
+
* caps nothing).
|
|
265
|
+
*
|
|
266
|
+
* It exists because the counts above are computed over the WHOLE join, before any cap: a
|
|
267
|
+
* consumer that found 200 rows under a `total` of 480 and no note would have to guess whether
|
|
268
|
+
* the tail was never ruled on. A cap that is not a plain prefix says so in its note, since
|
|
269
|
+
* `entries` is ordered by SEVERITY and the rows a cap drops are therefore the least severe
|
|
270
|
+
* ones rather than the end of the spec.
|
|
271
|
+
*/
|
|
272
|
+
truncations: v.array(v.string()),
|
|
273
|
+
});
|
|
274
|
+
/**
|
|
275
|
+
* Parse-or-throw an outcome payload, for any consumer proving the JSON it holds is this shape.
|
|
276
|
+
*/
|
|
277
|
+
export function parseRunOutcome(value) {
|
|
278
|
+
return v.parse(runOutcomeSchema, value);
|
|
279
|
+
}
|
|
280
|
+
/** Regressions first, then failures, then what held, then what nobody checked. */
|
|
281
|
+
const VERDICT_ORDER = {
|
|
282
|
+
not_met: 1,
|
|
283
|
+
met: 2,
|
|
284
|
+
not_covered: 3,
|
|
285
|
+
};
|
|
286
|
+
/** Project one joined row onto the summary's narrower row. */
|
|
287
|
+
function toOutcomeRequirement(row) {
|
|
288
|
+
return {
|
|
289
|
+
id: row.id,
|
|
290
|
+
title: row.title,
|
|
291
|
+
verdict: row.verdict,
|
|
292
|
+
detail: row.detail,
|
|
293
|
+
state: row.state,
|
|
294
|
+
regression: isRequirementRegression(row),
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
/** Severity first, then alphabetically by whatever the row can be named by. */
|
|
298
|
+
function bySeverity(a, b) {
|
|
299
|
+
if (a.regression !== b.regression)
|
|
300
|
+
return a.regression ? -1 : 1;
|
|
301
|
+
const order = VERDICT_ORDER[a.verdict] - VERDICT_ORDER[b.verdict];
|
|
302
|
+
return order !== 0 ? order : (a.title ?? a.id).localeCompare(b.title ?? b.id);
|
|
303
|
+
}
|
|
304
|
+
function composeRequirements(steps, spec) {
|
|
305
|
+
const testers = steps.filter((step) => isTesterKind(step.agentKind));
|
|
306
|
+
if (testers.length === 0)
|
|
307
|
+
return { status: 'absent', gap: 'no_tester_step' };
|
|
308
|
+
if (!testers.some((step) => step.test?.lastReport)) {
|
|
309
|
+
return { status: 'absent', gap: 'tester_not_reported' };
|
|
310
|
+
}
|
|
311
|
+
// Every tester step's verdicts, not just the reporting one's: a pipeline carrying `tester-api`
|
|
312
|
+
// beside `tester-ui` is ruled on by both, and this is the same index the PR verification
|
|
313
|
+
// report joins against.
|
|
314
|
+
const verdicts = indexRequirementVerdicts(steps);
|
|
315
|
+
const doc = spec?.spec ?? null;
|
|
316
|
+
if (!doc) {
|
|
317
|
+
// No denominator to count against. The rows are the tester's own verdicts, which is a
|
|
318
|
+
// narrower statement than the joined section makes and is labelled as one.
|
|
319
|
+
if (verdicts.size === 0)
|
|
320
|
+
return { status: 'absent', gap: 'no_verdicts' };
|
|
321
|
+
const entries = [...verdicts.values()]
|
|
322
|
+
.map((verdict) => ({
|
|
323
|
+
id: verdict.requirementId,
|
|
324
|
+
title: null,
|
|
325
|
+
verdict: verdict.status,
|
|
326
|
+
detail: verdict.detail?.trim() || null,
|
|
327
|
+
state: null,
|
|
328
|
+
regression: false,
|
|
329
|
+
}))
|
|
330
|
+
.sort(bySeverity);
|
|
331
|
+
return {
|
|
332
|
+
status: 'reported',
|
|
333
|
+
spec: 'not_read',
|
|
334
|
+
met: entries.filter((e) => e.verdict === 'met').length,
|
|
335
|
+
notMet: entries.filter((e) => e.verdict === 'not_met').length,
|
|
336
|
+
notCovered: entries.filter((e) => e.verdict === 'not_covered').length,
|
|
337
|
+
regressions: 0,
|
|
338
|
+
total: entries.length,
|
|
339
|
+
unmatchedVerdicts: 0,
|
|
340
|
+
entries,
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
const rows = joinSpecRequirements(doc, verdicts);
|
|
344
|
+
const unmatched = unmatchedVerdictIds(rows, verdicts);
|
|
345
|
+
// The spec was read and declares nothing, and no tester ruled on anything either: there is
|
|
346
|
+
// genuinely no coverage to state. An empty join with verdicts standing against it is NOT this
|
|
347
|
+
// case — it is a spec that moved on under the run, and reporting it as an absence would throw
|
|
348
|
+
// away every ruling the tester made and claim there was nothing to rule on.
|
|
349
|
+
if (rows.length === 0 && unmatched.length === 0) {
|
|
350
|
+
return { status: 'absent', gap: 'no_requirements' };
|
|
351
|
+
}
|
|
352
|
+
const tally = tallyRequirements(rows);
|
|
353
|
+
return {
|
|
354
|
+
status: 'reported',
|
|
355
|
+
spec: 'joined',
|
|
356
|
+
...tally,
|
|
357
|
+
// A verdict the join could not place is REPORTED rather than dropped: it is the difference
|
|
358
|
+
// between the tester's own count and this section's, and silence about it reads as a
|
|
359
|
+
// miscount in whichever of the two the reader trusts less.
|
|
360
|
+
unmatchedVerdicts: unmatched.length,
|
|
361
|
+
entries: rows.map(toOutcomeRequirement).sort(bySeverity),
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
function composeTests(step) {
|
|
365
|
+
if (!step)
|
|
366
|
+
return { status: 'absent', gap: 'no_tester_step' };
|
|
367
|
+
const report = step.test?.lastReport;
|
|
368
|
+
if (!report)
|
|
369
|
+
return { status: 'absent', gap: 'tester_not_reported' };
|
|
370
|
+
const abortReason = report.abort?.reason?.trim() || null;
|
|
371
|
+
return {
|
|
372
|
+
status: 'reported',
|
|
373
|
+
verdict: abortReason ? 'could_not_run' : report.greenlight ? 'greenlit' : 'concerns',
|
|
374
|
+
summary: report.summary?.trim() || null,
|
|
375
|
+
abortReason,
|
|
376
|
+
areas: [...report.tested],
|
|
377
|
+
...tallyTestOutcomes(report),
|
|
378
|
+
concerns: report.concerns.map((concern) => ({
|
|
379
|
+
title: concern.title,
|
|
380
|
+
severity: concern.severity,
|
|
381
|
+
})),
|
|
382
|
+
environment: report.environment ?? null,
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
function composeVisuals(steps, tester) {
|
|
386
|
+
// The visual-confirmation gate is preferred over the tester's raw captures: its pairs were
|
|
387
|
+
// put in FRONT of a human and carry the reference they were judged against.
|
|
388
|
+
const gate = steps.filter((s) => s.visualConfirm).at(-1)?.visualConfirm ?? null;
|
|
389
|
+
const pairs = (gate?.pairs ?? []).filter((p) => p.actualArtifactId || p.referenceArtifactId);
|
|
390
|
+
if (pairs.length > 0) {
|
|
391
|
+
return {
|
|
392
|
+
status: 'reported',
|
|
393
|
+
source: 'visual_confirm',
|
|
394
|
+
phase: gate?.phase ?? null,
|
|
395
|
+
views: pairs.map((p) => ({
|
|
396
|
+
view: p.view,
|
|
397
|
+
artifactId: p.actualArtifactId ?? null,
|
|
398
|
+
referenceArtifactId: p.referenceArtifactId ?? null,
|
|
399
|
+
})),
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
const shots = tester?.test?.lastReport?.screenshots ?? [];
|
|
403
|
+
if (shots.length > 0) {
|
|
404
|
+
return {
|
|
405
|
+
status: 'reported',
|
|
406
|
+
source: 'tester',
|
|
407
|
+
phase: null,
|
|
408
|
+
views: shots.map((s) => ({
|
|
409
|
+
view: s.view,
|
|
410
|
+
artifactId: s.artifactId,
|
|
411
|
+
referenceArtifactId: s.referenceArtifactId ?? null,
|
|
412
|
+
})),
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
// Nothing to show: say whether anything was ever meant to capture a view. A gate that ran
|
|
416
|
+
// and gathered nothing recorded WHY, and that reason is the whole answer for the reader.
|
|
417
|
+
//
|
|
418
|
+
// Asked of EVERY step, not of the tester whose report was selected: a pipeline can carry a
|
|
419
|
+
// `tester-ui` that has not reported beside a `tester-api` that has, and the selected step is
|
|
420
|
+
// then the api one. Reading the producer off it would tell a reader looking at a UI pipeline
|
|
421
|
+
// that nothing in it captures the interface.
|
|
422
|
+
const degraded = gate?.degradedReason?.trim() || null;
|
|
423
|
+
const hadProducer = Boolean(gate) || steps.some((s) => s.agentKind === UI_TESTER_AGENT_KIND);
|
|
424
|
+
return {
|
|
425
|
+
status: 'absent',
|
|
426
|
+
gap: hadProducer ? 'none_captured' : 'no_visual_step',
|
|
427
|
+
detail: degraded,
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
function composeChecks(steps) {
|
|
431
|
+
const checks = [];
|
|
432
|
+
const ci = steps.filter((s) => s.agentKind === 'ci' && s.gate).at(-1)?.gate ?? null;
|
|
433
|
+
// A CI gate that has not probed yet has no verdict to report; `pending` is what the gate
|
|
434
|
+
// itself records for "the checks are still running", so an unprobed gate is not folded onto it.
|
|
435
|
+
if (ci?.lastVerdict)
|
|
436
|
+
checks.push({ kind: 'ci', state: ci.lastVerdict, reproduction: null });
|
|
437
|
+
const validation = steps.filter((s) => s.validation).at(-1)?.validation ?? null;
|
|
438
|
+
if (validation) {
|
|
439
|
+
checks.push({
|
|
440
|
+
kind: 'validation',
|
|
441
|
+
state: validation.passed ? 'pass' : 'fail',
|
|
442
|
+
reproduction: null,
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
const reproduction = steps.filter((s) => s.reproduction).at(-1)?.reproduction ?? null;
|
|
446
|
+
if (reproduction) {
|
|
447
|
+
// Only red-on-the-pre-fix-tree then green-on-the-final-tree is proof; every other verdict
|
|
448
|
+
// is the absence of proof rather than a failure, which is why it is not a `fail`.
|
|
449
|
+
checks.push({
|
|
450
|
+
kind: 'reproduction',
|
|
451
|
+
state: reproduction.status === 'reproduced' ? 'pass' : 'inconclusive',
|
|
452
|
+
reproduction: reproduction.status,
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
return checks;
|
|
456
|
+
}
|
|
457
|
+
function composeDisposition(block, instance, unresolvedRun) {
|
|
458
|
+
if (block.status === 'done')
|
|
459
|
+
return 'merged';
|
|
460
|
+
if (block.status === 'pr_ready')
|
|
461
|
+
return 'awaiting_merge';
|
|
462
|
+
if (instance?.status === 'failed' || block.status === 'blocked')
|
|
463
|
+
return 'needs_attention';
|
|
464
|
+
// `in_progress` is the block's OWN word for a live run, so it stands whether or not the run
|
|
465
|
+
// itself resolved: the one in-flight reading that needs nothing from the instance.
|
|
466
|
+
if (instance || block.status === 'in_progress')
|
|
467
|
+
return 'in_flight';
|
|
468
|
+
return unresolvedRun ? 'unknown' : 'not_run';
|
|
469
|
+
}
|
|
470
|
+
function toOutcomePr(ref, repo) {
|
|
471
|
+
return {
|
|
472
|
+
url: ref.url,
|
|
473
|
+
number: ref.number ?? null,
|
|
474
|
+
branch: ref.branch ?? null,
|
|
475
|
+
repo: repo ?? null,
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Compose a run's outcome summary from what the run already carries. Pure: every input is a
|
|
480
|
+
* value the caller read off its store (the SPA) or off its repositories (the API), so the whole
|
|
481
|
+
* reduction unit-tests without mounting the window that renders it, and the two surfaces cannot
|
|
482
|
+
* answer the same question differently.
|
|
483
|
+
*/
|
|
484
|
+
export function composeRunOutcome({ block, instance, spec }) {
|
|
485
|
+
const steps = instance?.steps ?? [];
|
|
486
|
+
// The block names a run the caller could not resolve. Everything below is read off that run's
|
|
487
|
+
// steps, so composing from the empty list would report a pipeline that ran and produced
|
|
488
|
+
// nothing, the exact misreading this summary exists to prevent (see `runUnavailableGap`).
|
|
489
|
+
const unresolvedRun = !instance && Boolean(block.executionId);
|
|
490
|
+
const asked = {
|
|
491
|
+
version: RUN_OUTCOME_VERSION,
|
|
492
|
+
disposition: composeDisposition(block, instance, unresolvedRun),
|
|
493
|
+
title: block.title,
|
|
494
|
+
ask: block.description?.trim() || null,
|
|
495
|
+
// Read off the BLOCK, so they survive a run this summary cannot see: the pull request is
|
|
496
|
+
// what a merged task is usually reopened for, long after its run left the store.
|
|
497
|
+
pullRequests: allPullRequests(block).map(({ repo, ref }) => toOutcomePr(ref, repo)),
|
|
498
|
+
// This composition caps nothing: it reduces state the caller already holds in full. A
|
|
499
|
+
// consumer that BOUNDS the result for a wire fills this in and says what it dropped.
|
|
500
|
+
truncations: [],
|
|
501
|
+
};
|
|
502
|
+
if (unresolvedRun) {
|
|
503
|
+
return {
|
|
504
|
+
...asked,
|
|
505
|
+
requirements: { status: 'absent', gap: runUnavailableGap },
|
|
506
|
+
tests: { status: 'absent', gap: runUnavailableGap },
|
|
507
|
+
visuals: { status: 'absent', gap: runUnavailableGap, detail: null },
|
|
508
|
+
checks: [],
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
// The tester step whose report describes the work as it stands: the same selection the PR
|
|
512
|
+
// verification report's `tests` section makes, so the two never quote different sessions.
|
|
513
|
+
const tester = selectTesterReportStep(steps);
|
|
514
|
+
return {
|
|
515
|
+
...asked,
|
|
516
|
+
requirements: composeRequirements(steps, spec),
|
|
517
|
+
tests: composeTests(tester),
|
|
518
|
+
visuals: composeVisuals(steps, tester),
|
|
519
|
+
checks: composeChecks(steps),
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Whether a run has anything an outcome summary could show beyond the task's own title: a PR to
|
|
524
|
+
* open, or a step that recorded evidence. EVERY entry point asks this (the board card and the
|
|
525
|
+
* inspector alike, off the one reduction, so they can never disagree) so the affordance appears
|
|
526
|
+
* on a run that produced something and stays absent on one that has not yet, rather than
|
|
527
|
+
* offering a summary whose every section reads "nothing here".
|
|
528
|
+
*
|
|
529
|
+
* A run this summary could not resolve answers false unless the block still carries a pull
|
|
530
|
+
* request: there is nothing to show, and an affordance that opened onto four "not loaded"
|
|
531
|
+
* notices would be the same empty card by another route.
|
|
532
|
+
*/
|
|
533
|
+
export function hasOutcomeToShow(outcome) {
|
|
534
|
+
return (outcome.pullRequests.length > 0 ||
|
|
535
|
+
outcome.requirements.status === 'reported' ||
|
|
536
|
+
outcome.tests.status === 'reported' ||
|
|
537
|
+
outcome.visuals.status === 'reported' ||
|
|
538
|
+
outcome.checks.length > 0);
|
|
539
|
+
}
|
|
540
|
+
//# sourceMappingURL=run-outcome.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-outcome.js","sourceRoot":"","sources":["../src/run-outcome.ts"],"names":[],"mappings":"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"}
|