@invarn/cibuild 2.4.9 → 2.5.1

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.
@@ -51,6 +51,17 @@ export interface LayoutNode {
51
51
  fillAlpha?: number;
52
52
  /** Text alpha 0..1 (issue 14b), same convention as `fillAlpha`. */
53
53
  textAlpha?: number;
54
+ /** Border (ring) colour, hex — the design's `stroke` (property-recognizer 01),
55
+ * read from the layout node's `Modifier.border(...)` element. Absent when the
56
+ * node has no border OR has one this read cannot measure (a gradient brush),
57
+ * so absence alone is not "no border" — that is what `styleChannels` on the
58
+ * dump is for. */
59
+ borderColor?: string;
60
+ /** Border thickness in DP (the harness reads `Dp.value`), so unlike `bounds`
61
+ * it is NOT divided by density. Emitted together with `borderColor` or not at
62
+ * all: half a measurement compared against a whole design value is how a
63
+ * wrong number ships. */
64
+ borderWidth?: number;
54
65
  /** AnnotatedString background-span extents (issue 16): each range of the
55
66
  * node's text drawn with a specified span background — the highlighted
56
67
  * substrings. Offsets index into `text`. Absent in dumps from packages
@@ -142,6 +153,14 @@ export interface LayoutDump {
142
153
  * "no color span rendered", so the span compare only derives color-span
143
154
  * facts when the marker includes "color". */
144
155
  spanChannels?: string[];
156
+ /** The STYLE channels this dump's emitter can report ("border").
157
+ * Absent in dumps emitted before border capture existed, and load-bearing in
158
+ * that case: their silence means "cannot see a border", NOT "the render has no
159
+ * border". The border compare therefore withholds the ABSENCE case entirely
160
+ * without this marker and the caller advises "not checked" — reading it the
161
+ * other way would put a finding on every stroked design in the catalogue
162
+ * (property-recognizer 01). */
163
+ styleChannels?: string[];
145
164
  }
146
165
  export type Edge = 'left' | 'top' | 'right' | 'bottom';
