@variance-authority/report 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/LICENSE +21 -0
- package/README.md +258 -0
- package/dist/changelog-message.d.ts +51 -0
- package/dist/changelog-message.js +244 -0
- package/dist/changelog-message.js.map +1 -0
- package/dist/changelog.d.ts +231 -0
- package/dist/changelog.js +96 -0
- package/dist/changelog.js.map +1 -0
- package/dist/cluster.d.ts +112 -0
- package/dist/cluster.js +109 -0
- package/dist/cluster.js.map +1 -0
- package/dist/composition.d.ts +248 -0
- package/dist/composition.js +33 -0
- package/dist/composition.js.map +1 -0
- package/dist/declarations.d.ts +266 -0
- package/dist/declarations.js +212 -0
- package/dist/declarations.js.map +1 -0
- package/dist/file.d.ts +28 -0
- package/dist/file.js +151 -0
- package/dist/file.js.map +1 -0
- package/dist/finding-record.d.ts +64 -0
- package/dist/finding-record.js +14 -0
- package/dist/finding-record.js.map +1 -0
- package/dist/findings.d.ts +157 -0
- package/dist/findings.js +227 -0
- package/dist/findings.js.map +1 -0
- package/dist/format.d.ts +444 -0
- package/dist/format.js +2 -0
- package/dist/format.js.map +1 -0
- package/dist/history-records.d.ts +112 -0
- package/dist/history-records.js +16 -0
- package/dist/history-records.js.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/intent.d.ts +168 -0
- package/dist/intent.js +214 -0
- package/dist/intent.js.map +1 -0
- package/dist/presentation-record.d.ts +66 -0
- package/dist/presentation-record.js +9 -0
- package/dist/presentation-record.js.map +1 -0
- package/dist/promotion.d.ts +86 -0
- package/dist/promotion.js +104 -0
- package/dist/promotion.js.map +1 -0
- package/dist/reach.d.ts +154 -0
- package/dist/reach.js +47 -0
- package/dist/reach.js.map +1 -0
- package/dist/variation.d.ts +58 -0
- package/dist/variation.js +2 -0
- package/dist/variation.js.map +1 -0
- package/mark.svg +30 -0
- package/package.json +48 -0
package/dist/format.d.ts
ADDED
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
import type { AccessibilitySnapshot, ComponentBands, RenderIdentity } from '@variance-authority/core';
|
|
2
|
+
import type { FindingRecord } from './finding-record.js';
|
|
3
|
+
import type { CompositionReport } from './composition.js';
|
|
4
|
+
import type { IgnoreLedger, SensitivityLedger } from './declarations.js';
|
|
5
|
+
import type { ReachReport } from './reach.js';
|
|
6
|
+
import type { PresentationSignalRecord } from './presentation-record.js';
|
|
7
|
+
import type { ChurnRecord, DriftRecord, FlakinessRecord } from './history-records.js';
|
|
8
|
+
import type { VariationRecord } from './variation.js';
|
|
9
|
+
/**
|
|
10
|
+
* The run report — the artifact an agent actually reads.
|
|
11
|
+
*
|
|
12
|
+
* The observation pipeline produces values in memory and then the process ends.
|
|
13
|
+
* That is fine for a test and useless for the thing this is for: an agent asked
|
|
14
|
+
* to *fix* something arrives afterwards, in a different process, with no access
|
|
15
|
+
* to whatever was in scope when the change was sensed.
|
|
16
|
+
*
|
|
17
|
+
* So the run writes one of these, and the MCP tools query it. Keeping the file
|
|
18
|
+
* the contract — rather than having the tools re-run the pipeline — is what makes
|
|
19
|
+
* the two halves independent: a run can be produced by CI on a pinned machine
|
|
20
|
+
* and queried on a laptop, and the tools can be tested against a report nobody
|
|
21
|
+
* rendered.
|
|
22
|
+
*
|
|
23
|
+
* Deliberately not the raw `Observation`. That carries a `ChangeMask` and base64
|
|
24
|
+
* PNGs, which would make a 300-subject report hundreds of megabytes of data no
|
|
25
|
+
* reader ever looks at. What is kept is what a sentence needs.
|
|
26
|
+
*/
|
|
27
|
+
export interface RunReport {
|
|
28
|
+
readonly runVersion: 1;
|
|
29
|
+
/** ISO 8601. Supplied by the caller — nothing in this package reads a clock. */
|
|
30
|
+
readonly at: string;
|
|
31
|
+
readonly identity: RenderIdentity;
|
|
32
|
+
readonly retention: 'durable' | 'ephemeral';
|
|
33
|
+
/** What the run was comparing, in the author's words. Carried into every answer. */
|
|
34
|
+
readonly intent?: string;
|
|
35
|
+
readonly observations: readonly ObservationRecord[];
|
|
36
|
+
/**
|
|
37
|
+
* Subjects the run planned and has no observation for. **Absent is not empty.**
|
|
38
|
+
*
|
|
39
|
+
* Lives here rather than only on the CLI's own superset because the answers an
|
|
40
|
+
* agent gets are computed from *this* type, and a field the tools cannot see is
|
|
41
|
+
* a field the tools cannot be contradicted by. A run that planned 300 subjects,
|
|
42
|
+
* failed on 50 and found the other 250 unchanged produces a report in which
|
|
43
|
+
* every observation is clean and the conclusion "nothing to review" is false;
|
|
44
|
+
* the only thing that can refuse that sentence is this list.
|
|
45
|
+
*
|
|
46
|
+
* Optional because a report written by something other than `variance run` will
|
|
47
|
+
* not carry it, and the difference has to survive: `undefined` means the writer
|
|
48
|
+
* never said what it skipped, which is not the same claim as "it skipped
|
|
49
|
+
* nothing" and must never be printed as one. Costs every reader an extra state
|
|
50
|
+
* to handle, which is cheaper than the state it prevents collapsing.
|
|
51
|
+
*/
|
|
52
|
+
readonly notObserved?: readonly NotObserved[];
|
|
53
|
+
/**
|
|
54
|
+
* Which run this was, and at which commit.
|
|
55
|
+
*
|
|
56
|
+
* Present when the run could name itself — `--run` and `--commit`, or the pair
|
|
57
|
+
* the surrounding CI exports. Absent on a laptop, and absent is not a default
|
|
58
|
+
* anybody may fill in: an invented id cannot be joined back to anything that
|
|
59
|
+
* shipped, and it would silently become a denominator.
|
|
60
|
+
*
|
|
61
|
+
* Carried in the artifact because acceptance happens *later*, in a different
|
|
62
|
+
* command reading this file. A reviewer approves a subject **in a build**, and
|
|
63
|
+
* without the build's id there is nothing for that approval to point at — which
|
|
64
|
+
* is why every observation a run records is unapproved and why drift summed
|
|
65
|
+
* nothing until this field existed.
|
|
66
|
+
*/
|
|
67
|
+
readonly run?: {
|
|
68
|
+
readonly id: string;
|
|
69
|
+
readonly commit: string;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* What a history record already knew about the subjects this run found
|
|
73
|
+
* unstable, keyed by subject.
|
|
74
|
+
*
|
|
75
|
+
* Two readings put a *floor* under flakiness and can never put a ceiling on it
|
|
76
|
+
* (`ObservationRecord.unstable`). This is the other instrument: how often the
|
|
77
|
+
* subject has read differently before, and — the part that decides what anybody
|
|
78
|
+
* does next — whether it has happened since the last few sweeps. "Unstable in 6
|
|
79
|
+
* of 20" and "6 times, none in the last 9 sweeps" are opposite instructions.
|
|
80
|
+
*
|
|
81
|
+
* It lives on this type rather than only on the CLI's superset for the reason
|
|
82
|
+
* `notObserved` does: the answers an agent gets are computed from *this* type,
|
|
83
|
+
* and a field the tools cannot see is a field they cannot be contradicted by.
|
|
84
|
+
*
|
|
85
|
+
* **Absent is not "this has never happened."** It means no store answered —
|
|
86
|
+
* because none is configured, or because one could not be reached — and the
|
|
87
|
+
* reason is in `warnings` where it can be printed. A surface that renders a
|
|
88
|
+
* missing entry as "first occurrence" has invented the one fact this record
|
|
89
|
+
* exists to supply.
|
|
90
|
+
*/
|
|
91
|
+
readonly flakiness?: Readonly<Record<string, FlakinessRecord>>;
|
|
92
|
+
/**
|
|
93
|
+
* How often each component this run named as a cause has changed before,
|
|
94
|
+
* keyed by component.
|
|
95
|
+
*
|
|
96
|
+
* The instrument a comparison structurally cannot be. A diff answers *what
|
|
97
|
+
* moved*; this answers *how often this moves*, which is the difference between
|
|
98
|
+
* "review this" and "this component has been rewritten eleven times this
|
|
99
|
+
* quarter and nobody has asked why". No threshold reaches it, because the
|
|
100
|
+
* quantity is a count across runs and a one-run-at-a-time tool keeps none.
|
|
101
|
+
*
|
|
102
|
+
* **Absent is not "it has never changed."** It means no store answered, and the
|
|
103
|
+
* reason is in `warnings`.
|
|
104
|
+
*/
|
|
105
|
+
readonly churn?: Readonly<Record<string, ChurnRecord>>;
|
|
106
|
+
/**
|
|
107
|
+
* Design tokens whose value moved in this run, and what they have drifted to
|
|
108
|
+
* across every approved change in the window.
|
|
109
|
+
*
|
|
110
|
+
* The finding no comparison reaches. A button gains 2px, eleven times, each
|
|
111
|
+
* approved correctly by somebody looking at one diff — and the 22px is a number
|
|
112
|
+
* no review ever saw, because the quantity that would catch it is a sum and a
|
|
113
|
+
* single run holds none. Present only for tokens that moved *here*, so it is
|
|
114
|
+
* empty on almost every run and is the whole story on the one where it is not.
|
|
115
|
+
*/
|
|
116
|
+
readonly drift?: Readonly<Record<string, DriftRecord>>;
|
|
117
|
+
/**
|
|
118
|
+
* The suite compared to *itself*, at this one commit — see
|
|
119
|
+
* [`composition.ts`](./composition.ts).
|
|
120
|
+
*
|
|
121
|
+
* The only section of this report with no baseline in it. Absent when the
|
|
122
|
+
* collection produced no semantic snapshots to join, which is a real state and
|
|
123
|
+
* not an empty graph: a suite that shares nothing and a suite nobody could ask
|
|
124
|
+
* are different claims.
|
|
125
|
+
*/
|
|
126
|
+
readonly composition?: CompositionReport;
|
|
127
|
+
/**
|
|
128
|
+
* Subjects that declared themselves variations of another subject, and what
|
|
129
|
+
* the variation *is*.
|
|
130
|
+
*
|
|
131
|
+
* The other section with no baseline in it, and the answer to a question the
|
|
132
|
+
* category has never had one for: a story added behind a feature flag is a new
|
|
133
|
+
* subject, so its first run is `new`, its diff is empty, and what the flag
|
|
134
|
+
* actually does to the page is visible only by opening two pictures side by
|
|
135
|
+
* side. A subject that names a parent is compared against that parent *in the
|
|
136
|
+
* same run*, so the difference is a value with an identity — and the identity
|
|
137
|
+
* is what lets a reviewer be told that the difference is the one they already
|
|
138
|
+
* approved, on a run where both subjects changed.
|
|
139
|
+
*
|
|
140
|
+
* Every declared variation appears, including the ones that could not be
|
|
141
|
+
* computed: a parent nobody observed is a variation that was not measured, and
|
|
142
|
+
* dropping it would make a broken link look like a subject with nothing to say.
|
|
143
|
+
*
|
|
144
|
+
* Absent when no subject in the run declared a parent. Never present and empty.
|
|
145
|
+
*/
|
|
146
|
+
readonly variations?: readonly VariationRecord[];
|
|
147
|
+
/**
|
|
148
|
+
* What this commit reaches, from the diff and the file graph — see
|
|
149
|
+
* [`reach.ts`](./reach.ts).
|
|
150
|
+
*
|
|
151
|
+
* The third axis. `observations` is a subject against its past, `composition`
|
|
152
|
+
* is the suite against itself, and this is the suite against the *edit* — which
|
|
153
|
+
* components the changed files can possibly have moved, and by which chain.
|
|
154
|
+
* Crossed against the verdicts, it is what lets a report say that an edit
|
|
155
|
+
* reached a subject and changed nothing, or that a subject moved with nothing
|
|
156
|
+
* in the commit reaching it.
|
|
157
|
+
*
|
|
158
|
+
* Absent when the run was given no ref to diff against, or when no file graph
|
|
159
|
+
* was scanned. Present with `subjects` absent is the run saying it *has* a diff
|
|
160
|
+
* and could not attribute it, which is a different fact and a louder one.
|
|
161
|
+
*/
|
|
162
|
+
readonly reach?: ReachReport;
|
|
163
|
+
/**
|
|
164
|
+
* What this run narrowed by, and what it could have narrowed by.
|
|
165
|
+
*
|
|
166
|
+
* A run that observed everything is the default and is not a failure, so this
|
|
167
|
+
* is not a scolding — it is the coordinate. The execution index records the
|
|
168
|
+
* commit it was written at, which is its position in time and space; the
|
|
169
|
+
* distance from there to the tree on disk is what `--since` would have spent,
|
|
170
|
+
* and a reader that cannot see the coordinate cannot decide whether spending
|
|
171
|
+
* it is worth anything.
|
|
172
|
+
*
|
|
173
|
+
* Both halves are optional and mean different things absent. No `since` is a
|
|
174
|
+
* run that observed everything it planned. No `index` is either no recorded
|
|
175
|
+
* execution index or one with no position — nothing to diff from, so nothing
|
|
176
|
+
* to offer — and never *the index is current*, which is `changed: 0`.
|
|
177
|
+
*/
|
|
178
|
+
readonly narrowing?: {
|
|
179
|
+
/** The ref `--since` named. */
|
|
180
|
+
readonly since?: string;
|
|
181
|
+
/** Where the recorded execution index stands, and how far the tree is from it. */
|
|
182
|
+
readonly index?: {
|
|
183
|
+
readonly commit: string;
|
|
184
|
+
/** Files differing between that commit and the working tree. */
|
|
185
|
+
readonly changed: number;
|
|
186
|
+
};
|
|
187
|
+
};
|
|
188
|
+
/**
|
|
189
|
+
* What each declaration did, and the audit an ignore is only safe to have
|
|
190
|
+
* because of — see [`declarations.ts`](./declarations.ts). Kept in the record
|
|
191
|
+
* because *has this mask grown over a regression?* is asked months later, by
|
|
192
|
+
* somebody else. Never empty: absent is *the config named no such rule*.
|
|
193
|
+
*/
|
|
194
|
+
readonly ignores?: IgnoreLedger;
|
|
195
|
+
/** The same, for rules that relax an assertion rather than remove a region. */
|
|
196
|
+
readonly sensitivities?: SensitivityLedger;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Why a subject is in the report without an observation.
|
|
200
|
+
*
|
|
201
|
+
* Three kinds, because they mean different things about whether anyone should
|
|
202
|
+
* act. `excluded` is a decision the operator made and wrote down; `failed` is a
|
|
203
|
+
* hole in coverage, and collapsing the two makes every exclusion permanently red
|
|
204
|
+
* or a crash on subject 41 look chosen. `unreached` is neither: the run read the
|
|
205
|
+
* diff against what each baseline records having rendered and concluded this
|
|
206
|
+
* change cannot arrive. Calling that a decision reports one nobody made.
|
|
207
|
+
*/
|
|
208
|
+
export type NotObservedKind = 'excluded' | 'failed' | 'unreached';
|
|
209
|
+
export interface NotObserved {
|
|
210
|
+
readonly subject: string;
|
|
211
|
+
readonly kind: NotObservedKind;
|
|
212
|
+
/** One sentence, ready to print, naming what was not looked at and why. */
|
|
213
|
+
readonly because: string;
|
|
214
|
+
}
|
|
215
|
+
export interface ObservationRecord {
|
|
216
|
+
readonly subject: string;
|
|
217
|
+
/**
|
|
218
|
+
* `ignored` is green and is not `unchanged`.
|
|
219
|
+
*
|
|
220
|
+
* Pixels differed and every one of them landed inside a subtree the operator
|
|
221
|
+
* excluded (spec 0024). Kept as its own word so a report can be asked how much
|
|
222
|
+
* of its green was earned and how much was declared — a question `unchanged`
|
|
223
|
+
* absorbs and can never answer again.
|
|
224
|
+
*/
|
|
225
|
+
readonly verdict: 'unchanged' | 'changed' | 'new' | 'incomparable' | 'ignored';
|
|
226
|
+
readonly because: string;
|
|
227
|
+
/**
|
|
228
|
+
* Differing pixels at the policy the run isolated on, **after** exclusions.
|
|
229
|
+
*
|
|
230
|
+
* What was ignored is in {@link ObservationRecord.ignored} rather than folded
|
|
231
|
+
* in here, so the two numbers cannot be added by accident and a subject with a
|
|
232
|
+
* mask over half of it does not read as a subject that barely moved.
|
|
233
|
+
*/
|
|
234
|
+
readonly changedPixels: number;
|
|
235
|
+
/** Independently observed boundaries. A missing member was not measured. */
|
|
236
|
+
readonly signals?: {
|
|
237
|
+
readonly document?: 'unchanged' | 'changed';
|
|
238
|
+
readonly pixels?: 'unchanged' | 'changed';
|
|
239
|
+
readonly accessibility?: {
|
|
240
|
+
readonly verdict: 'unchanged' | 'changed' | 'incomparable';
|
|
241
|
+
readonly before?: AccessibilitySnapshot;
|
|
242
|
+
readonly after?: AccessibilitySnapshot;
|
|
243
|
+
};
|
|
244
|
+
/** Rendered relationship consequences, independent of render impact and verdict. */
|
|
245
|
+
readonly presentation?: PresentationSignalRecord;
|
|
246
|
+
};
|
|
247
|
+
/**
|
|
248
|
+
* What the operator's ignores took out of this comparison.
|
|
249
|
+
*
|
|
250
|
+
* Present whenever the subject had an excluded subtree at all, including when
|
|
251
|
+
* nothing was absorbed — `pixels: 0` with `boxes: 2` is a rule that caught
|
|
252
|
+
* nothing this run, which is the state that turns an ignore into a blind spot
|
|
253
|
+
* and therefore the one a report must be able to state.
|
|
254
|
+
*/
|
|
255
|
+
readonly ignored?: {
|
|
256
|
+
readonly pixels: number;
|
|
257
|
+
readonly boxes: number;
|
|
258
|
+
/** Boxes covering no changed pixel: the raster half of a dead ignore. */
|
|
259
|
+
readonly inert: number;
|
|
260
|
+
/** Pixels each rule absorbed here. A rule present with `0` caught nothing. */
|
|
261
|
+
readonly byRule: Readonly<Record<string, number>>;
|
|
262
|
+
};
|
|
263
|
+
/**
|
|
264
|
+
* The sensitivity that absorbed this subject, when one did.
|
|
265
|
+
*
|
|
266
|
+
* A subject reported `ignored` has two possible reasons and they are not
|
|
267
|
+
* interchangeable: every differing pixel fell inside an excluded subtree, or
|
|
268
|
+
* every band that moved was one this subject is not asserted on. The first is
|
|
269
|
+
* in {@link ObservationRecord.ignored}; this is the second, and keeping them
|
|
270
|
+
* apart is what lets a run be asked how much of its green came from a mask and
|
|
271
|
+
* how much from a declared level.
|
|
272
|
+
*/
|
|
273
|
+
readonly relaxed?: {
|
|
274
|
+
readonly rule: string;
|
|
275
|
+
readonly level: string;
|
|
276
|
+
readonly bands: readonly string[];
|
|
277
|
+
};
|
|
278
|
+
/**
|
|
279
|
+
* Every component whose hashes moved here, and the bands it moved in.
|
|
280
|
+
*
|
|
281
|
+
* A region is a box the pixels drew, named from where that box landed, so it
|
|
282
|
+
* fails where a change is most worth explaining: an edit that reflows its
|
|
283
|
+
* neighbours merges into one blob, the blob fits no component, and the name
|
|
284
|
+
* that comes back is the document root. These entries never looked at a pixel,
|
|
285
|
+
* so they still say `Button — geometry, token` where the only region is called
|
|
286
|
+
* `Anonymous`, and a component here that no region names is a difference lost.
|
|
287
|
+
*
|
|
288
|
+
* **Absent is not empty.** Omitted means no baseline hashes were there to
|
|
289
|
+
* compare; `[]` means both sides were read and every digest matched.
|
|
290
|
+
*/
|
|
291
|
+
readonly moved?: readonly ComponentBands[];
|
|
292
|
+
readonly regions: readonly RegionRecord[];
|
|
293
|
+
/** Regions found but not recorded, with their pixels. Never silently dropped. */
|
|
294
|
+
readonly truncated?: {
|
|
295
|
+
readonly regions: number;
|
|
296
|
+
readonly pixels: number;
|
|
297
|
+
};
|
|
298
|
+
readonly missingFonts?: readonly string[];
|
|
299
|
+
/**
|
|
300
|
+
* Defects found in *this* render, with no baseline consulted.
|
|
301
|
+
*
|
|
302
|
+
* The other half of what a run knows, and the half a comparison structurally
|
|
303
|
+
* cannot produce: a control that never had an accessible name compares equal
|
|
304
|
+
* to itself forever, so approving the first baseline approves the defect.
|
|
305
|
+
* Recorded per subject rather than per run because they are attributed the
|
|
306
|
+
* same way a region is — a component, a place, a file — and because the same
|
|
307
|
+
* component appearing in six subjects is six chances to notice it.
|
|
308
|
+
*
|
|
309
|
+
* They do not affect the verdict. A tool that blocks a merge on day one over
|
|
310
|
+
* findings nobody asked for gets switched off in week one; a project that
|
|
311
|
+
* wants them enforced writes `blocking: ['a11y']` in its policy, which covers
|
|
312
|
+
* both these and the regressions found by comparison.
|
|
313
|
+
*
|
|
314
|
+
* **Empty is not absent.** `[]` means this render was inspected and was clean;
|
|
315
|
+
* omitted means nothing inspected it, because the collector supplied no
|
|
316
|
+
* snapshot. Printing the second as the first tells a reader the component is
|
|
317
|
+
* fine on the authority of something that never looked at it — the same
|
|
318
|
+
* collapse `notObserved` exists to prevent.
|
|
319
|
+
*/
|
|
320
|
+
readonly findings?: readonly FindingRecord[];
|
|
321
|
+
/**
|
|
322
|
+
* What a second collection, in a world nothing else had touched, said.
|
|
323
|
+
*
|
|
324
|
+
* Present only on a subject the run called `changed`, and only when the
|
|
325
|
+
* collector can build such a world — `collectAlone` in `commands/run.ts` is
|
|
326
|
+
* optional, because a collector holding one page open across every subject
|
|
327
|
+
* cannot, and saying so is better than being assumed to have one.
|
|
328
|
+
*
|
|
329
|
+
* `reproduced: false` is the finding this whole path exists for: the change is
|
|
330
|
+
* gone when nothing else has run, so the baseline was right and the *session*
|
|
331
|
+
* moved this subject. That is a defect in the suite rather than in the
|
|
332
|
+
* component, and it must never be promoted — see `accept`, which refuses it.
|
|
333
|
+
*
|
|
334
|
+
* **Absent is not `reproduced: true`.** Omitted means nothing re-collected
|
|
335
|
+
* this subject, and reading that as "it reproduces" is how a false regression
|
|
336
|
+
* gets promoted with a confirmation attached to it.
|
|
337
|
+
*/
|
|
338
|
+
readonly alone?: {
|
|
339
|
+
/** `true` when the difference survived a world nothing else had touched. */
|
|
340
|
+
readonly reproduced: boolean;
|
|
341
|
+
readonly because: string;
|
|
342
|
+
};
|
|
343
|
+
/**
|
|
344
|
+
* The subject was read twice in one world and the two readings disagreed.
|
|
345
|
+
*
|
|
346
|
+
* The other second pass, and it answers the opposite question to
|
|
347
|
+
* {@link ObservationRecord.alone}: that one rebuilds the world and holds time,
|
|
348
|
+
* this one holds the world and lets time pass. A subject that fails this one is
|
|
349
|
+
* not a change and not a leak — it is a reading that cannot be taken twice, and
|
|
350
|
+
* everything the comparison said about it was said about one of the two.
|
|
351
|
+
*
|
|
352
|
+
* `accept` refuses it, for the reason it refuses order dependence: promoting a
|
|
353
|
+
* reading that will not reproduce makes the instability the baseline, and the
|
|
354
|
+
* next run compares against a coin flip somebody approved.
|
|
355
|
+
*
|
|
356
|
+
* **Absent means this run's two readings agreed — it does not mean stable.** A
|
|
357
|
+
* subject that reads differently one time in fifty passes twice-in-a-row forty
|
|
358
|
+
* nine runs out of fifty. Two readings put a floor under flakiness; nothing here
|
|
359
|
+
* puts a ceiling on it, and a reader who treats the absent field as a
|
|
360
|
+
* certificate has been told something this field never said. It is also absent
|
|
361
|
+
* on every subject the run did not call `changed`, which is almost all of them.
|
|
362
|
+
*/
|
|
363
|
+
readonly unstable?: {
|
|
364
|
+
/**
|
|
365
|
+
* Components whose own content differed between the two readings, with the
|
|
366
|
+
* file that declares each one where the source index could name it.
|
|
367
|
+
*
|
|
368
|
+
* Empty when the collector supplied no snapshot, which is a different state
|
|
369
|
+
* from *no component was responsible* — see the `because`, which says which
|
|
370
|
+
* of the two it is rather than leaving an empty list to be read as an answer.
|
|
371
|
+
*/
|
|
372
|
+
readonly components: readonly {
|
|
373
|
+
readonly name: string;
|
|
374
|
+
/** `file:line`. Absent when no source index resolved the name. */
|
|
375
|
+
readonly file?: string;
|
|
376
|
+
}[];
|
|
377
|
+
/** Frequency bands the disagreement fell in, e.g. `content`, `geometry`. */
|
|
378
|
+
readonly bands: readonly string[];
|
|
379
|
+
/**
|
|
380
|
+
* The declaration that put every band of this movement outside what the
|
|
381
|
+
* subject is asserted on.
|
|
382
|
+
*
|
|
383
|
+
* **Present means this is not a finding.** It does not gate, `accept` does
|
|
384
|
+
* not refuse it, and the summary files it under a different heading — because
|
|
385
|
+
* a route declared `layout` has said, in the config, that it does not assert
|
|
386
|
+
* on what the page is painted with, and a clock inside it is then a fact
|
|
387
|
+
* about the page rather than a defect in it. Stability is required inside the
|
|
388
|
+
* boundary the subject declares, and demanding it outside would make the
|
|
389
|
+
* declaration worthless: every route-level test would go red over the exact
|
|
390
|
+
* movement it was written to ignore.
|
|
391
|
+
*
|
|
392
|
+
* Recorded rather than dropped, for the reason `ignored` is a word of its own
|
|
393
|
+
* and never `unchanged` (ADR-0026): a suite has to be answerable about how
|
|
394
|
+
* much of its green came from a declaration. `bands` above still lists
|
|
395
|
+
* everything that moved, so the register can say what was absorbed and by
|
|
396
|
+
* which rule.
|
|
397
|
+
*/
|
|
398
|
+
readonly absorbed?: {
|
|
399
|
+
readonly rule: string;
|
|
400
|
+
readonly level: string;
|
|
401
|
+
};
|
|
402
|
+
readonly because: string;
|
|
403
|
+
};
|
|
404
|
+
/** Where the images went, when the run kept them. Relative to the report. */
|
|
405
|
+
readonly images?: {
|
|
406
|
+
readonly before?: string;
|
|
407
|
+
readonly after?: string;
|
|
408
|
+
readonly diff?: string;
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
export interface RegionRecord {
|
|
412
|
+
readonly x: number;
|
|
413
|
+
readonly y: number;
|
|
414
|
+
readonly width: number;
|
|
415
|
+
readonly height: number;
|
|
416
|
+
readonly pixels: number;
|
|
417
|
+
readonly component?: string;
|
|
418
|
+
readonly path?: string;
|
|
419
|
+
/** Landmark phrase, e.g. `main → list item 2 of 3`. */
|
|
420
|
+
readonly where?: string;
|
|
421
|
+
readonly file?: string;
|
|
422
|
+
/**
|
|
423
|
+
* `true` when the semantic tier named this component a root of the change.
|
|
424
|
+
*
|
|
425
|
+
* The field that decides whether a report leads with the edit or with what the
|
|
426
|
+
* edit pushed around. See `rankRegions` — area alone gets this backwards.
|
|
427
|
+
*/
|
|
428
|
+
readonly cause: boolean;
|
|
429
|
+
/** `true` when no box contained the region; a wrong scale or origin. */
|
|
430
|
+
readonly unattributed?: boolean;
|
|
431
|
+
/**
|
|
432
|
+
* The shape of this difference, with position and values removed.
|
|
433
|
+
*
|
|
434
|
+
* Printed so that writing a shape-scoped ignore is copying a digest out of the
|
|
435
|
+
* report rather than deriving one. Two regions with the same fingerprint are
|
|
436
|
+
* the same kind of thing happening, wherever on the canvas they landed.
|
|
437
|
+
*/
|
|
438
|
+
readonly fingerprint?: string;
|
|
439
|
+
}
|
|
440
|
+
export type { FindingRecord } from './finding-record.js';
|
|
441
|
+
export type { PresentationEffectEvidence, PresentationEffectRecord, PresentationEffectTransition, PresentationInformationRecord, PresentationSignalRecord, } from './presentation-record.js';
|
|
442
|
+
export type { ChurnRecord, DriftRecord, FlakinessRecord } from './history-records.js';
|
|
443
|
+
export type { VariationRecord } from './variation.js';
|
|
444
|
+
//# sourceMappingURL=format.d.ts.map
|
package/dist/format.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n AccessibilitySnapshot,\n ComponentBands,\n RenderIdentity,\n} from '@variance-authority/core';\nimport type { FindingRecord } from './finding-record.js';\nimport type { CompositionReport } from './composition.js';\nimport type { IgnoreLedger, SensitivityLedger } from './declarations.js';\nimport type { ReachReport } from './reach.js';\nimport type { PresentationSignalRecord } from './presentation-record.js';\nimport type { ChurnRecord, DriftRecord, FlakinessRecord } from './history-records.js';\nimport type { VariationRecord } from './variation.js';\n\n/**\n * The run report — the artifact an agent actually reads.\n *\n * The observation pipeline produces values in memory and then the process ends.\n * That is fine for a test and useless for the thing this is for: an agent asked\n * to *fix* something arrives afterwards, in a different process, with no access\n * to whatever was in scope when the change was sensed.\n *\n * So the run writes one of these, and the MCP tools query it. Keeping the file\n * the contract — rather than having the tools re-run the pipeline — is what makes\n * the two halves independent: a run can be produced by CI on a pinned machine\n * and queried on a laptop, and the tools can be tested against a report nobody\n * rendered.\n *\n * Deliberately not the raw `Observation`. That carries a `ChangeMask` and base64\n * PNGs, which would make a 300-subject report hundreds of megabytes of data no\n * reader ever looks at. What is kept is what a sentence needs.\n */\n\nexport interface RunReport {\n readonly runVersion: 1;\n /** ISO 8601. Supplied by the caller — nothing in this package reads a clock. */\n readonly at: string;\n readonly identity: RenderIdentity;\n readonly retention: 'durable' | 'ephemeral';\n /** What the run was comparing, in the author's words. Carried into every answer. */\n readonly intent?: string;\n readonly observations: readonly ObservationRecord[];\n /**\n * Subjects the run planned and has no observation for. **Absent is not empty.**\n *\n * Lives here rather than only on the CLI's own superset because the answers an\n * agent gets are computed from *this* type, and a field the tools cannot see is\n * a field the tools cannot be contradicted by. A run that planned 300 subjects,\n * failed on 50 and found the other 250 unchanged produces a report in which\n * every observation is clean and the conclusion \"nothing to review\" is false;\n * the only thing that can refuse that sentence is this list.\n *\n * Optional because a report written by something other than `variance run` will\n * not carry it, and the difference has to survive: `undefined` means the writer\n * never said what it skipped, which is not the same claim as \"it skipped\n * nothing\" and must never be printed as one. Costs every reader an extra state\n * to handle, which is cheaper than the state it prevents collapsing.\n */\n readonly notObserved?: readonly NotObserved[];\n\n /**\n * Which run this was, and at which commit.\n *\n * Present when the run could name itself — `--run` and `--commit`, or the pair\n * the surrounding CI exports. Absent on a laptop, and absent is not a default\n * anybody may fill in: an invented id cannot be joined back to anything that\n * shipped, and it would silently become a denominator.\n *\n * Carried in the artifact because acceptance happens *later*, in a different\n * command reading this file. A reviewer approves a subject **in a build**, and\n * without the build's id there is nothing for that approval to point at — which\n * is why every observation a run records is unapproved and why drift summed\n * nothing until this field existed.\n */\n readonly run?: {\n readonly id: string;\n readonly commit: string;\n };\n\n /**\n * What a history record already knew about the subjects this run found\n * unstable, keyed by subject.\n *\n * Two readings put a *floor* under flakiness and can never put a ceiling on it\n * (`ObservationRecord.unstable`). This is the other instrument: how often the\n * subject has read differently before, and — the part that decides what anybody\n * does next — whether it has happened since the last few sweeps. \"Unstable in 6\n * of 20\" and \"6 times, none in the last 9 sweeps\" are opposite instructions.\n *\n * It lives on this type rather than only on the CLI's superset for the reason\n * `notObserved` does: the answers an agent gets are computed from *this* type,\n * and a field the tools cannot see is a field they cannot be contradicted by.\n *\n * **Absent is not \"this has never happened.\"** It means no store answered —\n * because none is configured, or because one could not be reached — and the\n * reason is in `warnings` where it can be printed. A surface that renders a\n * missing entry as \"first occurrence\" has invented the one fact this record\n * exists to supply.\n */\n readonly flakiness?: Readonly<Record<string, FlakinessRecord>>;\n\n /**\n * How often each component this run named as a cause has changed before,\n * keyed by component.\n *\n * The instrument a comparison structurally cannot be. A diff answers *what\n * moved*; this answers *how often this moves*, which is the difference between\n * \"review this\" and \"this component has been rewritten eleven times this\n * quarter and nobody has asked why\". No threshold reaches it, because the\n * quantity is a count across runs and a one-run-at-a-time tool keeps none.\n *\n * **Absent is not \"it has never changed.\"** It means no store answered, and the\n * reason is in `warnings`.\n */\n readonly churn?: Readonly<Record<string, ChurnRecord>>;\n\n /**\n * Design tokens whose value moved in this run, and what they have drifted to\n * across every approved change in the window.\n *\n * The finding no comparison reaches. A button gains 2px, eleven times, each\n * approved correctly by somebody looking at one diff — and the 22px is a number\n * no review ever saw, because the quantity that would catch it is a sum and a\n * single run holds none. Present only for tokens that moved *here*, so it is\n * empty on almost every run and is the whole story on the one where it is not.\n */\n readonly drift?: Readonly<Record<string, DriftRecord>>;\n\n /**\n * The suite compared to *itself*, at this one commit — see\n * [`composition.ts`](./composition.ts).\n *\n * The only section of this report with no baseline in it. Absent when the\n * collection produced no semantic snapshots to join, which is a real state and\n * not an empty graph: a suite that shares nothing and a suite nobody could ask\n * are different claims.\n */\n readonly composition?: CompositionReport;\n\n /**\n * Subjects that declared themselves variations of another subject, and what\n * the variation *is*.\n *\n * The other section with no baseline in it, and the answer to a question the\n * category has never had one for: a story added behind a feature flag is a new\n * subject, so its first run is `new`, its diff is empty, and what the flag\n * actually does to the page is visible only by opening two pictures side by\n * side. A subject that names a parent is compared against that parent *in the\n * same run*, so the difference is a value with an identity — and the identity\n * is what lets a reviewer be told that the difference is the one they already\n * approved, on a run where both subjects changed.\n *\n * Every declared variation appears, including the ones that could not be\n * computed: a parent nobody observed is a variation that was not measured, and\n * dropping it would make a broken link look like a subject with nothing to say.\n *\n * Absent when no subject in the run declared a parent. Never present and empty.\n */\n readonly variations?: readonly VariationRecord[];\n\n /**\n * What this commit reaches, from the diff and the file graph — see\n * [`reach.ts`](./reach.ts).\n *\n * The third axis. `observations` is a subject against its past, `composition`\n * is the suite against itself, and this is the suite against the *edit* — which\n * components the changed files can possibly have moved, and by which chain.\n * Crossed against the verdicts, it is what lets a report say that an edit\n * reached a subject and changed nothing, or that a subject moved with nothing\n * in the commit reaching it.\n *\n * Absent when the run was given no ref to diff against, or when no file graph\n * was scanned. Present with `subjects` absent is the run saying it *has* a diff\n * and could not attribute it, which is a different fact and a louder one.\n */\n readonly reach?: ReachReport;\n\n /**\n * What this run narrowed by, and what it could have narrowed by.\n *\n * A run that observed everything is the default and is not a failure, so this\n * is not a scolding — it is the coordinate. The execution index records the\n * commit it was written at, which is its position in time and space; the\n * distance from there to the tree on disk is what `--since` would have spent,\n * and a reader that cannot see the coordinate cannot decide whether spending\n * it is worth anything.\n *\n * Both halves are optional and mean different things absent. No `since` is a\n * run that observed everything it planned. No `index` is either no recorded\n * execution index or one with no position — nothing to diff from, so nothing\n * to offer — and never *the index is current*, which is `changed: 0`.\n */\n readonly narrowing?: {\n /** The ref `--since` named. */\n readonly since?: string;\n /** Where the recorded execution index stands, and how far the tree is from it. */\n readonly index?: {\n readonly commit: string;\n /** Files differing between that commit and the working tree. */\n readonly changed: number;\n };\n };\n\n /**\n * What each declaration did, and the audit an ignore is only safe to have\n * because of — see [`declarations.ts`](./declarations.ts). Kept in the record\n * because *has this mask grown over a regression?* is asked months later, by\n * somebody else. Never empty: absent is *the config named no such rule*.\n */\n readonly ignores?: IgnoreLedger;\n /** The same, for rules that relax an assertion rather than remove a region. */\n readonly sensitivities?: SensitivityLedger;\n}\n\n/**\n * Why a subject is in the report without an observation.\n *\n * Three kinds, because they mean different things about whether anyone should\n * act. `excluded` is a decision the operator made and wrote down; `failed` is a\n * hole in coverage, and collapsing the two makes every exclusion permanently red\n * or a crash on subject 41 look chosen. `unreached` is neither: the run read the\n * diff against what each baseline records having rendered and concluded this\n * change cannot arrive. Calling that a decision reports one nobody made.\n */\nexport type NotObservedKind = 'excluded' | 'failed' | 'unreached';\n\nexport interface NotObserved {\n readonly subject: string;\n readonly kind: NotObservedKind;\n /** One sentence, ready to print, naming what was not looked at and why. */\n readonly because: string;\n}\n\nexport interface ObservationRecord {\n readonly subject: string;\n\n /**\n * `ignored` is green and is not `unchanged`.\n *\n * Pixels differed and every one of them landed inside a subtree the operator\n * excluded (spec 0024). Kept as its own word so a report can be asked how much\n * of its green was earned and how much was declared — a question `unchanged`\n * absorbs and can never answer again.\n */\n readonly verdict: 'unchanged' | 'changed' | 'new' | 'incomparable' | 'ignored';\n readonly because: string;\n\n /**\n * Differing pixels at the policy the run isolated on, **after** exclusions.\n *\n * What was ignored is in {@link ObservationRecord.ignored} rather than folded\n * in here, so the two numbers cannot be added by accident and a subject with a\n * mask over half of it does not read as a subject that barely moved.\n */\n readonly changedPixels: number;\n\n /** Independently observed boundaries. A missing member was not measured. */\n readonly signals?: {\n readonly document?: 'unchanged' | 'changed';\n readonly pixels?: 'unchanged' | 'changed';\n readonly accessibility?: {\n readonly verdict: 'unchanged' | 'changed' | 'incomparable';\n readonly before?: AccessibilitySnapshot;\n readonly after?: AccessibilitySnapshot;\n };\n /** Rendered relationship consequences, independent of render impact and verdict. */\n readonly presentation?: PresentationSignalRecord;\n };\n\n /**\n * What the operator's ignores took out of this comparison.\n *\n * Present whenever the subject had an excluded subtree at all, including when\n * nothing was absorbed — `pixels: 0` with `boxes: 2` is a rule that caught\n * nothing this run, which is the state that turns an ignore into a blind spot\n * and therefore the one a report must be able to state.\n */\n readonly ignored?: {\n readonly pixels: number;\n readonly boxes: number;\n /** Boxes covering no changed pixel: the raster half of a dead ignore. */\n readonly inert: number;\n /** Pixels each rule absorbed here. A rule present with `0` caught nothing. */\n readonly byRule: Readonly<Record<string, number>>;\n };\n /**\n * The sensitivity that absorbed this subject, when one did.\n *\n * A subject reported `ignored` has two possible reasons and they are not\n * interchangeable: every differing pixel fell inside an excluded subtree, or\n * every band that moved was one this subject is not asserted on. The first is\n * in {@link ObservationRecord.ignored}; this is the second, and keeping them\n * apart is what lets a run be asked how much of its green came from a mask and\n * how much from a declared level.\n */\n readonly relaxed?: {\n readonly rule: string;\n readonly level: string;\n readonly bands: readonly string[];\n };\n\n /**\n * Every component whose hashes moved here, and the bands it moved in.\n *\n * A region is a box the pixels drew, named from where that box landed, so it\n * fails where a change is most worth explaining: an edit that reflows its\n * neighbours merges into one blob, the blob fits no component, and the name\n * that comes back is the document root. These entries never looked at a pixel,\n * so they still say `Button — geometry, token` where the only region is called\n * `Anonymous`, and a component here that no region names is a difference lost.\n *\n * **Absent is not empty.** Omitted means no baseline hashes were there to\n * compare; `[]` means both sides were read and every digest matched.\n */\n readonly moved?: readonly ComponentBands[];\n readonly regions: readonly RegionRecord[];\n /** Regions found but not recorded, with their pixels. Never silently dropped. */\n readonly truncated?: { readonly regions: number; readonly pixels: number };\n readonly missingFonts?: readonly string[];\n\n /**\n * Defects found in *this* render, with no baseline consulted.\n *\n * The other half of what a run knows, and the half a comparison structurally\n * cannot produce: a control that never had an accessible name compares equal\n * to itself forever, so approving the first baseline approves the defect.\n * Recorded per subject rather than per run because they are attributed the\n * same way a region is — a component, a place, a file — and because the same\n * component appearing in six subjects is six chances to notice it.\n *\n * They do not affect the verdict. A tool that blocks a merge on day one over\n * findings nobody asked for gets switched off in week one; a project that\n * wants them enforced writes `blocking: ['a11y']` in its policy, which covers\n * both these and the regressions found by comparison.\n *\n * **Empty is not absent.** `[]` means this render was inspected and was clean;\n * omitted means nothing inspected it, because the collector supplied no\n * snapshot. Printing the second as the first tells a reader the component is\n * fine on the authority of something that never looked at it — the same\n * collapse `notObserved` exists to prevent.\n */\n readonly findings?: readonly FindingRecord[];\n\n /**\n * What a second collection, in a world nothing else had touched, said.\n *\n * Present only on a subject the run called `changed`, and only when the\n * collector can build such a world — `collectAlone` in `commands/run.ts` is\n * optional, because a collector holding one page open across every subject\n * cannot, and saying so is better than being assumed to have one.\n *\n * `reproduced: false` is the finding this whole path exists for: the change is\n * gone when nothing else has run, so the baseline was right and the *session*\n * moved this subject. That is a defect in the suite rather than in the\n * component, and it must never be promoted — see `accept`, which refuses it.\n *\n * **Absent is not `reproduced: true`.** Omitted means nothing re-collected\n * this subject, and reading that as \"it reproduces\" is how a false regression\n * gets promoted with a confirmation attached to it.\n */\n readonly alone?: {\n /** `true` when the difference survived a world nothing else had touched. */\n readonly reproduced: boolean;\n readonly because: string;\n };\n\n /**\n * The subject was read twice in one world and the two readings disagreed.\n *\n * The other second pass, and it answers the opposite question to\n * {@link ObservationRecord.alone}: that one rebuilds the world and holds time,\n * this one holds the world and lets time pass. A subject that fails this one is\n * not a change and not a leak — it is a reading that cannot be taken twice, and\n * everything the comparison said about it was said about one of the two.\n *\n * `accept` refuses it, for the reason it refuses order dependence: promoting a\n * reading that will not reproduce makes the instability the baseline, and the\n * next run compares against a coin flip somebody approved.\n *\n * **Absent means this run's two readings agreed — it does not mean stable.** A\n * subject that reads differently one time in fifty passes twice-in-a-row forty\n * nine runs out of fifty. Two readings put a floor under flakiness; nothing here\n * puts a ceiling on it, and a reader who treats the absent field as a\n * certificate has been told something this field never said. It is also absent\n * on every subject the run did not call `changed`, which is almost all of them.\n */\n readonly unstable?: {\n /**\n * Components whose own content differed between the two readings, with the\n * file that declares each one where the source index could name it.\n *\n * Empty when the collector supplied no snapshot, which is a different state\n * from *no component was responsible* — see the `because`, which says which\n * of the two it is rather than leaving an empty list to be read as an answer.\n */\n readonly components: readonly {\n readonly name: string;\n /** `file:line`. Absent when no source index resolved the name. */\n readonly file?: string;\n }[];\n /** Frequency bands the disagreement fell in, e.g. `content`, `geometry`. */\n readonly bands: readonly string[];\n\n /**\n * The declaration that put every band of this movement outside what the\n * subject is asserted on.\n *\n * **Present means this is not a finding.** It does not gate, `accept` does\n * not refuse it, and the summary files it under a different heading — because\n * a route declared `layout` has said, in the config, that it does not assert\n * on what the page is painted with, and a clock inside it is then a fact\n * about the page rather than a defect in it. Stability is required inside the\n * boundary the subject declares, and demanding it outside would make the\n * declaration worthless: every route-level test would go red over the exact\n * movement it was written to ignore.\n *\n * Recorded rather than dropped, for the reason `ignored` is a word of its own\n * and never `unchanged` (ADR-0026): a suite has to be answerable about how\n * much of its green came from a declaration. `bands` above still lists\n * everything that moved, so the register can say what was absorbed and by\n * which rule.\n */\n readonly absorbed?: {\n readonly rule: string;\n readonly level: string;\n };\n\n readonly because: string;\n };\n\n /** Where the images went, when the run kept them. Relative to the report. */\n readonly images?: {\n readonly before?: string;\n readonly after?: string;\n readonly diff?: string;\n };\n}\n\nexport interface RegionRecord {\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n readonly pixels: number;\n readonly component?: string;\n readonly path?: string;\n /** Landmark phrase, e.g. `main → list item 2 of 3`. */\n readonly where?: string;\n readonly file?: string;\n /**\n * `true` when the semantic tier named this component a root of the change.\n *\n * The field that decides whether a report leads with the edit or with what the\n * edit pushed around. See `rankRegions` — area alone gets this backwards.\n */\n readonly cause: boolean;\n /** `true` when no box contained the region; a wrong scale or origin. */\n readonly unattributed?: boolean;\n\n /**\n * The shape of this difference, with position and values removed.\n *\n * Printed so that writing a shape-scoped ignore is copying a digest out of the\n * report rather than deriving one. Two regions with the same fingerprint are\n * the same kind of thing happening, wherever on the canvas they landed.\n */\n readonly fingerprint?: string;\n}\n\n// Re-exported so a reader importing the report's shape gets the shapes its\n// fields are made of, without having to know which file each one was argued in.\nexport type { FindingRecord } from './finding-record.js';\nexport type {\n PresentationEffectEvidence,\n PresentationEffectRecord,\n PresentationEffectTransition,\n PresentationInformationRecord,\n PresentationSignalRecord,\n} from './presentation-record.js';\nexport type { ChurnRecord, DriftRecord, FlakinessRecord } from './history-records.js';\nexport type { VariationRecord } from './variation.js';\n"]}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the store answered, flattened into the report.
|
|
3
|
+
*
|
|
4
|
+
* Three shapes, and each is a copy of something `@variance-authority/history`
|
|
5
|
+
* already has. Deliberately: a report is opened by a reader that has a JSON file
|
|
6
|
+
* and nothing else, and importing the history package to name the type of a
|
|
7
|
+
* field would make reading a run report require installing a database client.
|
|
8
|
+
*
|
|
9
|
+
* They are together because they answer one question between them — *what does
|
|
10
|
+
* this suite's past say about what it just did* — and apart from `format.ts`
|
|
11
|
+
* because that question is the only one in the report a run cannot answer on its
|
|
12
|
+
* own. A run with no history configured has none of these, and its report is not
|
|
13
|
+
* missing anything it could have produced.
|
|
14
|
+
*/
|
|
15
|
+
/** What one token has drifted to, and how far it travelled getting there. */
|
|
16
|
+
export interface DriftRecord {
|
|
17
|
+
readonly from: string;
|
|
18
|
+
readonly to: string;
|
|
19
|
+
/** Value changes behind it. One is not drift; this is never below two. */
|
|
20
|
+
readonly steps: number;
|
|
21
|
+
readonly firstAt: string;
|
|
22
|
+
readonly lastAt: string;
|
|
23
|
+
/**
|
|
24
|
+
* The arithmetic, when every value was the same kind of quantity.
|
|
25
|
+
*
|
|
26
|
+
* Absent for a colour, a font stack, or a mixed set of units — and absent means
|
|
27
|
+
* *not measurable*, never zero. `because` says which.
|
|
28
|
+
*/
|
|
29
|
+
readonly quantity?: {
|
|
30
|
+
readonly unit: string;
|
|
31
|
+
readonly net: number;
|
|
32
|
+
/** The largest single step: the most any one review could have seen. */
|
|
33
|
+
readonly largestStep: number;
|
|
34
|
+
/** Sum of the absolute steps, which exceeds `|net|` whenever it changed direction. */
|
|
35
|
+
readonly travel: number;
|
|
36
|
+
};
|
|
37
|
+
/** One sentence, ready to print, from the package that owns the arithmetic. */
|
|
38
|
+
readonly because: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* How often one component's own code has changed, over a window.
|
|
42
|
+
*
|
|
43
|
+
* A structural copy of `@variance-authority/history`'s `Churn`, for the reason
|
|
44
|
+
* {@link FlakinessRecord} is one: this package requires nothing, and a report
|
|
45
|
+
* reader must not have to install a history client to open a file.
|
|
46
|
+
*/
|
|
47
|
+
export interface ChurnRecord {
|
|
48
|
+
/** Runs in the window, quiet ones included. The denominator. */
|
|
49
|
+
readonly runs: number;
|
|
50
|
+
/** Runs in which this component caused an **approved** change in any band. */
|
|
51
|
+
readonly changedRuns: number;
|
|
52
|
+
/**
|
|
53
|
+
* Runs in which only this component's geometry moved — it was *displaced* by an
|
|
54
|
+
* edit somewhere else. Reported, never summed: accumulating displacement makes
|
|
55
|
+
* the widest container in the application the thing that keeps changing, in
|
|
56
|
+
* every run, forever.
|
|
57
|
+
*/
|
|
58
|
+
readonly collateralRuns: number;
|
|
59
|
+
/** Runs carrying a change to this component that nobody approved. */
|
|
60
|
+
readonly rejectedRuns: number;
|
|
61
|
+
readonly firstAt?: string;
|
|
62
|
+
readonly lastAt?: string;
|
|
63
|
+
/** One sentence, ready to print, from the package that owns the arithmetic. */
|
|
64
|
+
readonly because: string;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* How often one subject has failed to read the same way twice.
|
|
68
|
+
*
|
|
69
|
+
* A structural copy of `@variance-authority/history`'s `Flakiness` rather than an
|
|
70
|
+
* import of it: this package requires nothing, and a report reader must not have
|
|
71
|
+
* to install a history client to open a file. The two are kept in step by the
|
|
72
|
+
* writer — `cli`, which imports both — and the fields that could drift are the
|
|
73
|
+
* ones with a rule attached, restated here so a reader of the artifact meets it.
|
|
74
|
+
*/
|
|
75
|
+
export interface FlakinessRecord {
|
|
76
|
+
/** Distinct runs recorded in the window, whatever they examined. */
|
|
77
|
+
readonly runs: number;
|
|
78
|
+
/**
|
|
79
|
+
* Distinct runs that read **every** subject twice, and the only honest
|
|
80
|
+
* denominator: an ordinary run asks a subject whether it agrees with itself
|
|
81
|
+
* only after calling it `changed`, so a green subject's silence in one is not
|
|
82
|
+
* evidence of anything.
|
|
83
|
+
*/
|
|
84
|
+
readonly sweeps: number;
|
|
85
|
+
/** Distinct runs in which this subject read differently and was not absorbed. */
|
|
86
|
+
readonly occurrences: number;
|
|
87
|
+
/**
|
|
88
|
+
* Runs whose instability fell entirely in bands this subject does not assert
|
|
89
|
+
* on — working as declared, never a finding, counted so a rule that absorbs
|
|
90
|
+
* something forever can still be asked about.
|
|
91
|
+
*/
|
|
92
|
+
readonly absorbedRuns: number;
|
|
93
|
+
/** Occurrences per sweep. **Absent when no sweep has run**, and never zero. */
|
|
94
|
+
readonly rate?: number;
|
|
95
|
+
/**
|
|
96
|
+
* Sweeps recorded since the most recent occurrence. Counted in sweeps rather
|
|
97
|
+
* than in days, so a suite that stopped running does not look increasingly
|
|
98
|
+
* fixed the longer nobody looks at it.
|
|
99
|
+
*/
|
|
100
|
+
readonly sweepsSince: number;
|
|
101
|
+
/** What read differently, loudest first. Empty when nothing could be named. */
|
|
102
|
+
readonly causes: readonly {
|
|
103
|
+
readonly component?: string;
|
|
104
|
+
readonly band?: string;
|
|
105
|
+
readonly runs: number;
|
|
106
|
+
}[];
|
|
107
|
+
readonly firstAt?: string;
|
|
108
|
+
readonly lastAt?: string;
|
|
109
|
+
/** One sentence, ready to print, from the package that owns the arithmetic. */
|
|
110
|
+
readonly because: string;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=history-records.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the store answered, flattened into the report.
|
|
3
|
+
*
|
|
4
|
+
* Three shapes, and each is a copy of something `@variance-authority/history`
|
|
5
|
+
* already has. Deliberately: a report is opened by a reader that has a JSON file
|
|
6
|
+
* and nothing else, and importing the history package to name the type of a
|
|
7
|
+
* field would make reading a run report require installing a database client.
|
|
8
|
+
*
|
|
9
|
+
* They are together because they answer one question between them — *what does
|
|
10
|
+
* this suite's past say about what it just did* — and apart from `format.ts`
|
|
11
|
+
* because that question is the only one in the report a run cannot answer on its
|
|
12
|
+
* own. A run with no history configured has none of these, and its report is not
|
|
13
|
+
* missing anything it could have produced.
|
|
14
|
+
*/
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=history-records.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history-records.js","sourceRoot":"","sources":["../src/history-records.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG","sourcesContent":["/**\n * What the store answered, flattened into the report.\n *\n * Three shapes, and each is a copy of something `@variance-authority/history`\n * already has. Deliberately: a report is opened by a reader that has a JSON file\n * and nothing else, and importing the history package to name the type of a\n * field would make reading a run report require installing a database client.\n *\n * They are together because they answer one question between them — *what does\n * this suite's past say about what it just did* — and apart from `format.ts`\n * because that question is the only one in the report a run cannot answer on its\n * own. A run with no history configured has none of these, and its report is not\n * missing anything it could have produced.\n */\n\n/** What one token has drifted to, and how far it travelled getting there. */\nexport interface DriftRecord {\n readonly from: string;\n readonly to: string;\n /** Value changes behind it. One is not drift; this is never below two. */\n readonly steps: number;\n readonly firstAt: string;\n readonly lastAt: string;\n\n /**\n * The arithmetic, when every value was the same kind of quantity.\n *\n * Absent for a colour, a font stack, or a mixed set of units — and absent means\n * *not measurable*, never zero. `because` says which.\n */\n readonly quantity?: {\n readonly unit: string;\n readonly net: number;\n /** The largest single step: the most any one review could have seen. */\n readonly largestStep: number;\n /** Sum of the absolute steps, which exceeds `|net|` whenever it changed direction. */\n readonly travel: number;\n };\n\n /** One sentence, ready to print, from the package that owns the arithmetic. */\n readonly because: string;\n}\n\n/**\n * How often one component's own code has changed, over a window.\n *\n * A structural copy of `@variance-authority/history`'s `Churn`, for the reason\n * {@link FlakinessRecord} is one: this package requires nothing, and a report\n * reader must not have to install a history client to open a file.\n */\nexport interface ChurnRecord {\n /** Runs in the window, quiet ones included. The denominator. */\n readonly runs: number;\n\n /** Runs in which this component caused an **approved** change in any band. */\n readonly changedRuns: number;\n\n /**\n * Runs in which only this component's geometry moved — it was *displaced* by an\n * edit somewhere else. Reported, never summed: accumulating displacement makes\n * the widest container in the application the thing that keeps changing, in\n * every run, forever.\n */\n readonly collateralRuns: number;\n\n /** Runs carrying a change to this component that nobody approved. */\n readonly rejectedRuns: number;\n\n readonly firstAt?: string;\n readonly lastAt?: string;\n\n /** One sentence, ready to print, from the package that owns the arithmetic. */\n readonly because: string;\n}\n\n/**\n * How often one subject has failed to read the same way twice.\n *\n * A structural copy of `@variance-authority/history`'s `Flakiness` rather than an\n * import of it: this package requires nothing, and a report reader must not have\n * to install a history client to open a file. The two are kept in step by the\n * writer — `cli`, which imports both — and the fields that could drift are the\n * ones with a rule attached, restated here so a reader of the artifact meets it.\n */\nexport interface FlakinessRecord {\n /** Distinct runs recorded in the window, whatever they examined. */\n readonly runs: number;\n\n /**\n * Distinct runs that read **every** subject twice, and the only honest\n * denominator: an ordinary run asks a subject whether it agrees with itself\n * only after calling it `changed`, so a green subject's silence in one is not\n * evidence of anything.\n */\n readonly sweeps: number;\n\n /** Distinct runs in which this subject read differently and was not absorbed. */\n readonly occurrences: number;\n\n /**\n * Runs whose instability fell entirely in bands this subject does not assert\n * on — working as declared, never a finding, counted so a rule that absorbs\n * something forever can still be asked about.\n */\n readonly absorbedRuns: number;\n\n /** Occurrences per sweep. **Absent when no sweep has run**, and never zero. */\n readonly rate?: number;\n\n /**\n * Sweeps recorded since the most recent occurrence. Counted in sweeps rather\n * than in days, so a suite that stopped running does not look increasingly\n * fixed the longer nobody looks at it.\n */\n readonly sweepsSince: number;\n\n /** What read differently, loudest first. Empty when nothing could be named. */\n readonly causes: readonly {\n readonly component?: string;\n readonly band?: string;\n readonly runs: number;\n }[];\n\n readonly firstAt?: string;\n readonly lastAt?: string;\n\n /** One sentence, ready to print, from the package that owns the arithmetic. */\n readonly because: string;\n}\n"]}
|