@tekyzinc/gsd-t 2.70.10 → 2.70.11

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 CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  All notable changes to GSD-T are documented here. Updated with each release.
4
4
 
5
+ ## [2.70.11] - 2026-04-06
6
+
7
+ ### Added (design pipeline — DOM box model inspection + layout arithmetic)
8
+ - **DOM Box Model Inspection** — new mandatory verification step for fixed-height containers. Uses Playwright to evaluate `offsetHeight` vs `scrollHeight` for each child element. Flags elements where `offsetHeight > scrollHeight * 1.5` as INFLATED (symptom: `flex: 1` on a content element inflating its box beyond content size). Added to: `gsd-t-execute` (Step 5.5 inside Design Verification Agent), `gsd-t-quick` (step 8 inside Design Verification Agent), `gsd-t-design-audit` (Step 3.75).
9
+ - **Internal Layout Arithmetic** — widget contract template now requires computed height budgets for fixed-height cards: `card_height - padding - header = body_available`, then `child1 + gap1 + child2 + ... = total_content ≤ body_available`. Forces the agent to write the math before coding — prevents `gap: 12px` when only `gap: 8px` fits.
10
+ - **Flex Centering Anti-Pattern Rule** — `design-to-code.md` Section 8 now explicitly prohibits `flex: 1` on content elements (KPI, labels, text) for centering. Rule: `flex: 1` belongs on containers, `justify-content: center` on the parent. Children keep natural size.
11
+ - **4 new verification checklist items** in `design-to-code.md` and `widget-contract.md`: box model inspection, layout arithmetic, no content flex:1, inflated element detection.
12
+
13
+ ### Why
14
+ BDS horizontal stacked bar cards required 5 user-prompted fix iterations to get spacing right. Root cause: agent used `flex: 1` on `.kpi` to center it vertically, which inflated the element to 144px (content was 40px), displacing the chart section. The property comparison table and SVG overlay both missed this because the *positions* were close enough — the problem was *how space was distributed*, not where elements landed. DOM box model inspection catches the cause (inflated element) not just the symptom (displaced sibling).
15
+
5
16
  ## [2.70.10] - 2026-04-06
6
17
 
7
18
  ### Added (design pipeline — 2 new capabilities)
@@ -197,9 +197,35 @@ After the per-widget property comparison, run a mechanical SVG-based diff to cat
197
197
 
198
198
  This step catches spacing rhythm, alignment drift, and proportion issues that pass the per-widget property check but are visually wrong in aggregate.
199
199
 
200
+ ## Step 3.75: DOM Box Model Inspection (MANDATORY for fixed-height containers)
201
+
202
+ For each card/widget with a fixed height, inspect the internal space distribution:
203
+
204
+ 1. **Evaluate in browser** (via Playwright) for each card body child:
205
+ - `offsetHeight` (layout box size), `scrollHeight` (content size), `flex-grow` (computed)
206
+
207
+ 2. **Flag inflated elements**: any element where `offsetHeight > scrollHeight * 1.5`
208
+ - This means `flex: 1` or `flex-grow: 1` is inflating the element's box beyond its content
209
+ - Severity: HIGH — "`.kpi` offsetHeight=144px but content only needs 40px — inflated by flex growth"
210
+
211
+ 3. **Verify layout arithmetic**: sum all child `offsetHeight` values + computed gaps. Compare against card body `offsetHeight`:
212
+ - Sum > body → content overflows (❌ DEVIATION)
213
+ - Sum < body by >20px with no centering strategy → space is unaccounted (❌ DEVIATION)
214
+
215
+ 4. **Produce box model table** per widget:
216
+
217
+ ```markdown
218
+ ### Box Model: {widget-name}
219
+
220
+ | # | Element | offsetHeight | scrollHeight | flex-grow | Verdict |
221
+ |---|---------|-------------|-------------|-----------|---------|
222
+ | 1 | .kpi | 144px | 40px | 1 | ❌ INFLATED |
223
+ | 2 | .chart | 74px | 74px | 0 | ✅ MATCH |
224
+ ```
225
+
200
226
  ## Step 4: Summary Report
201
227
 
202
- After all widgets are audited (property tables + SVG structural diff), produce a summary:
228
+ After all widgets are audited (property tables + SVG structural diff + box model), produce a summary:
203
229
 
