@flighthq/capture 0.3.0 → 0.3.1-next.1041.35b950c

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.
@@ -1,4 +1,4 @@
1
- import type { CaptureBaseline, CaptureColumnBaseline } from '@flighthq/types/contract';
1
+ import type { CaptureBaseline, CaptureBaselineField, CaptureBaselineProvenance, CaptureBaselineProvenanceField } from '@flighthq/types/contract';
2
2
  /** Allocates an empty baseline record. Columns are added via setCaptureBaselineField. */
3
3
  export declare function createCaptureBaseline(): CaptureBaseline;
4
4
  /**
@@ -12,7 +12,10 @@ export declare function formatCaptureBaseline(baseline: Readonly<CaptureBaseline
12
12
  * The value of one column's field, or `null` when the column or field is absent. `field` is
13
13
  * `'fingerprint'` or `'sha256'`.
14
14
  */
15
- export declare function getCaptureBaselineField(baseline: Readonly<CaptureBaseline>, column: string, field: keyof CaptureColumnBaseline): string | null;
15
+ export declare function getCaptureBaselineField(baseline: Readonly<CaptureBaseline>, column: string, field: CaptureBaselineField): string | null;
16
+ /** What produced ONE of a column's values — `field` names which. `null` when that value is absent or
17
+ * predates provenance recording, which reads as UNKNOWN provenance and never as agreement. */
18
+ export declare function getCaptureBaselineProvenance(baseline: Readonly<CaptureBaseline>, column: string, field: CaptureBaselineProvenanceField): CaptureBaselineProvenance | null;
16
19
  /**
17
20
  * Parses the text form produced by formatCaptureBaseline. Returns `null` for malformed input — invalid
18
21
  * JSON, or a top-level value that is not a plain object — so a corrupt baseline reads as "no baseline"
@@ -20,5 +23,7 @@ export declare function getCaptureBaselineField(baseline: Readonly<CaptureBaseli
20
23
  */
21
24
  export declare function parseCaptureBaseline(text: string): CaptureBaseline | null;
22
25
  /** Sets one column's field to `value`, creating the column entry if it does not yet exist. */
23
- export declare function setCaptureBaselineField(baseline: CaptureBaseline, column: string, field: keyof CaptureColumnBaseline, value: string): void;
26
+ export declare function setCaptureBaselineField(baseline: CaptureBaseline, column: string, field: CaptureBaselineField, value: string): void;
27
+ /** Records what produced ONE of a column's values, creating the column entry if it does not yet exist. */
28
+ export declare function setCaptureBaselineProvenance(baseline: CaptureBaseline, column: string, field: CaptureBaselineProvenanceField, provenance: Readonly<CaptureBaselineProvenance>): void;
24
29
  //# sourceMappingURL=captureBaseline.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"captureBaseline.d.ts","sourceRoot":"","sources":["../src/captureBaseline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAEvF,yFAAyF;AACzF,wBAAgB,qBAAqB,IAAI,eAAe,CAEvD;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,CAAC,eAAe,CAAC,GAAG,MAAM,CAWjF;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,QAAQ,CAAC,eAAe,CAAC,EACnC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,qBAAqB,GACjC,MAAM,GAAG,IAAI,CAEf;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CASzE;AAED,8FAA8F;AAC9F,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,eAAe,EACzB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,qBAAqB,EAClC,KAAK,EAAE,MAAM,GACZ,IAAI,CAEN"}