147
166
  export type StructuralFact = {
@@ -353,6 +372,23 @@ export interface StructuralGeometryElement {
353
372
  * ink. Absent for anything that paints no painter, and for every render made
354
373
  * before the emitter tracked it. */
355
374
  paintedInk?: PaintedInk;
375
+ /**
376
+ * The element's render ancestry: every ancestor node id from its IMMEDIATE
377
+ * parent up to the root (icon-ink-ratio 05). The dump's `parentId` links are
378
+ * consumed here for sibling grouping and were dropped, so the judge could not
379
+ * see the render's tree at all — and an element the wrapper nested in the wrong
380
+ * container had no finding of its own.
381
+ *
382
+ * The CHAIN rather than the parent link, because Compose's semantics tree omits
383
+ * untagged layout nodes: a declared key routinely sits several levels below the
384
+ * container it should be compared against, and an immediate parent alone cannot
385
+ * see past the gap. Measured over three gated screens, the parent link produces
386
+ * 21 false rows where the chain produces 2.
387
+ *
388
+ * An EMPTY array is a root node — a measurement, distinguishable from the
389
+ * ABSENT field of every render made before this shipped.
390
+ */
391
+ ancestors?: string[];
356
392
  }
357
393
  export interface StructuralGeometry {
358
394
  unit: 'dp';
@@ -395,6 +431,33 @@ export type AppearanceFact = {
395
431
  channel: 'fill' | 'text';
396
432
  rendered: number;
397
433
  reference: number;
434
+ }
435
+ /** The design declares a STROKE the render drew no border for at all
436
+ * (property-recognizer 01). The motivating case: an 18dp badge with a 4dp
437
+ * white ring inside it, rendered as a plain green blob, about which the gate
438
+ * said nothing because no harness captured a border. Emitted ONLY from a dump
439
+ * that declares border capability (`styleChannels`) — an older emitter's
440
+ * silence is "cannot see a border", never "no border was drawn". */
441
+ | {
442
+ kind: 'border_missing';
443
+ elementId: string;
444
+ reference: string;
445
+ referenceWidth?: number;
446
+ }
447
+ /** A drawn border whose COLOUR differs from the design's stroke. */
448
+ | {
449
+ kind: 'border';
450
+ elementId: string;
451
+ rendered: string;
452
+ reference: string;
453
+ }
454
+ /** A drawn border of the right colour and the wrong THICKNESS, in dp. Its own
455
+ * kind so a correctly-coloured ring is never reported as a colour problem. */
456
+ | {
457
+ kind: 'border_width';
458
+ elementId: string;
459
+ rendered: number;
460
+ reference: number;
398
461
  } | {
399
462
  kind: 'text_mismatch';
400
463
  elementId: string;
@@ -679,6 +742,15 @@ export interface ElementColors {
679
742
  /** Per-channel alpha 0..1 (issue 14b), present only when translucent. */
680
743
  fillAlpha?: number;
681
744
  textAlpha?: number;
745
+ /** The BORDER colour (property-recognizer 01) — the design calls this a
746
+ * `stroke`, and both sides use that name so they line up. On the reference
747
+ * side it comes from `colors[key].stroke`; on the rendered side from the
748
+ * dump's `borderColor`. */
749
+ stroke?: string;
750
+ /** Border thickness in DP on both sides — the harness reads `Dp.value` and the
751
+ * design's `strokeWeight` is in design units, so unlike bounds this is never
752
+ * divided by density. */
753
+ strokeWeight?: number;
682
754
  }
683
755
  export type ColorSource = Record<string, ElementColors>;
684
756
  /**
@@ -693,6 +765,33 @@ export declare function hexToLab(hex: string): Lab;
693
765
  * test data. Pure and symmetric; identical colours give 0.
694
766
  */
695
767
  export declare function ciede2000(lab1: Lab, lab2: Lab): number;
768
+ /**
769
+ * Border facts (property-recognizer 01) — the design's `stroke` against the
770
+ * render's captured border. THE case this exists for: an 18dp badge with a 4dp
771
+ * white ring inside it rendered as a plain green blob, about which the gate said
772
+ * nothing at all, because the design's stroke lived in an authoring hint and the
773
+ * dump captured no border. Nothing compared, so an unmeasured property read as a
774
+ * pass.
775
+ *
776
+ * The DESIGN is the only side that raises the question, exactly as with alpha: an
777
+ * entry with no declared `stroke` is skipped, so a wrapper adding a ring the
778
+ * design never asked for is not something this calls wrong.
779
+ *
780
+ * Three kinds, because they are three different fixes — absent / wrong colour /
781
+ * wrong thickness. Folding width into `border` would report "the ring is the
782
+ * wrong colour" about a ring whose colour is exactly right.
783
+ *
784
+ * `capable` gates the ABSENCE case only, and both directions of that gate are
785
+ * wrong in a way worth naming: without it, a border-blind dump would fire
786
+ * `border_missing` on every stroked design in the catalogue; with it applied too
787
+ * broadly, a real divergence on a capable dump would go unreported. A colour or
788
+ * width difference is a genuine measurement either way — only "I saw no border"
789
+ * depends on being able to see borders at all.
790
+ *
791
+ * Pure and platform-agnostic; deterministic (sorted by element id). Mirrors the
792
+ * CLI preview twin in `packages/cli/lib/fidelity-structural.mjs`.
793
+ */
794
+ export declare function deriveBorderFacts(rendered: ColorSource, reference: ColorSource, capable: boolean): AppearanceFact[];
696
795
  /**
697
796
  * Color facts from the per-element, per-channel comparison of rendered vs
698
797
  * reference color, keyed on the stable element id shared with Signal B. For each
@@ -1 +1 @@
1
- {"version":3,"file":"structural-facts.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/structural-facts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"structural-facts.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/structural-facts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,oDAAoD;IACpD,EAAE,EAAE,MAAM,CAAC;IACX;6CACyC;IACzC,MAAM,EAAE,YAAY,CAAC;IACrB;;;+EAG2E;IAC3E,eAAe,CAAC,EAAE,YAAY,CAAC;IAC/B,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;oFACgF;IAChF,aAAa,EAAE,OAAO,CAAC;IAKvB,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;8EAE0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;uBAImB;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;8BAG0B;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;sCAIkC;IAClC,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB;;;;;yCAKqC;IACrC,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB;;;;;;kFAM8E;IAC9E,gBAAgB,CAAC,EAAE,YAAY,CAAC;IAChC;;;;;;;iDAO6C;IAC7C,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAED;;;;;kDAKkD;AAClD,MAAM,MAAM,UAAU,GAClB;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnC;;;;sBAIkB;IAClB,GAAG,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACvD,GACD;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1C;iEACiE;AACjE,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,mDAAmD;AACnD,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IACzB,+CAA+C;IAC/C,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB;;;;qEAIiE;IACjE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;kDAI8C;IAC9C,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB;;;;;;oCAMgC;IAChC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEvD,MAAM,MAAM,cAAc,GACtB;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;CAC3C,GACD;IACE,IAAI,EAAE,mBAAmB,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;CAC1C,GACD;IACE,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;CAC5C,GACD;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1B,SAAS,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,KAAK,EAAE,MAAM,CAAC;CACf,GACD;IACE;;;;;yCAKqC;IACrC,IAAI,EAAE,gBAAgB,CAAC;IACvB,QAAQ,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnC,QAAQ,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnC,MAAM,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,GAAG,GAAG,GAAG,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxD,GACD;IACE;;;;;oEAKgE;IAChE,IAAI,EAAE,eAAe,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEN;;wEAEwE;AACxE,MAAM,WAAW,cAAc;IAC7B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;;;sDAIsD;AACtD,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnC,MAAM,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjC,MAAM,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,GAAG,GAAG,GAAG,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxD;AAED;+DAC+D;AAC/D,eAAO,MAAM,8BAA8B,IAAI,CAAC;AAEhD;;;;;8EAK8E;AAC9E,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,KAAK,CAAC,EAAE,aAAa,EAAE,CAAC;CACzB;AAED;wCACwC;AACxC,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAE5C,MAAM,WAAW,4BAA4B;IAC3C;yEACqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;mCAC+B;IAC/B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAmED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAOnF;AAED,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,UAAU,EAChB,OAAO,GAAE,4BAAiC,GACzC,cAAc,EAAE,CAyIlB;AAkBD,iFAAiF;AACjF,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,MAAM,CAAC;CACZ;AACD,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAC7D,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,GAAG,GAAG,GAAG,CAAC;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AACD,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,EAAE,CAAC;CAC1B;AAKD;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,cAAc,EACzB,SAAS,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,EAC5C,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GACrC,aAAa,EAAE,CAqBjB;AAED,gFAAgF;AAChF,MAAM,MAAM,iBAAiB,GAAG,MAAM,CACpC,MAAM,EACN;IAAE,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CACnD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IACxC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IACtC,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7C,QAAQ,EAAE,OAAO,CAAC;IAClB;oEACgE;IAChE,UAAU,EAAE,OAAO,CAAC;IACpB;kFAC8E;IAC9E,aAAa,EAAE,OAAO,CAAC;IACvB;;kFAE8E;IAC9E,cAAc,EAAE,OAAO,CAAC;CACzB;AACD,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IAMX,QAAQ,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAIzD,MAAM,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAClF,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAC9B;;;yCAGqC;IACrC,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB;;;;;;;;;;;;;;;OAeG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AACD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,IAAI,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,yBAAyB,EAAE,CAAC;CACvC;AACD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,yEAAyE;IACzE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AACD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,iBAAiB,CAAC;IAC3B,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAC9B,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAClC,yDAAyD;IACzD,SAAS,CAAC,EAAE,mBAAmB,CAAC;CACjC;AAiBD;+EAC+E;AAC/E,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,iBAAiB,CAAC;AAE7D,MAAM,MAAM,cAAc,GACtB;IACE,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;CAChB,GACD;IACE;;;qEAGiE;IACjE,IAAI,EAAE,aAAa,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AACH;;;;;qEAKqE;GACnE;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE;AAC3F,oEAAoE;GAClE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE;AAC5E;+EAC+E;GAC7E;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAChF;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACjF;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE;AAChE;;;uCAGuC;GACrC;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE;AACnF;;;;yEAIyE;GACvE;IACE,IAAI,EAAE,qBAAqB,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AACH;;yEAEyE;GACvE;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE;AACzF;;;;mFAImF;GACjF;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,YAAY,CAAC;IACvB,SAAS,EAAE,YAAY,CAAC;CACzB;AACH,sCAAsC;GACpC;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE;AAChD,sCAAsC;GACpC;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjD;;;sEAGsE;AACtE,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB;;0BAEsB;IACtB,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB;0DACsD;IACtD,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAC9B;;;+DAG2D;IAC3D,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB;;oFAEgF;IAChF,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB;;wEAEoE;IACpE,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB;;;uBAGmB;IACnB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB;;iEAE6D;IAC7D,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB;;;gDAG4C;IAC5C,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED;gEACgE;AAChE,MAAM,WAAW,yBAAyB;IACxC;8BAC0B;IAC1B,OAAO,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACnC,yDAAyD;IACzD,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC9B,gFAAgF;IAChF,QAAQ,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC7B,yEAAyE;IACzE,QAAQ,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC7B;oEACgE;IAChE,WAAW,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IACpC,QAAQ,EAAE,kBAAkB,CAAC;CAC9B;AAMD;;;;;;;;;GASG;AACH,wBAAgB,kCAAkC,CAChD,MAAM,EAAE,yBAAyB,GAChC,mBAAmB,GAAG,IAAI,CA+B5B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qCAAqC,CACnD,QAAQ,EAAE,kBAAkB,GAAG,IAAI,GAAG,SAAS,GAC9C,mBAAmB,GAAG,IAAI,CAoB5B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,EAC7B,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,GAC7B,cAAc,EAAE,CAWlB;AAED;;;yEAGyE;AACzE,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAO5D;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,UAAU,EACpB,SAAS,EAAE,UAAU,GACpB,cAAc,EAAE,CAalB;AAED;;;qDAGqD;AACrD,MAAM,MAAM,UAAU,GAAG,MAAM,CAC7B,MAAM,EACN;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CACnE,CAAC;AAEF;;uEAEuE;AACvE,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAC,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,aAAa,EACvB,SAAS,EAAE,UAAU,EACrB,YAAY,CAAC,EAAE,OAAO,GACrB,cAAc,EAAE,CA6DlB;AAED;;;0BAG0B;AAC1B,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;AAE9D;;gFAEgF;AAChF,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAC,CAAC;AAEnE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,aAAa,EACvB,SAAS,EAAE,UAAU,GACpB,cAAc,EAAE,CAwBlB;AASD,+BAA+B;AAC/B,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAE3C;uEACuE;AACvE,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;gCAG4B;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;8BAE0B;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AACD,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAyBxD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAYzC;AAKD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,GAAG,MAAM,CA2DtD;AASD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,WAAW,EACrB,SAAS,EAAE,WAAW,EACtB,OAAO,EAAE,OAAO,GACf,cAAc,EAAE,CAqClB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,WAAW,EACrB,SAAS,EAAE,WAAW,GACrB,cAAc,EAAE,CAmClB;AAYD,4EAA4E;AAC5E,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,CAAC,CAAC;AAuDtE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAE,cAAc,GACxB,cAAc,EAAE,CAgBlB;AAiRD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,UAAU,EAChB,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,IAAI,EAC5C,OAAO,CAAC,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,eAAe,CAAC,EAAE,MAAM,CAAC;IAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAAO,EACxE,mBAAmB,CAAC,EAAE,mBAAmB,GAAG,IAAI,EAChD,cAAc,CAAC,EAAE,cAAc,GAAG,IAAI,EACtC,WAAW,CAAC,EAAE,cAAc,GAAG,IAAI,GAClC,eAAe,CA0WjB;AAaD,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,IAAI,CAAC;CACf;AACD,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,IAAI,CAAC;IACd,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,IAAI,EAAE,SAAS,EAAE,CAAC;CACnB;AAiGD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE;IAC9C,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;CACtC,GAAG,cAAc,CA6CjB;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,yBAAyB,EAAE,MAoLvC,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,gCAAgC,IAAI;IAClD,qBAAqB,EAAE,CACrB,IAAI,EAAE,UAAU,EAChB,OAAO,CAAC,EAAE,4BAA4B,KACnC,cAAc,EAAE,CAAC;CACvB,CAWA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,EAAE,MA+rC1C,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,yBAAyB,IAAI;IAC3C,eAAe,EAAE,CACf,SAAS,EAAE,cAAc,EACzB,SAAS,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,EAC5C,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,KAC/B,aAAa,EAAE,CAAC;IACrB,oBAAoB,EAAE,CACpB,IAAI,EAAE,UAAU,EAChB,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,IAAI,EAC5C,OAAO,CAAC,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,MAAM,CAAC;QAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;KAAE,EACpE,mBAAmB,CAAC,EAAE,mBAAmB,GAAG,IAAI,EAChD,cAAc,CAAC,EAAE,cAAc,GAAG,IAAI,EACtC,WAAW,CAAC,EAAE,cAAc,GAAG,IAAI,KAChC,eAAe,CAAC;IACrB,mBAAmB,EAAE,CAAC,UAAU,EAAE;QAChC,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;QACzB,QAAQ,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;KACtC,KAAK,cAAc,CAAC;IACrB,mBAAmB,EAAE,CACnB,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,EAC7B,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,KAC3B,cAAc,EAAE,CAAC;IACtB,eAAe,EAAE,CAAC,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,KAAK,cAAc,EAAE,CAAC;IACnF,eAAe,EAAE,CAAC,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,KAAK,cAAc,EAAE,CAAC;IACtF,eAAe,EAAE,CAAC,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,KAAK,cAAc,EAAE,CAAC;IACtF,gBAAgB,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,KAAK,cAAc,EAAE,CAAC;IACtF,mBAAmB,EAAE,CAAC,QAAQ,EAAE,cAAc,EAAE,SAAS,EAAE,cAAc,KAAK,cAAc,EAAE,CAAC;IAC/F,kCAAkC,EAAE,CAClC,MAAM,EAAE,yBAAyB,KAC9B,mBAAmB,GAAG,IAAI,CAAC;IAChC,SAAS,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,KAAK,MAAM,CAAC;IAC5C,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,GAAG,CAAC;CAChC,CAOA"}
@@ -661,6 +661,71 @@ function hueDeg(b, a) {
661
661
  const deg = rad2deg(Math.atan2(b, a));
662
662
  return deg >= 0 ? deg : deg + 360;
663
663
  }
664
+ /**
665
+ * Border facts (property-recognizer 01) — the design's `stroke` against the
666
+ * render's captured border. THE case this exists for: an 18dp badge with a 4dp
667
+ * white ring inside it rendered as a plain green blob, about which the gate said
668
+ * nothing at all, because the design's stroke lived in an authoring hint and the
669
+ * dump captured no border. Nothing compared, so an unmeasured property read as a
670
+ * pass.
671
+ *
672
+ * The DESIGN is the only side that raises the question, exactly as with alpha: an
673
+ * entry with no declared `stroke` is skipped, so a wrapper adding a ring the
674
+ * design never asked for is not something this calls wrong.
675
+ *
676
+ * Three kinds, because they are three different fixes — absent / wrong colour /
677
+ * wrong thickness. Folding width into `border` would report "the ring is the
678
+ * wrong colour" about a ring whose colour is exactly right.
679
+ *
680
+ * `capable` gates the ABSENCE case only, and both directions of that gate are
681
+ * wrong in a way worth naming: without it, a border-blind dump would fire
682
+ * `border_missing` on every stroked design in the catalogue; with it applied too
683
+ * broadly, a real divergence on a capable dump would go unreported. A colour or
684
+ * width difference is a genuine measurement either way — only "I saw no border"
685
+ * depends on being able to see borders at all.
686
+ *
687
+ * Pure and platform-agnostic; deterministic (sorted by element id). Mirrors the
688
+ * CLI preview twin in `packages/cli/lib/fidelity-structural.mjs`.
689
+ */
690
+ export function deriveBorderFacts(rendered, reference, capable) {
691
+ const facts = [];
692
+ for (const elementId of Object.keys(reference).sort()) {
693
+ const ref = reference[elementId];
694
+ if (!ref || !hasText(ref.stroke))
695
+ continue;
696
+ const ren = rendered[elementId];
697
+ const renderedStroke = ren ? ren.stroke : undefined;
698
+ if (!hasText(renderedStroke)) {
699
+ if (capable) {
700
+ const width = ref.strokeWeight;
701
+ facts.push({
702
+ kind: 'border_missing',
703
+ elementId,
704
+ reference: ref.stroke,
705
+ ...(typeof width === 'number' ? { referenceWidth: width } : {}),
706
+ });
707
+ }
708
+ continue;
709
+ }
710
+ if (renderedStroke.toLowerCase() !== ref.stroke.toLowerCase()) {
711
+ facts.push({
712
+ kind: 'border',
713
+ elementId,
714
+ rendered: renderedStroke,
715
+ reference: ref.stroke,
716
+ });
717
+ }
718
+ // Width only when the DESIGN states one — an undeclared weight says nothing
719
+ // about thickness, the same asymmetry alpha uses. 0.5dp is the floor below
720
+ // which two rings are the same ring.
721
+ const refW = ref.strokeWeight;
722
+ const renW = ren ? ren.strokeWeight : undefined;
723
+ if (typeof refW === 'number' && typeof renW === 'number' && Math.abs(refW - renW) > 0.5) {
724
+ facts.push({ kind: 'border_width', elementId, rendered: renW, reference: refW });
725
+ }
726
+ }
727
+ return facts;
728
+ }
664
729
  /**
665
730
  * Color facts from the per-element, per-channel comparison of rendered vs
666
731
  * reference color, keyed on the stable element id shared with Signal B. For each
@@ -850,6 +915,28 @@ function subtreeTextLineCount(elementId, byId, childrenByParent) {
850
915
  }
851
916
  return lines;
852
917
  }
918
+ /**
919
+ * One element's render ancestry: every ancestor id from its IMMEDIATE parent up
920
+ * to the root (icon-ink-ratio 05). Empty for a root node.
921
+ *
922
+ * Ids, not nodes, because the judge compares them against DESIGN keys — a render
923
+ * parent is usually an untagged layout node whose id is a Compose number, and it
924
+ * gets identified by the declared elements inside it rather than by its name.
925
+ *
926
+ * Guards against a parent cycle the same way `subtreeTextLineCount` does: a
927
+ * malformed dump must not hang a build.
928
+ */
929
+ function ancestorChain(elementId, byId) {
930
+ const out = [];
931
+ const seen = new Set([elementId]);
932
+ let cursor = byId.get(elementId)?.parentId ?? null;
933
+ while (cursor != null && !seen.has(cursor)) {
934
+ seen.add(cursor);
935
+ out.push(cursor);
936
+ cursor = byId.get(cursor)?.parentId ?? null;
937
+ }
938
+ return out;
939
+ }
853
940
  /** The size band for one element: the line-scaled text band when its subtree
854
941
  * lays out text (never stricter than the caller's tolerance), else strict. */
855
942
  function sizeBandDp(subtreeLines, sizeTolerancePx) {
@@ -1165,6 +1252,12 @@ export function buildStructuralBlock(dump, referenceGeometry, density, options =
1165
1252
  const paintedInk = byId.get(id)?.paintedInk;
1166
1253
  if (paintedInk)
1167
1254
  element.paintedInk = paintedInk;
1255
+ // The render's ancestry (icon-ink-ratio 05). Always set when the node is in
1256
+ // the dump, empty chain included: an absent field means "this render predates
1257
+ // ancestry", which is what keeps the nesting check silent on old renders
1258
+ // instead of guessing at a tree it cannot see.
1259
+ if (byId.has(id))
1260
+ element.ancestors = ancestorChain(id, byId);
1168
1261
  elements.push(element);
1169
1262
  }
1170
1263
  geometry = { unit: 'dp', density: d, elements };
@@ -1303,8 +1396,15 @@ export function buildStructuralBlock(dump, referenceGeometry, density, options =
1303
1396
  colors.fillAlpha = node.fillAlpha;
1304
1397
  if (typeof node.textAlpha === 'number')
1305
1398
  colors.textAlpha = node.textAlpha;
1306
- if (colors.fill !== undefined || colors.text !== undefined)
1399
+ // The rendered border (property-recognizer 01), keyed as `stroke` so the
1400
+ // design and render sides line up. `borderWidth` is already DP.
1401
+ if (typeof node.borderColor === 'string')
1402
+ colors.stroke = node.borderColor;
1403
+ if (typeof node.borderWidth === 'number')
1404
+ colors.strokeWeight = node.borderWidth;
1405
+ if (colors.fill !== undefined || colors.text !== undefined || colors.stroke !== undefined) {
1307
1406
  renderedColor[node.id] = colors;
1407
+ }
1308
1408
  // The resolved-typeface enrichment (issue 03): the font that actually painted.
1309
1409
  const tf = node.resolvedTypeface;
1310
1410
  if (tf && typeof tf.family === 'string' && tf.family.length > 0) {
@@ -1362,6 +1462,26 @@ export function buildStructuralBlock(dump, referenceGeometry, density, options =
1362
1462
  appearanceFacts.push(...deriveTypefaceFacts(renderedTypeface, appearanceReference.typeface));
1363
1463
  }
1364
1464
  }
1465
+ // Border facts (property-recognizer 01). `styleChannels` is the emitter's own
1466
+ // declaration that it can see borders; a package predating border capture
1467
+ // lacks it, and that silence is "cannot see a border", never "no border was
1468
+ // drawn". The advisory NAMES the elements — an unnamed "not checked" is a
1469
+ // statement nobody can act on, which is the same silence in a new place.
1470
+ if (appearanceReference.color) {
1471
+ const borderCapable = Array.isArray(dump.styleChannels) && dump.styleChannels.includes('border');
1472
+ appearanceFacts.push(...deriveBorderFacts(renderedColor, appearanceReference.color, borderCapable));
1473
+ if (!borderCapable) {
1474
+ const declared = Object.keys(appearanceReference.color)
1475
+ .filter((key) => hasText(appearanceReference.color?.[key]?.stroke))
1476
+ .sort();
1477
+ if (declared.length > 0) {
1478
+ advisories.push('border check requires a render package that captures one; this proof declared no ' +
1479
+ 'style channels (an older package) — the design stroke on ' +
1480
+ declared.join(', ') +
1481
+ ' was not checked, not passing');
1482
+ }
1483
+ }
1484
+ }
1365
1485
  const rendered = { elementIds: [...renderedIds].sort() };
1366
1486
  if (Object.keys(renderedText).length > 0)
1367
1487
  rendered.text = renderedText;
@@ -2190,6 +2310,44 @@ function deriveColorFacts(rendered, reference) {
2190
2310
  return facts;
2191
2311
  }
2192
2312
 
2313
+ // Border facts (property-recognizer 01) — the runner twin of deriveBorderFacts.
2314
+ // The design's stroke against the render's captured border; the DESIGN is the
2315
+ // only side that raises the question, and "capable" gates the ABSENCE case only,
2316
+ // because a border-blind dump cannot tell "no ring drawn" from "I cannot see
2317
+ // rings". Patching only the typed copy would make the local preview and the real
2318
+ // gate disagree, silently.
2319
+ function deriveBorderFacts(rendered, reference, capable) {
2320
+ var facts = [];
2321
+ var ids = Object.keys(reference).sort();
2322
+ for (var i = 0; i < ids.length; i++) {
2323
+ var elementId = ids[i];
2324
+ var ref = reference[elementId];
2325
+ if (!ref || !copyHasText(ref.stroke)) continue;
2326
+ var ren = rendered[elementId];
2327
+ var renderedStroke = ren ? ren.stroke : undefined;
2328
+ if (!copyHasText(renderedStroke)) {
2329
+ if (capable) {
2330
+ var missing = { kind: 'border_missing', elementId: elementId, reference: ref.stroke };
2331
+ if (typeof ref.strokeWeight === 'number') missing.referenceWidth = ref.strokeWeight;
2332
+ facts.push(missing);
2333
+ }
2334
+ continue;
2335
+ }
2336
+ if (renderedStroke.toLowerCase() !== ref.stroke.toLowerCase()) {
2337
+ facts.push({
2338
+ kind: 'border', elementId: elementId,
2339
+ rendered: renderedStroke, reference: ref.stroke,
2340
+ });
2341
+ }
2342
+ var refW = ref.strokeWeight;
2343
+ var renW = ren ? ren.strokeWeight : undefined;
2344
+ if (typeof refW === 'number' && typeof renW === 'number' && Math.abs(refW - renW) > 0.5) {
2345
+ facts.push({ kind: 'border_width', elementId: elementId, rendered: renW, reference: refW });
2346
+ }
2347
+ }
2348
+ return facts;
2349
+ }
2350
+
2193
2351
  // Signal C: typeface facts (issue 03) — the RESOLVED (painted, post-fallback)
2194
2352
  // font vs the reference font. Mirrors the typed normalizeTypeface /
2195
2353
  // deriveTypefaceFacts: a weight-name suffix on the family is stripped and, when
@@ -2323,6 +2481,22 @@ function sizeBandDp(subtreeLines, sizeTolerancePx) {
2323
2481
  return band > sizeTolerancePx ? band : sizeTolerancePx;
2324
2482
  }
2325
2483
 
2484
+ // The element's render ancestry, immediate parent first (icon-ink-ratio 05).
2485
+ // Empty for a root. Cycle-guarded like subtreeTextLineCount above.
2486
+ function ancestorChain(elementId, byId) {
2487
+ var out = [];
2488
+ var seen = [elementId];
2489
+ var node = byId[elementId];
2490
+ var cursor = node && node.parentId != null ? node.parentId : null;
2491
+ while (cursor != null && seen.indexOf(cursor) === -1) {
2492
+ seen.push(cursor);
2493
+ out.push(cursor);
2494
+ var next = byId[cursor];
2495
+ cursor = next && next.parentId != null ? next.parentId : null;
2496
+ }
2497
+ return out;
2498
+ }
2499
+
2326
2500
  function buildStructuralBlock(dump, referenceGeometry, density, options, appearanceReference, referenceFrame, anchorFrame) {
2327
2501
  var opts = options || {};
2328
2502
  var DIMENSION_SHORT = { width: 'w', height: 'h', x: 'x', y: 'y' };
@@ -2435,6 +2609,11 @@ function buildStructuralBlock(dump, referenceGeometry, density, options, appeara
2435
2609
  // so without this the judge compares a container against ink.
2436
2610
  var paintedInk = byId[id] ? byId[id].paintedInk : undefined;
2437
2611
  if (paintedInk) element.paintedInk = paintedInk;
2612
+ // Render ancestry (icon-ink-ratio 05) — the CHAIN, because Compose omits
2613
+ // untagged layout nodes and an immediate parent cannot see past the gap.
2614
+ // Absent (not empty) when the node is not in the dump, so the judge can tell
2615
+ // "no ancestry measured" from "measured, at the root".
2616
+ if (byId[id]) element.ancestors = ancestorChain(id, byId);
2438
2617
  elements.push(element);
2439
2618
  }
2440
2619
  geometry = { unit: 'dp', density: d, elements: elements };
@@ -2584,6 +2763,12 @@ function buildStructuralBlock(dump, referenceGeometry, density, options, appeara
2584
2763
  if (typeof rnode.textColor === 'string') { colors.text = rnode.textColor; hasColor = true; }
2585
2764
  if (typeof rnode.fillAlpha === 'number') { colors.fillAlpha = rnode.fillAlpha; }
2586
2765
  if (typeof rnode.textAlpha === 'number') { colors.textAlpha = rnode.textAlpha; }
2766
+ // The rendered border (property-recognizer 01), keyed as "stroke" to match
2767
+ // the design side. borderWidth is already DP — never divided by density.
2768
+ // hasColor flips here too: a ring is the element's only paint on a
2769
+ // stroke-only rule, and dropping the entry would lose the comparison.
2770
+ if (typeof rnode.borderColor === 'string') { colors.stroke = rnode.borderColor; hasColor = true; }
2771
+ if (typeof rnode.borderWidth === 'number') { colors.strokeWeight = rnode.borderWidth; }
2587
2772
  if (hasColor) renderedColor[rnode.id] = colors;
2588
2773
  // The resolved-typeface enrichment (issue 03): the font that actually painted.
2589
2774
  var rtf = rnode.resolvedTypeface;
@@ -2641,6 +2826,30 @@ function buildStructuralBlock(dump, referenceGeometry, density, options, appeara
2641
2826
  for (var tff = 0; tff < typefaceFacts.length; tff++) appearanceFacts.push(typefaceFacts[tff]);
2642
2827
  }
2643
2828
  }
2829
+ // Border facts (property-recognizer 01). styleChannels is the emitter's own
2830
+ // declaration that it can see borders; a package predating border capture
2831
+ // lacks it, and that silence is "cannot see a border", never "no border was
2832
+ // drawn". The advisory NAMES the elements — an unnamed "not checked" is a
2833
+ // statement nobody can act on.
2834
+ if (appearanceReference.color) {
2835
+ var borderCapable = Array.isArray(dump.styleChannels) &&
2836
+ dump.styleChannels.indexOf('border') !== -1;
2837
+ var borderFacts = deriveBorderFacts(renderedColor, appearanceReference.color, borderCapable);
2838
+ for (var bf = 0; bf < borderFacts.length; bf++) appearanceFacts.push(borderFacts[bf]);
2839
+ if (!borderCapable) {
2840
+ var strokeKeys = Object.keys(appearanceReference.color).filter(function (k) {
2841
+ return copyHasText(appearanceReference.color[k] && appearanceReference.color[k].stroke);
2842
+ }).sort();
2843
+ if (strokeKeys.length > 0) {
2844
+ appearanceAdvisories.push(
2845
+ 'border check requires a render package that captures one; this proof declared no ' +
2846
+ 'style channels (an older package) — the design stroke on ' +
2847
+ strokeKeys.join(', ') +
2848
+ ' was not checked, not passing'
2849
+ );
2850
+ }
2851
+ }
2852
+ }
2644
2853
  var sortedIds = renderedIds.slice().sort();
2645
2854
  var rendered = { elementIds: sortedIds };
2646
2855
  if (Object.keys(renderedText).length > 0) rendered.text = renderedText;
@@ -8,7 +8,7 @@
8
8
  * overflowing voucher tag; the deriver must surface the bottom clip as a
9
9
  * fact so it is never again skipped by eye.
10
10
  */
11
- import { deriveStructuralFacts, derivePresenceFacts, deriveCopyFacts, deriveSpanFacts, deriveLineFacts, deriveColorFacts, deriveTypefaceFacts, ciede2000, hexToLab, diffKeyGeometry, buildStructuralBlock, buildReviewScaffold, appearanceReferenceFromPreviousRender, buildAppearanceReferenceFromParams, getStructuralFactsStageInternals, getGeometryStageInternals, } from './structural-facts.js';
11
+ import { deriveStructuralFacts, derivePresenceFacts, deriveCopyFacts, deriveSpanFacts, deriveLineFacts, deriveColorFacts, deriveBorderFacts, deriveTypefaceFacts, ciede2000, hexToLab, diffKeyGeometry, buildStructuralBlock, buildReviewScaffold, appearanceReferenceFromPreviousRender, buildAppearanceReferenceFromParams, getStructuralFactsStageInternals, getGeometryStageInternals, } from './structural-facts.js';
12
12
  // 200x400 canvas in px for all fixtures unless noted.
13
13
  const CANVAS = { left: 0, top: 0, right: 200, bottom: 400 };
14
14
  describe('deriveStructuralFacts — containment', () => {
@@ -477,6 +477,10 @@ describe('buildStructuralBlock — with reference geometry (Signal B)', () => {
477
477
  design: { w: 81, h: 81 },
478
478
  deltas: [{ dimension: 'w', delta: 15 }, { dimension: 'h', delta: 15 }],
479
479
  sizeFlag: true,
480
+ // The render ancestry (icon-ink-ratio 05): `voucher` sits inside `banner`,
481
+ // which sits at the root. This assertion is exhaustive on purpose — it is
482
+ // what noticed the new field, and it is what will notice the next one.
483
+ ancestors: ['banner', 'node-1'],
480
484
  });
481
485
  const banner = block.geometry?.elements.find((e) => e.id === 'banner');
482
486
  expect(banner?.sizeFlag).toBe(true);
@@ -1139,6 +1143,64 @@ describe('buildStructuralBlock — appearance container (Signal C, additive)', (
1139
1143
  const embedded = getGeometryStageInternals();
1140
1144
  expect(embedded.buildStructuralBlock(INK_DUMP, INK_REFERENCE, 2)).toEqual(buildStructuralBlock(INK_DUMP, INK_REFERENCE, 2));
1141
1145
  });
1146
+ // ---- Render ancestry (icon-ink-ratio 05) ----
1147
+ // The dump carries `parentId` per node and the deriver consumes it for sibling
1148
+ // grouping, then drops it. Without it the judge cannot see the render's tree at
1149
+ // all, so an element the wrapper nested in the wrong container has no finding of
1150
+ // its own — it surfaces only as a side effect of whatever collision it happens
1151
+ // to cause.
1152
+ //
1153
+ // The CHAIN, not the parent link. Compose's semantics tree omits untagged layout
1154
+ // nodes, so a declared key routinely sits several levels below the parent it
1155
+ // should be compared against; measured against three gated screens, an immediate
1156
+ // parent alone produces 21 false rows where the chain produces 2 (see the issue).
1157
+ //
1158
+ // Same three copies as `paintedInk`: this module, the embedded render script that
1159
+ // actually runs on the runner, and Invarn's vendored twin.
1160
+ const NESTED_DUMP = {
1161
+ canvas: CANVAS,
1162
+ nodes: [
1163
+ {
1164
+ id: 'root',
1165
+ bounds: { left: 0, top: 0, right: 200, bottom: 200 },
1166
+ unclippedBounds: { left: 0, top: 0, right: 200, bottom: 200 },
1167
+ parentId: null,
1168
+ clipsChildren: false,
1169
+ },
1170
+ // An UNTAGGED intermediate: the case the chain exists for.
1171
+ {
1172
+ id: 'node-7',
1173
+ bounds: { left: 0, top: 0, right: 200, bottom: 200 },
1174
+ unclippedBounds: { left: 0, top: 0, right: 200, bottom: 200 },
1175
+ parentId: 'root',
1176
+ clipsChildren: false,
1177
+ },
1178
+ {
1179
+ id: 'badge',
1180
+ bounds: { left: 32, top: 32, right: 48, bottom: 48 },
1181
+ unclippedBounds: { left: 32, top: 32, right: 48, bottom: 48 },
1182
+ parentId: 'node-7',
1183
+ clipsChildren: false,
1184
+ },
1185
+ ],
1186
+ };
1187
+ const NESTED_REFERENCE = { root: { w: 100, h: 100 }, badge: { w: 8, h: 8 } };
1188
+ test('carries the render ancestor chain onto the element, immediate parent first (icon-ink-ratio 05)', () => {
1189
+ const block = buildStructuralBlock(NESTED_DUMP, NESTED_REFERENCE, 2);
1190
+ const badge = block.geometry?.elements.find((e) => e.id === 'badge');
1191
+ // Through the untagged `node-7` and on to the root — the untagged link is the
1192
+ // whole reason a single `parentId` is not enough.
1193
+ expect(badge?.ancestors).toEqual(['node-7', 'root']);
1194
+ // A root node's chain is empty, not absent: "measured, no ancestors" is a
1195
+ // statement, and it is what tells the judge this render carries ancestry at
1196
+ // all (every render made before this shipped carries none).
1197
+ const root = block.geometry?.elements.find((e) => e.id === 'root');
1198
+ expect(root?.ancestors).toEqual([]);
1199
+ });
1200
+ test('embedded stage matches the module for render ancestry (parity, icon-ink-ratio 05)', () => {
1201
+ const embedded = getGeometryStageInternals();
1202
+ expect(embedded.buildStructuralBlock(NESTED_DUMP, NESTED_REFERENCE, 2)).toEqual(buildStructuralBlock(NESTED_DUMP, NESTED_REFERENCE, 2));
1203
+ });
1142
1204
  test('embedded stage matches the module for the figma missing-element case (parity, issue 03)', () => {
1143
1205
  const embedded = getGeometryStageInternals();
1144
1206
  const reference = {
@@ -2760,4 +2822,47 @@ describe('embedded geometry stage parity', () => {
2760
2822
  expect(embedded.buildStructuralBlock(dump, ref, 1, undefined, undefined, frame)).toEqual(buildStructuralBlock(dump, ref, 1, undefined, undefined, frame));
2761
2823
  });
2762
2824
  });
2825
+ // ─── Border facts (property-recognizer 01) ───────────────────────────────────
2826
+ // The runner half of the comparison that finally makes a missing ring visible.
2827
+ // These lock the TYPED copy; the ES5 runner twin is exercised through the
2828
+ // generated-script tests, and the two must not drift — patching one only is a
2829
+ // silent asymmetry between the local preview and the real gate.
2830
+ describe('deriveBorderFacts — the design stroke vs the rendered border', () => {
2831
+ const REF = { badge: { fill: '#3ca000', stroke: '#ffffff', strokeWeight: 4 } };
2832
+ test('THE motivating case: a declared ring the render never drew', () => {
2833
+ expect(deriveBorderFacts({ badge: { fill: '#3ca000' } }, REF, true)).toEqual([
2834
+ { kind: 'border_missing', elementId: 'badge', reference: '#ffffff', referenceWidth: 4 },
2835
+ ]);
2836
+ });
2837
+ test('a border-blind dump states NOTHING — silence is "cannot see", not "absent"', () => {
2838
+ // Without this gate every stroked design in the catalogue gains a finding on
2839
+ // the strength of a blindness. The caller raises a not-checked advisory.
2840
+ expect(deriveBorderFacts({ badge: { fill: '#3ca000' } }, REF, false)).toEqual([]);
2841
+ });
2842
+ test('a ring in the wrong colour is a border fact', () => {
2843
+ expect(deriveBorderFacts({ badge: { stroke: '#cccccc', strokeWeight: 4 } }, REF, true)).toEqual([{ kind: 'border', elementId: 'badge', rendered: '#cccccc', reference: '#ffffff' }]);
2844
+ });
2845
+ test('a ring of the right colour and the wrong thickness is its own fact', () => {
2846
+ expect(deriveBorderFacts({ badge: { stroke: '#ffffff', strokeWeight: 1 } }, REF, true)).toEqual([{ kind: 'border_width', elementId: 'badge', rendered: 1, reference: 4 }]);
2847
+ });
2848
+ test('hex case never matters, and a matching ring yields nothing', () => {
2849
+ expect(deriveBorderFacts({ badge: { stroke: '#FFFFFF', strokeWeight: 4 } }, REF, true)).toEqual([]);
2850
+ });
2851
+ test('sub-half-dp width differences are the same ring', () => {
2852
+ expect(deriveBorderFacts({ badge: { stroke: '#ffffff', strokeWeight: 4.4 } }, REF, true)).toEqual([]);
2853
+ });
2854
+ test('a design with no declared stroke says nothing about a rendered ring', () => {
2855
+ // The design is the only side that can raise the question — the same
2856
+ // asymmetry alpha uses. A wrapper adding an unasked-for ring is not a defect
2857
+ // this comparison can name.
2858
+ expect(deriveBorderFacts({ badge: { stroke: '#ffffff', strokeWeight: 4 } }, { badge: { fill: '#3ca000' } }, true)).toEqual([]);
2859
+ });
2860
+ test('an undeclared design WIDTH grades colour only, never thickness', () => {
2861
+ expect(deriveBorderFacts({ badge: { stroke: '#ffffff', strokeWeight: 9 } }, { badge: { stroke: '#ffffff' } }, true)).toEqual([]);
2862
+ // ...and a missing ring still states the colour, without inventing a width.
2863
+ expect(deriveBorderFacts({}, { badge: { stroke: '#ffffff' } }, true)).toEqual([
2864
+ { kind: 'border_missing', elementId: 'badge', reference: '#ffffff' },
2865
+ ]);
2866
+ });
2867
+ });
2763
2868
  //# sourceMappingURL=structural-facts.test.js.map
@@ -453,10 +453,18 @@ describe('android render runtime — render + trim (happy path)', () => {
453
453
  design: { w: 80, h: 80 },
454
454
  deltas: [{ dimension: 'h', delta: 10 }],
455
455
  sizeFlag: true,
456
+ // Render ancestry (icon-ink-ratio 05), measured by the EMBEDDED port that
457
+ // actually runs on the runner: `card` is a root in this dump, so its chain
458
+ // is empty. Empty is a measurement — the judge reads an ABSENT field as
459
+ // "this render predates ancestry" and stays silent on it.
460
+ ancestors: [],
456
461
  });
457
462
  const tag = geometry?.elements.find((e) => e.id === 'tag');
458
463
  expect(tag?.sizeFlag).toBe(false);
459
464
  expect(tag?.deltas).toEqual([]);
465
+ // ...and `tag` is nested inside `card`, so the chain the judge compares
466
+ // against the design tree is non-trivial here.
467
+ expect(tag?.ancestors).toEqual(['card']);
460
468
  });
461
469
  test('derives a flagged typeface fact when reference_typeface is given and the resolved font diverges (typeface issue 04)', async () => {
462
470
  // The fake dump resolved Roboto-Regular 400 on `tag`; the design declares
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@invarn/cibuild",
3
- "version": "2.4.9",
3
+ "version": "2.5.1",
4
4
  "description": "CI Build CLI — local pipeline orchestration and validation",
5
5
  "type": "module",
6
6
  "main": "dist/cli.cjs",