204
230
  ```markdown
205
231
  ## Design Audit Summary
@@ -785,6 +785,49 @@ aggregate visual drift that individual property checks miss.
785
785
  This step catches spacing rhythm, alignment drift, and proportion issues
786
786
  that pass the property-level check but are visually wrong in aggregate.
787
787
 
788
+ ## Step 5.5: DOM Box Model Inspection (MANDATORY for fixed-height containers)
789
+
790
+ The property table catches wrong values. The SVG overlay catches wrong positions.
791
+ This step catches wrong SPACE DISTRIBUTION — elements whose box model is inflated
792
+ by flex growth, pushing siblings out of position even when the visual appears close.
793
+
794
+ For each card/widget with a fixed height (container_height is not 'auto'):
795
+
796
+ 1. Use Playwright to evaluate in the browser:
797
+ ```javascript
798
+ // For each child element of the card body:
799
+ const children = await page.$$eval('.card-body > *', els =>
800
+ els.map(el => ({
801
+ selector: el.className,
802
+ offsetHeight: el.offsetHeight,
803
+ scrollHeight: el.scrollHeight,
804
+ computedFlex: getComputedStyle(el).flex,
805
+ computedFlexGrow: getComputedStyle(el).flexGrow,
806
+ }))
807
+ );
808
+ ```
809
+
810
+ 2. Flag any element where `offsetHeight > scrollHeight * 1.5`:
811
+ This means the element's layout box is ≥50% larger than its content.
812
+ Symptom: element is using `flex: 1` or `flex-grow: 1` and inflating.
813
+ ❌ DEVIATION (severity HIGH): '{selector} offsetHeight={X}px but
814
+ content only needs {scrollHeight}px — inflated by flex growth.
815
+ Fix: remove flex:1 from this element, apply justify-content:center
816
+ on its parent container instead.'
817
+
818
+ 3. Verify layout arithmetic:
819
+ - Read the widget contract's Internal Layout Arithmetic section
820
+ - Sum all child offsetHeights + computed gaps
821
+ - Compare against the card body's offsetHeight
822
+ - If sum > body height → ❌ DEVIATION: content overflows
823
+ - If sum < body height by >20px with no centering strategy → ❌ DEVIATION
824
+
825
+ 4. Produce box model table:
826
+ | # | Element | offsetHeight | scrollHeight | flex-grow | Verdict |
827
+ |---|---------|-------------|-------------|-----------|---------|
828
+ | 1 | .kpi | 144px | 40px | 1 | ❌ INFLATED |
829
+ | 2 | .chart | 74px | 74px | 0 | ✅ MATCH |
830
+
788
831
  ## Step 6: Report Deviations
789
832
 
790
833
  For each ❌ DEVIATION, write a specific finding:
@@ -288,7 +288,14 @@ cannot be redeemed by visual polish.
288
288
  | # | SVG Element | SVG Position | Built Position | Δ px | Verdict |
289
289
  g. Flag unmapped SVG elements as MISSING, unmapped DOM elements as EXTRA
290
290
  This catches aggregate visual drift that property-level checks miss.
291
- 8. Write results (property table + SVG diff) to .gsd-t/contracts/design-contract.md
291
+ 8. DOM Box Model Inspection (for fixed-height containers):
292
+ a. For each card body child, evaluate: offsetHeight, scrollHeight, flex-grow
293
+ b. Flag elements where offsetHeight > scrollHeight * 1.5 as INFLATED
294
+ (element using flex:1 when it shouldn't — box larger than content)
295
+ c. Verify layout arithmetic: sum of child heights + gaps = body height
296
+ d. Produce box model table:
297
+ | Element | offsetHeight | scrollHeight | flex-grow | Verdict |
298
+ 9. Write results (property table + SVG diff + box model) to .gsd-t/contracts/design-contract.md
292
299
  under '## Verification Status'
293
300
  9. Any ❌ → append to .gsd-t/qa-issues.md with [VISUAL] tag
294
301
  10. Report: DESIGN VERIFIED | DESIGN DEVIATIONS FOUND ({count})"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekyzinc/gsd-t",
3
- "version": "2.70.10",
3
+ "version": "2.70.11",
4
4
  "description": "GSD-T: Contract-Driven Development for Claude Code — 54 slash commands with headless CI/CD mode, graph-powered code analysis, real-time agent dashboard, execution intelligence, task telemetry, doc-ripple enforcement, backlog management, impact analysis, test sync, milestone archival, and PRD generation",
5
5
  "author": "Tekyz, Inc.",
6
6
  "license": "MIT",
@@ -281,6 +281,47 @@ MANDATORY:
281
281
 
282
282
  **GOOD** — Extracting gap as exactly `24px` from the design, then: `display: flex; gap: 1.5rem; /* 24px — design contract: section-gap */`
283
283
 
284
+ ### Flex Centering Anti-Pattern (MANDATORY)
285
+
286
+ ```
287
+ NEVER use flex: 1 on a content element to center its text/content.
288
+ flex: 1 makes the ELEMENT GROW to fill available space — the content
289
+ centers within an oversized box, but the box itself displaces siblings.
290
+
291
+ WRONG — content element grows, inflated box shifts layout:
292
+ .kpi { flex: 1; display: flex; justify-content: center; }
293
+
294
+ RIGHT — parent grows, children keep natural size:
295
+ .body { flex: 1; display: flex; flex-direction: column;
296
+ justify-content: center; }
297
+ .kpi { /* no flex: 1 — natural height only */ }
298
+
299
+ RULE: flex: 1 belongs on CONTAINERS, not on CONTENT elements.
300
+ To center content vertically, apply justify-content: center
301
+ on the parent — never flex: 1 on the child.
302
+ ```
303
+
304
+ ### Fixed-Height Container Arithmetic (MANDATORY)
305
+
306
+ ```
307
+ When a card or container has a fixed height, BEFORE writing any CSS:
308
+ 1. Compute the total available body height:
309
+ body_available = card_height - padding_top - padding_bottom
310
+ - header_height - header_to_body_gap
311
+ 2. List every child element's height (from the design contract)
312
+ 3. List every gap between children
313
+ 4. SUM them: total_content = child1 + gap1 + child2 + gap2 + ...
314
+ 5. Compare: total_content MUST ≤ body_available
315
+ 6. If total_content < body_available:
316
+ Document the centering strategy (justify-content: center on parent)
317
+ 7. If total_content > body_available:
318
+ The design extraction is wrong — go back to Figma
319
+
320
+ This arithmetic goes in the widget contract's Internal Layout
321
+ Arithmetic section. The implementation MUST match the arithmetic.
322
+ If gap: 12px makes the math exceed body_available, use gap: 8px.
323
+ ```
324
+
284
325
  ---
285
326
 
286
327
  ## 9. Responsive Breakpoint Strategy
@@ -628,4 +669,7 @@ Before marking any design implementation task as complete:
628
669
  - [ ] Accessibility: focus indicators, alt text, ARIA where needed, 44px touch targets
629
670
  - [ ] No magic numbers — every value is documented or uses a design token
630
671
  - [ ] SVG structural overlay comparison completed — geometry diff ≤2px per element
672
+ - [ ] DOM box model inspection passed — no inflated elements (offsetHeight >> scrollHeight)
673
+ - [ ] Layout arithmetic verified — child heights + gaps = body available height (fixed-height cards)
674
+ - [ ] No content element uses `flex: 1` for centering — only parent containers
631
675
  - [ ] Verification results logged in design contract Verification Status table
@@ -95,6 +95,41 @@ This section specifies how elements are sized, spaced, and aligned WITHIN the ca
95
95
  - `body_layout` + `body_justify` + `body_align` together define whether the chart is centered in its card, left-aligned, or stretched. Get this wrong and every widget "looks off."
96
96
  - These values are WIDGET-OWNED — they describe how the widget positions its elements, not the elements' internal specs (which live in element contracts).
97
97
 
98
+ ### Internal Layout Arithmetic (MANDATORY for fixed-height cards)
99
+
100
+ When `container_height` is fixed (not `auto`), you MUST compute and document the internal height budget. The math must add up exactly — no approximation.
101
+
102
+ ```
103
+ card_height: {e.g., 334px}
104
+ card_padding_top: {e.g., 16px}
105
+ card_padding_bottom: {e.g., 16px}
106
+ header_height: {title + subtitle + gap} = {e.g., 48px}
107
+ header_to_body_gap: {e.g., 16px}
108
+ ─────────────────────────────────────────────────
109
+ body_available: {card_height - padding_top - padding_bottom
110
+ - header_height - header_to_body_gap}
111
+ = {e.g., 334 - 16 - 16 - 48 - 16 = 238px}
112
+
113
+ body_breakdown:
114
+ kpi_height: {natural content height, e.g., 40px — NOT flex:1}
115
+ kpi_to_chart_gap: {e.g., 16px}
116
+ chart_section: {bar + gap + labels + gap + legend}
117
+ = {e.g., 30 + 8 + 12 + 8 + 16 = 74px}
118
+ ────────────────────
119
+ total_body_content: {40 + 16 + 74 = 130px}
120
+ remaining_space: {238 - 130 = 108px}
121
+
122
+ centering_strategy: {e.g., body uses flex-column + justify-content: center
123
+ to vertically center the content group (KPI + chart)
124
+ in the 238px body area. KPI keeps natural height.}
125
+ ```
126
+
127
+ **Rules:**
128
+ - Every row must be an exact pixel value extracted from the Figma design
129
+ - The sum of all body content MUST equal `body_available` OR explicitly document how remaining space is distributed (centering, padding, etc.)
130
+ - **NEVER use `flex: 1` on a content element (KPI, label, text) to center it.** `flex: 1` makes the element grow to fill available space, inflating its box model. Use `flex: 1` + `justify-content: center` on the PARENT container instead. The parent grows; children keep natural size.
131
+ - If the math doesn't add up, the design extraction is incomplete — go back to Figma
132
+
98
133
  ## Data Binding
99
134
 
100
135
  **Widget input shape:**
@@ -189,6 +224,9 @@ Widget-level verification runs AFTER all referenced elements pass their own veri
189
224
  - [ ] Element sizing matches design (chart_width, chart_height, legend_width)
190
225
  - [ ] Legend alignment matches design (footer_legend_justify: center vs left)
191
226
  - [ ] Card container values match design (padding, border, radius, shadow)
227
+ - [ ] Layout arithmetic adds up: sum of child heights + gaps = body_available (fixed-height cards only)
228
+ - [ ] No content element uses `flex: 1` for centering — only parent containers may use `flex: 1`
229
+ - [ ] DOM box model check: no element's offsetHeight >> its content height (inflated box = wrong flex)
192
230
  - [ ] Responsive breakpoints adapt as specified
193
231
  - [ ] Data binding produces correct element inputs (spot-check with sample data)
194
232
  - [ ] Inter-element interactions fire (hover sync, click propagation)