@flighthq/capture 0.3.1-next.575.c1f8e01 → 0.3.1-next.616.aa7ae7f

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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flighthq/capture",
3
- "version": "0.3.1-next.575.c1f8e01",
3
+ "version": "0.3.1-next.616.aa7ae7f",
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.1-next.575.c1f8e01",
42
- "@flighthq/types": "0.3.1-next.575.c1f8e01"
41
+ "@flighthq/bitmap": "0.3.1-next.616.aa7ae7f",
42
+ "@flighthq/types": "0.3.1-next.616.aa7ae7f"
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 };