1
+ {"version":3,"file":"captureBaseline.d.ts","sourceRoot":"","sources":["../src/captureBaseline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,oBAAoB,EACpB,yBAAyB,EACzB,8BAA8B,EAE/B,MAAM,0BAA0B,CAAC;AAElC,yFAAyF;AACzF,wBAAgB,qBAAqB,IAAI,eAAe,CAEvD;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,CAAC,eAAe,CAAC,GAAG,MAAM,CAejF;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,QAAQ,CAAC,eAAe,CAAC,EACnC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,oBAAoB,GAC1B,MAAM,GAAG,IAAI,CAEf;AAED;8FAC8F;AAC9F,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,QAAQ,CAAC,eAAe,CAAC,EACnC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,8BAA8B,GACpC,yBAAyB,GAAG,IAAI,CAElC;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CASzE;AAED,8FAA8F;AAC9F,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,eAAe,EACzB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,oBAAoB,EAC3B,KAAK,EAAE,MAAM,GACZ,IAAI,CAEN;AAED,0GAA0G;AAC1G,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,eAAe,EACzB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,8BAA8B,EACrC,UAAU,EAAE,QAAQ,CAAC,yBAAyB,CAAC,GAC9C,IAAI,CAEN"}
@@ -19,6 +19,12 @@ export function formatCaptureBaseline(baseline) {
19
19
  out.sourceHash = entry.sourceHash;
20
20
  if (entry.sha256 !== undefined)
21
21
  out.sha256 = entry.sha256;
22
+ // Provenance is emitted LAST so adding it to a column leaves every existing line in place and the
23
+ // diff is one appended block rather than a rewrite of the record.
24
+ if (entry.fingerprintProvenance !== undefined)
25
+ out.fingerprintProvenance = entry.fingerprintProvenance;
26
+ if (entry.sha256Provenance !== undefined)
27
+ out.sha256Provenance = entry.sha256Provenance;
22
28
  sorted[column] = out;
23
29
  }
24
30
  return JSON.stringify(sorted, null, 2) + '\n';
@@ -30,6 +36,11 @@ export function formatCaptureBaseline(baseline) {
30
36
  export function getCaptureBaselineField(baseline, column, field) {
31
37
  return baseline[column]?.[field] ?? null;
32
38
  }
39
+ /** What produced ONE of a column's values — `field` names which. `null` when that value is absent or
40
+ * predates provenance recording, which reads as UNKNOWN provenance and never as agreement. */
41
+ export function getCaptureBaselineProvenance(baseline, column, field) {
42
+ return baseline[column]?.[provenanceMember(field)] ?? null;
43
+ }
33
44
  /**
34
45
  * Parses the text form produced by formatCaptureBaseline. Returns `null` for malformed input — invalid
35
46
  * JSON, or a top-level value that is not a plain object — so a corrupt baseline reads as "no baseline"
@@ -51,4 +62,11 @@ export function parseCaptureBaseline(text) {
51
62
  export function setCaptureBaselineField(baseline, column, field, value) {
52
63
  (baseline[column] ??= {})[field] = value;
53
64
  }
65
+ /** Records what produced ONE of a column's values, creating the column entry if it does not yet exist. */
66
+ export function setCaptureBaselineProvenance(baseline, column, field, provenance) {
67
+ (baseline[column] ??= {})[provenanceMember(field)] = { ...provenance };
68
+ }
69
+ function provenanceMember(field) {
70
+ return field === 'fingerprint' ? 'fingerprintProvenance' : 'sha256Provenance';
71
+ }
54
72
  //# sourceMappingURL=captureBaseline.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"captureBaseline.js","sourceRoot":"","sources":["../src/captureBaseline.ts"],"names":[],"mappings":"AAEA,yFAAyF;AACzF,MAAM,UAAU,qBAAqB;IACnC,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAmC;IACvE,MAAM,MAAM,GAAoB,EAAE,CAAC;IACnC,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAClD,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC/B,MAAM,GAAG,GAA0B,EAAE,CAAC;QACtC,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS;YAAE,GAAG,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;QACzE,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;YAAE,GAAG,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;QACtE,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;YAAE,GAAG,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QAC1D,MAAM,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC;IACvB,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;AAChD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CACrC,QAAmC,EACnC,MAAc,EACd,KAAkC;IAElC,OAAO,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC;AAC3C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IACxF,OAAO,MAAyB,CAAC;AACnC,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,uBAAuB,CACrC,QAAyB,EACzB,MAAc,EACd,KAAkC,EAClC,KAAa;IAEb,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;AAC3C,CAAC"}
1
+ {"version":3,"file":"captureBaseline.js","sourceRoot":"","sources":["../src/captureBaseline.ts"],"names":[],"mappings":"AAQA,yFAAyF;AACzF,MAAM,UAAU,qBAAqB;IACnC,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAmC;IACvE,MAAM,MAAM,GAAoB,EAAE,CAAC;IACnC,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAClD,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC/B,MAAM,GAAG,GAA0B,EAAE,CAAC;QACtC,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS;YAAE,GAAG,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;QACzE,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;YAAE,GAAG,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;QACtE,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;YAAE,GAAG,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QAC1D,kGAAkG;QAClG,kEAAkE;QAClE,IAAI,KAAK,CAAC,qBAAqB,KAAK,SAAS;YAAE,GAAG,CAAC,qBAAqB,GAAG,KAAK,CAAC,qBAAqB,CAAC;QACvG,IAAI,KAAK,CAAC,gBAAgB,KAAK,SAAS;YAAE,GAAG,CAAC,gBAAgB,GAAG,KAAK,CAAC,gBAAgB,CAAC;QACxF,MAAM,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC;IACvB,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;AAChD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CACrC,QAAmC,EACnC,MAAc,EACd,KAA2B;IAE3B,OAAO,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC;AAC3C,CAAC;AAED;8FAC8F;AAC9F,MAAM,UAAU,4BAA4B,CAC1C,QAAmC,EACnC,MAAc,EACd,KAAqC;IAErC,OAAO,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC;AAC7D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IACxF,OAAO,MAAyB,CAAC;AACnC,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,uBAAuB,CACrC,QAAyB,EACzB,MAAc,EACd,KAA2B,EAC3B,KAAa;IAEb,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;AAC3C,CAAC;AAED,0GAA0G;AAC1G,MAAM,UAAU,4BAA4B,CAC1C,QAAyB,EACzB,MAAc,EACd,KAAqC,EACrC,UAA+C;IAE/C,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,GAAG,UAAU,EAAE,CAAC;AACzE,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAqC;IAC7D,OAAO,KAAK,KAAK,aAAa,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,kBAAkB,CAAC;AAChF,CAAC"}
@@ -21,6 +21,13 @@ export declare function evaluateCaptureParity(a: string, b: string, tolerance?:
21
21
  * Regression: whether a freshly captured `fingerprint` still matches its own committed
22
22
  * `baselineFingerprint` within `tolerance`. `difference` is the tolerant distance (Infinity when
23
23
  * either fingerprint is unparseable); `pass` is `difference <= tolerance`.
24
+ *
25
+ * ⚠ A PASS MEANS THE FINGERPRINT DID NOT MOVE, WHICH IS NOT THE SAME AS THE RENDER NOT MOVING. Each
26
+ * cell averages the pixels beneath it, so a pattern finer than a cell — scanlines, dithering, a fine
27
+ * periodic warp — can change completely while every cell average stays put. Three separate defects in
28
+ * this repository passed this check while the pixels underneath disagreed, one of them by more than
29
+ * fifty times the distance reported here. Where the subject is high-frequency, a passing regression
30
+ * is evidence about the fingerprint and not about the image.
24
31
  */
25
32
  export declare function evaluateCaptureRegression(fingerprint: string, baselineFingerprint: string, tolerance?: number): CaptureCheckResult;
26
33
  //# sourceMappingURL=captureComparison.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"captureComparison.d.ts","sourceRoot":"","sources":["../src/captureComparison.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAInE,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAK3C,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAKvE;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,SAAS,SAA2B,GAAG,kBAAkB,CAGpH;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,EACnB,mBAAmB,EAAE,MAAM,EAC3B,SAAS,SAA+B,GACvC,kBAAkB,CAGpB"}
1
+ {"version":3,"file":"captureComparison.d.ts","sourceRoot":"","sources":["../src/captureComparison.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAInE,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAK3C,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAKvE;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,SAAS,SAA2B,GAAG,kBAAkB,CAGpH;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,EACnB,mBAAmB,EAAE,MAAM,EAC3B,SAAS,SAA+B,GACvC,kBAAkB,CAGpB"}
@@ -35,6 +35,13 @@ export function evaluateCaptureParity(a, b, tolerance = CAPTURE_PARITY_TOLERANCE
35
35
  * Regression: whether a freshly captured `fingerprint` still matches its own committed
36
36
  * `baselineFingerprint` within `tolerance`. `difference` is the tolerant distance (Infinity when
37
37
  * either fingerprint is unparseable); `pass` is `difference <= tolerance`.
38
+ *
39
+ * ⚠ A PASS MEANS THE FINGERPRINT DID NOT MOVE, WHICH IS NOT THE SAME AS THE RENDER NOT MOVING. Each
40
+ * cell averages the pixels beneath it, so a pattern finer than a cell — scanlines, dithering, a fine
41
+ * periodic warp — can change completely while every cell average stays put. Three separate defects in
42
+ * this repository passed this check while the pixels underneath disagreed, one of them by more than
43
+ * fifty times the distance reported here. Where the subject is high-frequency, a passing regression
44
+ * is evidence about the fingerprint and not about the image.
38
45
  */
39
46
  export function evaluateCaptureRegression(fingerprint, baselineFingerprint, tolerance = CAPTURE_REGRESSION_TOLERANCE) {
40
47
  const difference = compareCaptureFingerprints(fingerprint, baselineFingerprint);
@@ -1 +1 @@
1
- {"version":3,"file":"captureComparison.js","sourceRoot":"","sources":["../src/captureComparison.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAG9F,sGAAsG;AACtG,sGAAsG;AACtG,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAE3C,uGAAuG;AACvG,uGAAuG;AACvG,iEAAiE;AACjE,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC;AAE9C;;;;;;;GAOG;AACH,MAAM,UAAU,0BAA0B,CAAC,CAAS,EAAE,CAAS;IAC7D,MAAM,EAAE,GAAG,sBAAsB,CAAC,CAAC,CAAC,CAAC;IACrC,MAAM,EAAE,GAAG,sBAAsB,CAAC,CAAC,CAAC,CAAC;IACrC,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,CAAC,QAAQ,KAAK,EAAE,CAAC,QAAQ;QAAE,OAAO,MAAM,CAAC,iBAAiB,CAAC;IAC/F,OAAO,yBAAyB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,CAAS,EAAE,CAAS,EAAE,SAAS,GAAG,wBAAwB;IAC9F,MAAM,UAAU,GAAG,0BAA0B,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACpD,OAAO,EAAE,IAAI,EAAE,UAAU,IAAI,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;AAClE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CACvC,WAAmB,EACnB,mBAA2B,EAC3B,SAAS,GAAG,4BAA4B;IAExC,MAAM,UAAU,GAAG,0BAA0B,CAAC,WAAW,EAAE,mBAAmB,CAAC,CAAC;IAChF,OAAO,EAAE,IAAI,EAAE,UAAU,IAAI,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;AAClE,CAAC"}
1
+ {"version":3,"file":"captureComparison.js","sourceRoot":"","sources":["../src/captureComparison.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAG9F,sGAAsG;AACtG,sGAAsG;AACtG,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAE3C,uGAAuG;AACvG,uGAAuG;AACvG,iEAAiE;AACjE,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC;AAE9C;;;;;;;GAOG;AACH,MAAM,UAAU,0BAA0B,CAAC,CAAS,EAAE,CAAS;IAC7D,MAAM,EAAE,GAAG,sBAAsB,CAAC,CAAC,CAAC,CAAC;IACrC,MAAM,EAAE,GAAG,sBAAsB,CAAC,CAAC,CAAC,CAAC;IACrC,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,CAAC,QAAQ,KAAK,EAAE,CAAC,QAAQ;QAAE,OAAO,MAAM,CAAC,iBAAiB,CAAC;IAC/F,OAAO,yBAAyB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,CAAS,EAAE,CAAS,EAAE,SAAS,GAAG,wBAAwB;IAC9F,MAAM,UAAU,GAAG,0BAA0B,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACpD,OAAO,EAAE,IAAI,EAAE,UAAU,IAAI,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;AAClE,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,yBAAyB,CACvC,WAAmB,EACnB,mBAA2B,EAC3B,SAAS,GAAG,4BAA4B;IAExC,MAAM,UAAU,GAAG,0BAA0B,CAAC,WAAW,EAAE,mBAAmB,CAAC,CAAC;IAChF,OAAO,EAAE,IAAI,EAAE,UAAU,IAAI,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;AAClE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flighthq/capture",
3
- "version": "0.3.0",
3
+ "version": "0.3.1-next.1041.35b950c",
4
4
  "author": "Joshua Granick and other contributors",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -38,8 +38,8 @@
38
38
  "clean:dist": "tsx ../../scripts/clean-package-dist.ts"
39
39
  },
40
40
  "dependencies": {
41
- "@flighthq/bitmap": "0.3.0",
42
- "@flighthq/types": "0.3.0"
41
+ "@flighthq/bitmap": "0.3.1-next.1041.35b950c",
42
+ "@flighthq/types": "0.3.1-next.1041.35b950c"
43
43
  },
44
44
  "devDependencies": {
45
45
  "typescript": "^5.3.0"
@@ -4,8 +4,10 @@ import {
4
4
  createCaptureBaseline,
5
5
  formatCaptureBaseline,
6
6
  getCaptureBaselineField,
7
+ getCaptureBaselineProvenance,
7
8
  parseCaptureBaseline,
8
9
  setCaptureBaselineField,
10
+ setCaptureBaselineProvenance,
9
11
  } from './captureBaseline';
10
12
 
11
13
  describe('createCaptureBaseline', () => {
@@ -72,6 +74,31 @@ describe('getCaptureBaselineField', () => {
72
74
  });
73
75
  });
74
76
 
77
+ describe('getCaptureBaselineProvenance', () => {
78
+ it('reads back what was recorded', () => {
79
+ const baseline = createCaptureBaseline();
80
+ setCaptureBaselineProvenance(baseline, 'webgl', 'sha256', PROVENANCE);
81
+ expect(getCaptureBaselineProvenance(baseline, 'webgl', 'sha256')).toEqual(PROVENANCE);
82
+ });
83
+
84
+ it('does NOT answer for the other value — one provenance per independently-written field', () => {
85
+ const baseline = createCaptureBaseline();
86
+ setCaptureBaselineProvenance(baseline, 'webgl', 'sha256', PROVENANCE);
87
+ // fingerprint is written by a DIFFERENT pass. A sha256 stamp must not read as covering it, or the
88
+ // record reports agreement it never established.
89
+ expect(getCaptureBaselineProvenance(baseline, 'webgl', 'fingerprint')).toBeNull();
90
+ expect(getCaptureBaselineProvenance(baseline, 'webgl', 'sha256')).toEqual(PROVENANCE);
91
+ });
92
+
93
+ it('reads a column written before provenance existed as UNKNOWN, not as agreement', () => {
94
+ const baseline = createCaptureBaseline();
95
+ setCaptureBaselineField(baseline, 'webgl', 'sha256', 'abc');
96
+ // null is the whole staging decision: a legacy record must not read as "produced the same way".
97
+ expect(getCaptureBaselineProvenance(baseline, 'webgl', 'sha256')).toBeNull();
98
+ expect(getCaptureBaselineProvenance(baseline, 'absent', 'sha256')).toBeNull();
99
+ });
100
+ });
101
+
75
102
  describe('parseCaptureBaseline', () => {
76
103
  it('round-trips format output to a stable, equal record', () => {
77
104
  const baseline = createCaptureBaseline();
@@ -114,3 +141,23 @@ describe('setCaptureBaselineField', () => {
114
141
  expect(getCaptureBaselineField(baseline, 'canvas', 'fingerprint')).toBe('1:ffffff');
115
142
  });
116
143
  });
144
+
145
+ describe('setCaptureBaselineProvenance', () => {
146
+ it('creates the column and leaves the other fields alone', () => {
147
+ const baseline = createCaptureBaseline();
148
+ setCaptureBaselineField(baseline, 'webgl', 'sha256', 'abc');
149
+ setCaptureBaselineProvenance(baseline, 'webgl', 'sha256', PROVENANCE);
150
+ expect(getCaptureBaselineField(baseline, 'webgl', 'sha256')).toBe('abc');
151
+ expect(getCaptureBaselineProvenance(baseline, 'webgl', 'sha256')).toEqual(PROVENANCE);
152
+ });
153
+
154
+ it('copies rather than aliasing, so a later caller mutation cannot rewrite the record', () => {
155
+ const baseline = createCaptureBaseline();
156
+ const source = { ...PROVENANCE };
157
+ setCaptureBaselineProvenance(baseline, 'webgl', 'sha256', source);
158
+ source.frames = 99;
159
+ expect(getCaptureBaselineProvenance(baseline, 'webgl', 'sha256')?.frames).toBe(PROVENANCE.frames);
160
+ });
161
+ });
162
+
163
+ const PROVENANCE = { frames: 1, sourceHash: 'a1b2c3', targetKind: 'webgl', verifyPublished: true, warmupFrames: 0 };