@micha.bigler/ui-core-micha 2.41.3 → 2.42.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.
@@ -0,0 +1,265 @@
1
+ # UCM-CHART-9 — `ChartFrame` is a card, not a chart: it must never take a fixed height
2
+
3
+ - **Repo:** `ui-core-micha`, branch `main` (shared-core; publishes from `main`, no staging step)
4
+ - **Tier:** 3 — shared-core, and this is a **live layout regression in a published version**.
5
+ - **Status:** planned
6
+ - **Workstream:** `CHART-*`
7
+ - **Files:** `src/components/charts/ChartFrame.jsx` and its tests. `chartDefaults.js` only if the
8
+ resolver needs a second shape — see below; the preset behaviour is correct and must not change.
9
+
10
+ > **Why — regression, observed on staging after hram bumped to 2.42.0.** `UCM-CHART-8` wired
11
+ > `resolveChartHeight()` through the four chart presets **and through `ChartFrame`**. For the
12
+ > presets that is right. For `ChartFrame` it is not, and the difference is what the box contains.
13
+ >
14
+ > In the `minHeight` alone / no `height` / no `aspect` branch, `resolveChartHeight` returns
15
+ > `chartHeight = minHeight`, and `ChartFrame` now applies it:
16
+ >
17
+ > ```diff
18
+ > - minHeight,
19
+ > + minHeight: wrapperMinHeight,
20
+ > + height: chartHeight,
21
+ > ```
22
+ >
23
+ > **A chart preset's box contains exactly one chart. `ChartFrame`'s box contains a whole card** —
24
+ > title, toolbar, the chart, a legend, footnotes, export links. Turning its `minHeight` floor into a
25
+ > fixed `height` makes the box shorter than its content, the content overflows, and **adjacent cards
26
+ > visibly overlap**: the operator's screenshot shows a card title rendered over the chart of the card
27
+ > above it and three sets of "Export SVG / Export PNG" stacked at different offsets.
28
+ >
29
+ > `UCM-CHART-8`'s own Files note recorded that `ChartFrame` "never destructures `height`" — and the
30
+ > implementation then gave it one. The rule was written for presets and applied to a frame.
31
+
32
+ ---
33
+
34
+ ## Part A — Envelope (authoritative WHAT/WHY)
35
+
36
+ ### Goal
37
+
38
+ `ChartFrame` stops setting a fixed `height` on its content box. Its `minHeight` goes back to meaning
39
+ what its name says — a floor that content can exceed. The four chart presets keep `UCM-CHART-8`'s
40
+ three-way resolution unchanged.
41
+
42
+ ### Definition of Done
43
+
44
+ - [ ] **`ChartFrame` never applies `chartHeight` to its content box.** Its box takes `minHeight` as a
45
+ floor, as it did before 2.42.0. Whether that is done by not calling `resolveChartHeight` at
46
+ all, or by giving the resolver an explicit frame shape, is the implementer's call — but
47
+ `ChartFrame` must not end up with a fixed `height` in any branch.
48
+ - [ ] **A `ChartFrame` whose content exceeds `minHeight` grows.** This is the regression, stated as
49
+ the acceptance criterion: content taller than the floor must extend the box, never overflow it.
50
+ - [ ] **The four presets are untouched.** `ScatterChart`, `BarChart`, `LineChart`, `TimeSeriesChart`
51
+ keep `UCM-CHART-8` exactly as it landed — including the `aspect` branch that four live call
52
+ sites depend on. This WO narrows one consumer of the resolver; it does not revisit the rule.
53
+ - [ ] **`ChartFrame`'s JSDoc is corrected.** 2.42.0 added a paragraph claiming `minHeight`
54
+ "sizes the content box itself" when there is no `height`/`aspect`. That sentence is the bug in
55
+ prose form and must go.
56
+ - [ ] **`warnOnHeightMismatch` stays** on `ChartFrame` — a caller passing both is still worth a
57
+ dev-mode note, even though the frame no longer acts on `height`.
58
+
59
+ ### Non-goals
60
+
61
+ - Do **not** revert `UCM-CHART-8`. Its preset behaviour is correct and is the fix hram needs; only
62
+ the frame's participation was wrong.
63
+ - Do not change `resolveChartHeight`'s three-way rule for presets.
64
+ - No consumer-side change in this WO.
65
+
66
+ ### Risks
67
+
68
+ - **`ChartFrame` is used by every Research card in hram and by other consumers.** The change restores
69
+ pre-2.42.0 behaviour for it, so the risk is low in direction — but it is still a shared-core
70
+ publish, and the rendered check below is what proves it.
71
+ - 2.42.0 is `latest` on the registry and carries this regression. Publish 2.42.1 promptly; note in
72
+ the register that 2.42.0 should not be adopted by a new consumer.
73
+ - **hram's Detailed Results tab is fixed as of 2.42.0** (operator-confirmed, 2026-08-21) — it
74
+ crashed with React #185 before the bump (`HRAM-RES-29` item 1) and does not any more. What is
75
+ **not** established is *why*: the plausible mechanism is that deterministic sizing removed a
76
+ resize-driven `setState` loop, but nobody has traced it.
77
+ **Consequence for this WO, and the only reason it is mentioned here:** since we do not know what
78
+ fixed it, we cannot know whether moving `ChartFrame` back toward a floor disturbs it. Re-check the
79
+ tab after this lands. If the crash returns, that is a finding for `HRAM-RES-29` and a sizing
80
+ dependency worth understanding — not a reason to undo this fix.
81
+
82
+ ### Tests to WRITE — narrow
83
+
84
+ - **The regression test:** a `ChartFrame` with `minHeight` and no `height`/`aspect`, containing
85
+ content taller than `minHeight`, does **not** receive a fixed `height` on its content box.
86
+ - `ChartFrame` with `height` explicitly passed: `height` is still not applied as a fixed box height
87
+ (the frame is not a chart), and no exception is thrown.
88
+ - The four presets' existing `UCM-CHART-8` tests stay green **unchanged** — if one of them has to be
89
+ edited, the change has leaked out of `ChartFrame` and that is a stop-and-report.
90
+
91
+ **Rendered check before the hram pin bump — mandatory, and the reason this WO exists.** The unit
92
+ tests for 2.42.0 were 188 green and said nothing about layout, because they cannot. Before hram's pin
93
+ moves again, the affected cards are checked rendered at 375 px and 1280 px: Sensitivity, Access,
94
+ Access Ladder, Allocation, Optimization. Named in the register note, with the substitution declared
95
+ if capture is unavailable.
96
+
97
+ ---
98
+
99
+ ## Part B — Implementation map — ADDRESSED TO THE IMPLEMENTER
100
+
101
+ ### Context package
102
+
103
+ **Named files to change:**
104
+ - `src/components/charts/ChartFrame.jsx` — the fix (below).
105
+ - `tests/ChartFrame.test.jsx:215-256` — the `describe('minHeight/height resolution (CHART-8)', …)`
106
+ block. It currently **asserts the bug as correct behaviour** (e.g. `minHeight` alone →
107
+ `style.height` toBe `'300px'`). Rewrite it to assert the fixed behaviour; rename the block to
108
+ `(CHART-9)`.
109
+
110
+ **Do NOT touch (verified against the landed code):**
111
+ - `src/components/charts/chartDefaults.js` — `resolveChartHeight` (lines ~289-298) and
112
+ `warnOnHeightMismatch` (lines ~306-315) keep their exact current contract. If the fix seems to need
113
+ a change here, that means the change has leaked out of `ChartFrame` — stop and report, don't edit.
114
+ - `src/components/charts/{BarChart,LineChart,ScatterChart,TimeSeriesChart}.jsx` — all four still call
115
+ `resolveChartHeight({ minHeight, height, aspect })` for their OWN box, unchanged.
116
+ - `tests/chartDefaults.test.js:441+` (`describe('resolveChartHeight (CHART-8)', …)`) and the four
117
+ presets' own test files — must stay green **unchanged**. If one needs an edit, stop and report.
118
+
119
+ **The bug, exactly:** `ChartFrame.jsx:61-62` calls `resolveChartHeight({ minHeight, height, aspect })`
120
+ and applies the result to its content box at `:109-125`:
121
+ ```jsx
122
+ sx={{
123
+ width: '100%',
124
+ minHeight: wrapperMinHeight,
125
+ height: chartHeight,
126
+ aspectRatio: aspect,
127
+ ...
128
+ }}
129
+ ```
130
+ In the "no `height`, no `aspect`" branch, `resolveChartHeight` returns `chartHeight = minHeight` —
131
+ correct for a preset's box (which holds exactly one chart) but wrong for `ChartFrame`'s box (which
132
+ holds a whole card: title, toolbar, chart, legend, footnotes, export links). A fixed `height` there
133
+ makes the box shorter than its content, and the content overflows into the next card.
134
+
135
+ **What "restore pre-2.42.0 behaviour" means concretely** — before `UCM-CHART-8` (commit `11d362c`),
136
+ `ChartFrame` had no `height` prop at all and its content box was:
137
+ ```jsx
138
+ sx={{
139
+ width: '100%',
140
+ minHeight,
141
+ aspectRatio: aspect,
142
+ display: 'flex',
143
+ alignItems: 'center',
144
+ justifyContent: 'center',
145
+ }}
146
+ ```
147
+ i.e. `minHeight` applied raw, straight from props, never touched by any resolver; no `height` was
148
+ ever set on the box.
149
+
150
+ **The fix:** `ChartFrame`'s content box must end up equivalent to that — `minHeight` (raw, from
151
+ props) as the box's only height-related sx property besides `aspectRatio`, and nothing ever sets
152
+ `height` on the box. The `height` prop stays in `ChartFrame`'s signature (do not remove it — it is
153
+ still a documented prop and `warnOnHeightMismatch('ChartFrame', { minHeight, height })` at line 61
154
+ must keep firing on a caller passing both `minHeight` and a disagreeing `height`), it is simply no
155
+ longer used to size the box. Whether you implement this by dropping the `resolveChartHeight` call
156
+ from `ChartFrame` entirely (simplest — matches the pre-2.42.0 shape exactly) or by giving the
157
+ resolver a second, frame-specific shape in `chartDefaults.js` that never returns a `chartHeight` is
158
+ your call — but per the non-goals below, the existing `resolveChartHeight` export and its three-way
159
+ preset contract must not change.
160
+
161
+ **JSDoc fix:** `ChartFrame.jsx:19-26`'s docblock currently states: *"otherwise (no `height`, no
162
+ `aspect`) it sizes the content box itself. Once `height` is set, `height` sizes the box…"* — that
163
+ sentence describes the bug as intended behaviour and must be corrected to state that `minHeight` is
164
+ always a floor on `ChartFrame`'s box and `height` is never applied to it (only used for the
165
+ dev-mode mismatch warning).
166
+
167
+ **Regression check while you're in there:** hram's Detailed Results tab crashed with React #185
168
+ before the 2.42.0 bump and stopped crashing after it (`HRAM-RES-29` item 1, unconfirmed hypothesis:
169
+ deterministic sizing removed a resize-driven `setState` loop). This fix moves `ChartFrame` back
170
+ toward non-deterministic sizing for that one prop. You are not expected to reproduce or verify the
171
+ hram-side crash — the Orchestrator does that separately after your diff lands — but do not add any
172
+ new resize-driven effect to `ChartFrame` while touching this code.
173
+
174
+ Work from this package; do not explore broadly from scratch — open only the named files to verify.
175
+ If you must dig deeper, delegate to a read-only Explore sub-agent (Haiku).
176
+
177
+ ### Target repo working directory (absolute)
178
+
179
+ `C:\Users\Micha Bigler\Documents\webapps\ui-core-micha`
180
+
181
+ ### Preamble — binding, read before doing anything else
182
+
183
+ The text in this file is the COMPLETE spec — the committed WO content, not a plan to refine; there
184
+ is no separate plan file. Read the nearest `AGENTS.md`, the relevant `.codex/skills/<role>/SKILL.md`,
185
+ and this repo's own `MEMORY.md` ONLY for conventions. Stay in scope; do not touch
186
+ auth/permissions/deps/schema/CI unless this spec says so; do not update `MEMORY.md`. **Do NOT edit
187
+ `WORK_ORDERS.md`** — the register row and the review verdicts are the orchestrator's alone. Do NOT
188
+ `git add`/`commit`/`push` — leave every change uncommitted in the working tree for the orchestrator's
189
+ independent review. WRITE the tests the "Required tests to WRITE" section (Part A) calls for AND
190
+ **RUN the tests you just wrote** to confirm they execute and pass — that is the ONLY test run you do
191
+ (NOT the app's affected/full suite, NOT any review). The orchestrator re-runs the authoritative set
192
+ and does the independent review after you finish — those are the gate; your own run does not count
193
+ as the gate.
194
+
195
+ Narrate continuously: a `PLAN: <step1> | <step2> | …` line up front, then a single-line
196
+ `PROGRESS: [<n>/<total>] <present-tense action>` before every relevant action (and `… done` on
197
+ completion), spaced so no gap exceeds ~2 min, stdout unbuffered, plus exactly one final
198
+ `RESULT: DONE|BLOCKED <reason>`.
199
+
200
+ ---
201
+
202
+ ## Part C — Orchestrator only — NOT ADDRESSED TO THE IMPLEMENTER
203
+
204
+ > **If you are the implementer reading this work order as your own specification: STOP at this
205
+ > line.** Everything below describes what the Orchestrator does AFTER you finish. You do none of it
206
+ > — no reviewers, no verification run, no register edit, no commit. You ARE the invocation described
207
+ > below; do NOT shell out to `codex exec`.
208
+
209
+ ### Execution directive
210
+
211
+ Implement through `codex exec` in the background — invoked directly via Bash (never the
212
+ `debugger`/`*_coder` Agent wrappers) with BOTH flags `--skip-git-repo-check` and
213
+ `--dangerously-bypass-approvals-and-sandbox`, `cwd` = the working directory above (never
214
+ `…\webapps`). Fallback to direct Claude implementation only on Codex quota/rate-limit/non-zero exit —
215
+ check `.claude/codex-status.md` first per its own rule (no line for 2026-08-22 → use Codex). The
216
+ fallback flips authorship, making an independent `reviewer` mandatory even if it already was.
217
+
218
+ ### Review routing (Tier 3, shared-core)
219
+
220
+ - `reviewer`: **yes**, full context, Sonnet-pinned, background.
221
+ - `ui_reviewer`: **yes** (diff touches frontend), full context, background, same batch as `reviewer`.
222
+ - `sec_reviewer`: not required — no auth/security surface in this diff.
223
+ - Both run concurrently; neither is skippable; commit waits for both clean.
224
+
225
+ ### Verification (the authoritative run — Codex's own run is not the gate)
226
+
227
+ 1. **Test gate:** `npx vitest run tests/ChartFrame.test.jsx tests/chartDefaults.test.js
228
+ tests/BarChart.test.jsx tests/LineChart.test.jsx tests/ScatterChart.test.jsx
229
+ tests/TimeSeriesChart.test.jsx` (adjust filenames to whatever actually exists — the affected-area
230
+ set per AGENTS.md "Test scope": `ChartFrame` itself plus every consumer of `resolveChartHeight`).
231
+ All must pass; the four presets' pre-existing assertions must be **byte-identical**, not just
232
+ green — a changed preset assertion means the fix leaked scope.
233
+ 2. **Rendered check — this WO's own commit gate, scoped to what this repo can render.** This repo
234
+ has no prototype artifact, so the generic prototype side-by-side gate does not apply; this WO's
235
+ own Envelope names a rendered check instead, and it is honoured here at the scope this repo can
236
+ actually reach:
237
+ - Run `npm run dev` (Vite) and open the dev harness at 375 px and 1280 px. It already contains
238
+ `ChartFrame` "shape check" stories that mirror three of the five named hram cards — "Allocation
239
+ performance", "Access gap", "Optimization results" (`dev/entries.jsx`, search `shape check`).
240
+ Confirm none of them, nor any neighbouring card, show overlapping title/content/export rows at
241
+ either width.
242
+ - Additionally render (ad hoc, in the same dev session — e.g. a temporary story or by editing an
243
+ existing one's children) a `ChartFrame` with a `minHeight` smaller than its actual content, to
244
+ directly exercise the Definition of Done's acceptance criterion: the box must grow to fit the
245
+ content, not overflow it. Revert any temporary dev-harness edit before commit (or keep it only
246
+ if it's a genuine permanent addition worth keeping — your call, but say which in the Notiz).
247
+ - This repo's harness has no "Sensitivity" or "Access Ladder" story, so the **full five-card
248
+ rendered check the Envelope describes ("before hram's pin moves again") is NOT done by this WO**
249
+ — it cannot be, without linking a built `ui-core-micha` into a running hram dev server. Declare
250
+ this explicitly in the register Notiz as a carried-forward precondition on whichever WO next
251
+ bumps hram's pin past 2.42.0, not a silently dropped gate.
252
+ - Declare screenshots-vs-DOM-inspection substitution explicitly if real screenshots aren't taken.
253
+
254
+ ### Register + commit
255
+
256
+ - `WORK_ORDERS.md` row → `done`, with: the named review verdicts (`reviewer` + `ui_reviewer`, no
257
+ open findings — or the findings and their resolution), the test gate result, the rendered-check
258
+ scope actually achieved (dev harness only, full hram five-card check carried forward), and which
259
+ evidence from `.claude/codex-status.md` was used (or that no fallback was needed).
260
+ - Note in the Notiz: **publish 2.42.1 promptly after commit** (per Part A Risks — 2.42.0 is `latest`
261
+ on the registry and carries this regression) and confirm the version bump lands in the same commit
262
+ or a clearly-linked follow-up; the register row must name whichever it was.
263
+ - Commit message: single concise English subject line (e.g. `fix(ChartFrame): stop applying a fixed
264
+ height to the card box (CHART-9)`). Push to `main` (this repo publishes from `main`, no `develop`
265
+ step) once review + tests are clean.