@micha.bigler/ui-core-micha 2.30.0 → 2.31.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.
- package/WORK_ORDERS.md +2 -2
- package/dev/entries.jsx +58 -0
- package/dist/components/charts/BarChart.js +8 -6
- package/dist/components/charts/LineChart.js +23 -6
- package/dist/components/charts/TimeSeriesChart.js +12 -3
- package/dist/components/charts/chartDefaults.js +85 -0
- package/dist/components/charts/chartLabels.js +31 -0
- package/dist/components/charts/yearTickInterval.js +7 -0
- package/dist/index.js +2 -0
- package/dist/theme/index.js +2 -0
- package/dist/theme/themeCompleteness.js +18 -2
- package/dist/theme/tokens.js +1 -1
- package/package.json +1 -1
- package/src/components/charts/BarChart.jsx +38 -9
- package/src/components/charts/LineChart.jsx +62 -9
- package/src/components/charts/TimeSeriesChart.jsx +21 -0
- package/src/components/charts/chartDefaults.js +120 -0
- package/src/components/charts/chartLabels.js +36 -0
- package/src/components/charts/yearTickInterval.js +7 -0
- package/src/index.js +7 -0
- package/src/theme/index.js +7 -0
- package/src/theme/themeCompleteness.js +16 -0
- package/src/theme/tokens.js +1 -1
- package/tests/BarChart.test.jsx +4 -1
- package/tests/LineChart.test.jsx +5 -2
- package/tests/chartDefaults.test.js +208 -0
- package/tests/chartLabels.test.js +50 -0
- package/tests/createAppTheme.test.js +9 -2
- package/tests/themeCompleteness.test.js +31 -0
- package/tests/timeSeriesLegend.test.js +99 -0
- package/work-orders/CHART-6.md +199 -1
- package/work-orders/THEME-2.md +339 -0
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
# THEME-2 — Two defects from the THEME-1/CHART-6 landings: `warning.main` contrast, and `grid` replacing instead of merging
|
|
2
|
+
|
|
3
|
+
**Target repo:** `ui-core-micha` (branch `main` — this repo has no `develop`)
|
|
4
|
+
**Tier:** 2 (shared core — `ui-core-micha` is named in AGENTS.md's Tier-2 forcing list)
|
|
5
|
+
**Review:** independent `reviewer` **and** `ui_reviewer` — spawned concurrently, both mandatory before commit
|
|
6
|
+
**Version target:** `2.31.1` (patch — one palette value corrected, one merge bug fixed, one assertion rule added; no API change)
|
|
7
|
+
**Decision record:** `webapp-management/DESIGN_SYSTEM_PROGRAM.md` → "Open follow-ups from the two landings"
|
|
8
|
+
|
|
9
|
+
Short-form WO: both defects are fully diagnosed and measured. There is no design question in either.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## A. Envelope
|
|
14
|
+
|
|
15
|
+
### Goal
|
|
16
|
+
|
|
17
|
+
Fix the two defects found after `THEME-1` (`96992cf`) and `CHART-6` (`6dedc62`) landed, and in each
|
|
18
|
+
case close the **mechanism** rather than only the instance — both are the same failure class as
|
|
19
|
+
something already fixed, which is why they recurred.
|
|
20
|
+
|
|
21
|
+
### Defect 1 — `warning.main` fails AA as a foreground
|
|
22
|
+
|
|
23
|
+
THEME-1's R1 fix gave every status channel an explicit `main`/`light`/`dark`/`contrastText` (correct
|
|
24
|
+
— MUI was otherwise filling its stock hues for `color="success"` and friends). It put the **fill**
|
|
25
|
+
tone in `main`. Measured against `#FFFFFF`:
|
|
26
|
+
|
|
27
|
+
| Channel | `main` | as foreground | |
|
|
28
|
+
|---|---|---|---|
|
|
29
|
+
| success | `#1B8038` | 5.010 | passes |
|
|
30
|
+
| error | `#BF3227` | 5.674 | passes |
|
|
31
|
+
| **warning** | `#C08A2C` | **3.038** | **fails AA (4.5)** |
|
|
32
|
+
|
|
33
|
+
`main`/`contrastText` pairs are all fine (warning 5.078 with dark ink). The failure is only when
|
|
34
|
+
`main` is used as a **foreground on a light surface** — `<Typography color="warning.main">`,
|
|
35
|
+
`color="warning"` on an icon, and an outlined warning chip, whose border and label both come from
|
|
36
|
+
`main`.
|
|
37
|
+
|
|
38
|
+
**Why warning specifically, and why this is not carelessness:** green and red can serve both roles
|
|
39
|
+
with one value. Amber cannot. A legible amber **fill** needs dark text on it and must therefore stay
|
|
40
|
+
light; a legible amber **text** must be dark. The two requirements pull in opposite directions.
|
|
41
|
+
Warning is the one channel where "one hex for both roles" is impossible in principle — so the
|
|
42
|
+
pattern that works for success and error had to break here.
|
|
43
|
+
|
|
44
|
+
**Fix:** `warning.main` = `#976100` (the text tone already in the same token block, 5.216 on white),
|
|
45
|
+
`contrastText` = `#FFFFFF`. The light amber stays available as `warning.fill` for deliberate fill
|
|
46
|
+
use, unchanged.
|
|
47
|
+
|
|
48
|
+
**Accepted visual consequence, stated so nobody treats it as a regression:** a filled
|
|
49
|
+
`color="warning"` Button/Chip becomes a darker brown with white text instead of a lighter amber with
|
|
50
|
+
dark text. That is the price of one token serving MUI's `main` contract, and it is the operator's
|
|
51
|
+
call already recorded in the programme doc.
|
|
52
|
+
|
|
53
|
+
**Close the mechanism, not just the value:** add an assertion rule that checks **every** status
|
|
54
|
+
channel's `main` against `#FFFFFF` and `background.default` at 4.5:1. Without it the next channel
|
|
55
|
+
added repeats this exactly — the existing contrast checks were designed before R1 introduced `main`,
|
|
56
|
+
which is why they did not catch it.
|
|
57
|
+
|
|
58
|
+
### Defect 2 — `grid` is replaced, not merged
|
|
59
|
+
|
|
60
|
+
`LineChart` and `BarChart` declare `grid = { horizontal: true }` as a plain default parameter and
|
|
61
|
+
pass it straight through. A caller writing `grid={{ vertical: true }}` — intending to *add* vertical
|
|
62
|
+
lines — silently loses the horizontal ones.
|
|
63
|
+
|
|
64
|
+
This is the same class as the `scaleType` bug the rendered gate caught during CHART-6: **a partial
|
|
65
|
+
caller object erases a default.** `xAxis`, `yAxis`, `margin` and `slotProps` all go through merge
|
|
66
|
+
helpers; `grid` alone does not.
|
|
67
|
+
|
|
68
|
+
**Fix:** merge `grid` with the default the way the sibling props already do, so a caller adds to it
|
|
69
|
+
rather than replacing it.
|
|
70
|
+
|
|
71
|
+
**Close the mechanism:** audit the remaining object-valued props the wrappers default or forward
|
|
72
|
+
(`slots`, `tickLabelStyle` and anything CHART-6 introduced) for the same replace-instead-of-merge
|
|
73
|
+
shape, and state the result — either "all others already merge" or a named list. **Audit and report;
|
|
74
|
+
do not refactor beyond `grid`** unless the audit finds another live instance, in which case fix that
|
|
75
|
+
too and say so.
|
|
76
|
+
|
|
77
|
+
### Non-goals / do not touch
|
|
78
|
+
|
|
79
|
+
- The other status channels' `main` values — success and error measure fine and stay.
|
|
80
|
+
- `warning.fill` / `warning.text` / `warning.bg` — unchanged.
|
|
81
|
+
- The reference sheet's committed HTML artifact. It is the frozen spec of the accepted baseline;
|
|
82
|
+
`warning.main` is a channel the sheet never depicted (see Verification).
|
|
83
|
+
- Anything in `CHART-6`'s scope beyond the `grid` merge and the audit.
|
|
84
|
+
- No behaviour, permission or data-contract change.
|
|
85
|
+
|
|
86
|
+
### Risks
|
|
87
|
+
|
|
88
|
+
- **A palette value change is visible.** Any app already using `color="warning"` sees a darker
|
|
89
|
+
filled control. No app has an adoption WO yet, so the blast radius today is ucm's own harness — but
|
|
90
|
+
say it in the release note rather than let someone find it.
|
|
91
|
+
- **Adding an assertion rule can turn a green suite red.** Safe today by the ratchet: the
|
|
92
|
+
completeness check is a hard failure only for an app whose adoption WO has landed, and none has.
|
|
93
|
+
It must stay that way — the new rule must not become hard for non-adopters.
|
|
94
|
+
- **No staging net.** A push to `main` touching `src/**` publishes to npm at once; the independent
|
|
95
|
+
review is the only gate and is not back-fillable.
|
|
96
|
+
- **The `grid` merge changes behaviour for any caller who passes a partial `grid` today.** That is
|
|
97
|
+
the point, but it means the rendered check should look at a chart that passes `grid` explicitly if
|
|
98
|
+
one exists.
|
|
99
|
+
|
|
100
|
+
### Required tests to WRITE
|
|
101
|
+
|
|
102
|
+
Narrow. Extend the existing files rather than adding new ones.
|
|
103
|
+
|
|
104
|
+
**`tests/themeCompleteness.test.js`**
|
|
105
|
+
|
|
106
|
+
1. Every status channel's `main` clears 4.5:1 against `#FFFFFF` **and** against
|
|
107
|
+
`background.default`. **Prove non-vacuity** by restoring `warning.main` to `#C08A2C` and
|
|
108
|
+
confirming this test fails — that is the whole point of the rule.
|
|
109
|
+
2. The new rule reports, and does not hard-fail, for a theme belonging to an app without a landed
|
|
110
|
+
adoption WO (the ratchet stays intact).
|
|
111
|
+
|
|
112
|
+
**`tests/chartDefaults.test.js`**
|
|
113
|
+
|
|
114
|
+
3. A caller passing `grid={{ vertical: true }}` receives **both** `vertical: true` and the default
|
|
115
|
+
`horizontal: true`. **Prove non-vacuity** by reverting to the plain default parameter and
|
|
116
|
+
confirming the test fails.
|
|
117
|
+
4. A caller passing `grid={false}` (or the documented way to switch the grid off entirely) still
|
|
118
|
+
gets no grid — merging must not make the default un-removable.
|
|
119
|
+
|
|
120
|
+
Plus `tsc -p tsconfig.build.json --noEmit` clean.
|
|
121
|
+
|
|
122
|
+
**No full-suite run.** Affected-areas set is the two test files above.
|
|
123
|
+
|
|
124
|
+
### Verification
|
|
125
|
+
|
|
126
|
+
- The rendered two-width side-by-side per DS-1, **and this time it must cover what changed**: the
|
|
127
|
+
harness needs a specimen row rendering `color="success|warning|error|info"` on **Button, Chip and
|
|
128
|
+
Alert** — the components where `main` actually resolves. It has none today, which is precisely why
|
|
129
|
+
the gate could not catch defect 1 the first time. Adding that row is part of this WO.
|
|
130
|
+
- A chart specimen that passes a partial `grid`, to show the merge.
|
|
131
|
+
|
|
132
|
+
### Preconditions
|
|
133
|
+
|
|
134
|
+
- `THEME-1` (`2.30.0`) and `CHART-6` (`2.31.0`) landed and published.
|
|
135
|
+
|
|
136
|
+
### Parity guardrail
|
|
137
|
+
|
|
138
|
+
No behaviour, permission or data-contract change. One palette value moves deliberately and visibly;
|
|
139
|
+
everything else must render identically.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## B. Implementation map
|
|
144
|
+
|
|
145
|
+
*Filled by the Orchestrator on `git pull` — see AGENTS.md → "Work Order".*
|
|
146
|
+
|
|
147
|
+
### Execution directive (read this first)
|
|
148
|
+
|
|
149
|
+
> **If you are the implementer reading this work order as your own specification: this section is
|
|
150
|
+
> NOT addressed to you.** It tells the Orchestrator how to invoke you. **You ARE that invocation —
|
|
151
|
+
> do NOT shell out to `codex exec`.**
|
|
152
|
+
>
|
|
153
|
+
> Implement through `codex exec` in the background — invoked directly via Bash (never the
|
|
154
|
+
> `debugger`/`*_coder` Agent wrappers) with BOTH flags `--skip-git-repo-check` and
|
|
155
|
+
> `--dangerously-bypass-approvals-and-sandbox`. **Pass the WO via stdin, not as a positional
|
|
156
|
+
> argument** — `cat work-orders/THEME-2.md | codex exec --skip-git-repo-check
|
|
157
|
+
> --dangerously-bypass-approvals-and-sandbox -` (a positional arg hits Windows' command-line length
|
|
158
|
+
> limit on a WO this size — proven on THEME-1/CHART-6). Fallback to direct Claude implementation
|
|
159
|
+
> only on Codex quota/rate-limit/non-zero exit.
|
|
160
|
+
|
|
161
|
+
### Context package
|
|
162
|
+
|
|
163
|
+
**Preconditions verified 2026-08-10:** `THEME-1` (`96992cf`) and `CHART-6` (`6dedc62`) are both
|
|
164
|
+
landed on `main` and published (`2.30.0`, `2.31.0`).
|
|
165
|
+
|
|
166
|
+
**Defect 1 — exact current state, verified in `src/theme/tokens.js:81-87`:**
|
|
167
|
+
```js
|
|
168
|
+
warning: {
|
|
169
|
+
...withMainShades('#C08A2C', '#212529'),
|
|
170
|
+
text: '#976100',
|
|
171
|
+
fill: '#C08A2C',
|
|
172
|
+
fillText: '#212529',
|
|
173
|
+
bg: '#FBF0DC',
|
|
174
|
+
},
|
|
175
|
+
```
|
|
176
|
+
`withMainShades(main, contrastText)` (defined near the top of `tokens.js`) sets `main`/`light`/`dark`/
|
|
177
|
+
`contrastText` via MUI's own `lighten`/`darken` at 0.2/0.3 tonal offsets. **Fix:** change the call to
|
|
178
|
+
`withMainShades('#976100', '#FFFFFF')` — reusing the existing `text` value as the new `main`, and
|
|
179
|
+
`'#FFFFFF'` as `contrastText` (verify this actually clears 4.5:1 — the WO states 5.216 on white
|
|
180
|
+
already for `#976100`, and `contrastText` white-on-`#976100` is the same ratio by symmetry). Leave
|
|
181
|
+
`text`/`fill`/`fillText`/`bg` untouched — `fill` stays the lighter amber for deliberate fill use
|
|
182
|
+
(THEME-1's own `MuiAlert` `standardWarning` styleOverride already reads `palette.warning.text`/`.bg`,
|
|
183
|
+
NOT `.main`, so that specimen is unaffected by this change — see the harness note below for why a
|
|
184
|
+
NEW specimen is needed to actually exercise `.main`).
|
|
185
|
+
|
|
186
|
+
**Defect 1's assertion rule — add to `src/theme/themeCompleteness.js`'s `contrastFindings(theme)`
|
|
187
|
+
function (~line 249).** Alongside the existing per-status `text`-vs-`bg` and `fillText`-vs-`fill`
|
|
188
|
+
loops, add a third: for each `status` in `STATUS_KEYS` (`['success','warning','error','info',
|
|
189
|
+
'stale']`, from `tokens.js`) that HAS a `.main` property (**`stale` does not** — it's a custom
|
|
190
|
+
augmented namespace, never passed through MUI's `createPalette`/`augmentColor`, so
|
|
191
|
+
`theme.palette.stale.main` is `undefined` — skip it, don't push a spurious finding for a channel
|
|
192
|
+
that was never supposed to have one), check `calculateContrastRatio(tokens.main, '#FFFFFF')` and
|
|
193
|
+
`calculateContrastRatio(tokens.main, theme.palette.background.default)`, both `>= 4.5`, pushing a
|
|
194
|
+
`contrast.<status>.main-on-<white|page>` finding (matching the existing naming convention,
|
|
195
|
+
`contrast.controlBorder.<state>-on-<surface>`) on failure. This is a REPORT via the existing
|
|
196
|
+
`findings` array — `assertThemeComplete` never throws or hard-fails on its own (confirm this by
|
|
197
|
+
reading the function; the "ratchet stays a report, not a hard fail for non-adopters" is structural
|
|
198
|
+
here, not a flag to add — a consuming app's OWN test suite decides whether to assert
|
|
199
|
+
`findings.length === 0`, ucm's export just returns data either way).
|
|
200
|
+
|
|
201
|
+
**Defect 2 — exact current state, verified in `src/components/charts/BarChart.jsx:26` and
|
|
202
|
+
`LineChart.jsx:43`:** `grid = { horizontal: true }` as a bare JS default parameter, then
|
|
203
|
+
`grid={grid}` passed straight through (`BarChart.jsx:65`, `LineChart.jsx:88`) — a caller-supplied
|
|
204
|
+
`grid` object REPLACES the default wholesale rather than merging per-key, unlike every sibling prop
|
|
205
|
+
in this file (compare `withAxisDefaults`'s `tickLabelStyle` merge, `withChartSlotDefaults`'s
|
|
206
|
+
`tooltip`/`legend` merge — both spread the default first, caller second, so the caller only
|
|
207
|
+
overrides the keys it actually sets). **Fix:** add a `withGridDefaults(grid)` helper to
|
|
208
|
+
`src/components/charts/chartDefaults.js` following the SAME pattern (`{ horizontal: true, ...grid }`
|
|
209
|
+
— MUI's `grid` prop type is `Pick<ChartsGridProps, 'vertical'|'horizontal'>`, plain optional
|
|
210
|
+
booleans, no special `false`/`true` shorthand at the type level, so spreading a caller's object
|
|
211
|
+
after the default is sufficient: a caller wanting no grid at all passes
|
|
212
|
+
`grid={{ horizontal: false, vertical: false }}` explicitly, which the spread correctly honours since
|
|
213
|
+
it's a later key overriding an earlier one — do not add special-casing for a literal `grid={false}`
|
|
214
|
+
unless you find MUI's actual runtime prop handling treats a boolean differently from the declared
|
|
215
|
+
type, which the WO's own phrasing ("or the documented way to switch the grid off entirely") already
|
|
216
|
+
anticipates might not be a literal `false`). Wire it into both `BarChart.jsx` and `LineChart.jsx`
|
|
217
|
+
the same way the other `chartDefaults.js` helpers are used.
|
|
218
|
+
|
|
219
|
+
**Defect 2's audit — read `src/components/charts/chartDefaults.js` in full and check each
|
|
220
|
+
object-valued prop the wrappers default or forward against the same replace-vs-merge question:**
|
|
221
|
+
- `withAxisDefaults`'s `tickLabelStyle: { fontSize: tickFontSize, ...axis.tickLabelStyle }` —
|
|
222
|
+
ALREADY merges correctly (default first, caller's own `tickLabelStyle` fields win per-key).
|
|
223
|
+
- `withChartSlotDefaults`'s `{ ...slotProps, tooltip: {...}, legend: {...} }` — the outer
|
|
224
|
+
`...slotProps` spread preserves any OTHER slot key a caller sets (e.g. `slotProps.axisHighlight`),
|
|
225
|
+
and the `tooltip`/`legend` sub-objects are themselves merged default-first. ALREADY correct.
|
|
226
|
+
- `LineChart.jsx`'s `slots={{ mark: FilledMarkElement, ...slots }}` — default first, caller's own
|
|
227
|
+
`slots` spread after, so a caller's own `slots.mark` wins and other slot keys survive. ALREADY
|
|
228
|
+
correct.
|
|
229
|
+
- `spaceForRotatedTicks`'s `margin` handling is NOT a "default object caller can partially override"
|
|
230
|
+
shape at all (it only computes `margin.bottom` when rotation is detected AND the caller hasn't set
|
|
231
|
+
one) — not the same bug class, nothing to fix there, but confirm this reading is right by re-reading
|
|
232
|
+
the function rather than trusting this summary.
|
|
233
|
+
**Verify each of these four independently rather than trusting this list — this map is a starting
|
|
234
|
+
point for the audit, not a substitute for it.** If the audit finds anything actually broken beyond
|
|
235
|
+
`grid`, fix it and say so explicitly in the PR/commit, per the WO's "fix that too and say so." If the
|
|
236
|
+
audit confirms all four are already correct, state that explicitly too — "audited and confirmed
|
|
237
|
+
correct" is a valid, expected outcome per the WO ("either... or a named list").
|
|
238
|
+
|
|
239
|
+
**Harness — why a new specimen row is required, not optional (verified 2026-08-10):** the current
|
|
240
|
+
`ThemeBaselineEntry` (`dev/entries.jsx`) has TWO status-colour specimens today, and NEITHER exercises
|
|
241
|
+
`palette.<status>.main`:
|
|
242
|
+
1. `StatusChip` (`dev/entries.jsx:71-78`) sets `sx={{ bgcolor: '${tone}.fill', color:
|
|
243
|
+
'${tone}.fillText' }}` directly — bypasses `.main` entirely by design.
|
|
244
|
+
2. `<Alert severity="warning">` etc. (`dev/entries.jsx:136-140`) — THEME-1's `MuiAlert`
|
|
245
|
+
`styleOverrides.standardWarning` (`src/theme/createAppTheme.js`'s `createPaletteAwareComponents`)
|
|
246
|
+
already overrides the STANDARD variant's `color`/`backgroundColor` to `palette.warning.text`/
|
|
247
|
+
`.bg` directly, NOT `.main` — so this existing Alert row was already immune to defect 1 and would
|
|
248
|
+
not have caught it even now.
|
|
249
|
+
Add: a row of `<Button color="success|warning|error|info" variant="contained">` (MUI's contained
|
|
250
|
+
Button reads `palette[color].main` for its background and `.contrastText` for its label — this is
|
|
251
|
+
the most direct `.main` exposure in the kit), a row of native `<Chip color="warning">` (not
|
|
252
|
+
`StatusChip` — MUI's own `color` prop on `Chip`, filled variant, also reads `.main`/
|
|
253
|
+
`.contrastText` directly), and an `<Alert severity="warning" variant="filled">` (MUI's `filled`
|
|
254
|
+
Alert variant is NOT covered by THEME-1's `standardWarning`-only override, so it still resolves
|
|
255
|
+
`.main` — confirm this by checking `createPaletteAwareComponents`'s `alertStyles` only sets
|
|
256
|
+
`standard${Status}` keys, never `filled${Status}` or `outlined${Status}`). These three together
|
|
257
|
+
are what the WO's Verification section means by "Button, Chip and Alert — the components where
|
|
258
|
+
`main` actually resolves."
|
|
259
|
+
|
|
260
|
+
**Chart specimen for the `grid` merge:** the existing "Caller overrides" `LineChart` specimen
|
|
261
|
+
(`dev/entries.jsx`, added in CHART-6) already sets `grid={{ horizontal: true, vertical: true }}` — a
|
|
262
|
+
COMPLETE object, which happens to already include `horizontal: true`, so it would not visibly
|
|
263
|
+
demonstrate the bug even pre-fix. Change it to a genuinely PARTIAL grid, e.g. `grid={{ vertical:
|
|
264
|
+
true }}` alone — pre-fix this would have shown ONLY vertical lines (losing the horizontal default);
|
|
265
|
+
post-fix it must show both. This is the specimen the WO's Verification section calls for ("A chart
|
|
266
|
+
specimen that passes a partial `grid`, to show the merge").
|
|
267
|
+
|
|
268
|
+
### Named files to change
|
|
269
|
+
|
|
270
|
+
- `src/theme/tokens.js` — the `warning` entry's `withMainShades(...)` call (line 82).
|
|
271
|
+
- `src/theme/themeCompleteness.js` — `contrastFindings` (~line 249), add the `main`-vs-white/page
|
|
272
|
+
loop, skipping any `STATUS_KEYS` entry without a `.main`.
|
|
273
|
+
- `src/components/charts/chartDefaults.js` — new `withGridDefaults` export.
|
|
274
|
+
- `src/components/charts/BarChart.jsx:26,65`, `src/components/charts/LineChart.jsx:43,88` — wire in
|
|
275
|
+
`withGridDefaults`.
|
|
276
|
+
- `dev/entries.jsx` — new Button/Chip/Alert `.main`-exercising specimen row; fix the existing
|
|
277
|
+
"Caller overrides" LineChart's `grid` prop to a genuinely partial object.
|
|
278
|
+
- `package.json` — version `2.31.0` → `2.31.1` (patch).
|
|
279
|
+
- `tests/themeCompleteness.test.js` — extend with the 2 required tests (main contrast + non-vacuity
|
|
280
|
+
proof by temporarily reverting `warning.main`; ratchet/report-not-hard-fail confirmation).
|
|
281
|
+
- `tests/chartDefaults.test.js` — extend with the 2 required tests (partial-grid merge + non-vacuity
|
|
282
|
+
proof by temporarily reverting to the bare default parameter; grid-off-via-explicit-false-object
|
|
283
|
+
still works).
|
|
284
|
+
|
|
285
|
+
### Do-not-touch / invariants
|
|
286
|
+
|
|
287
|
+
- `success`/`error`/`info`/`stale` palette values — untouched, they measure fine.
|
|
288
|
+
- `warning.fill`/`.text`/`.bg` — untouched.
|
|
289
|
+
- The committed reference-sheet HTML artifact (`work-orders/assets/THEME-1-baseline-reference-sheet.html`)
|
|
290
|
+
— frozen spec, never depicted `warning.main` as a foreground, not touched by this WO.
|
|
291
|
+
- Anything in CHART-6's scope beyond the `grid` merge and the audit — no new chart-chrome feature
|
|
292
|
+
work here.
|
|
293
|
+
- No behaviour, permission, or data-contract change.
|
|
294
|
+
|
|
295
|
+
### Pitfalls (verified against landed code 2026-08-10)
|
|
296
|
+
|
|
297
|
+
- `withMainShades` is defined once near the top of `tokens.js` and used for
|
|
298
|
+
`success`/`warning`/`error`/`info` — changing ONLY the `warning` call site, not the helper itself
|
|
299
|
+
(the helper's `lighten`/`darken` derivation logic is correct and unrelated to this bug).
|
|
300
|
+
- `STATUS_KEYS` includes `'stale'`, which has no MUI-augmented `.main` — a naive loop over all
|
|
301
|
+
`STATUS_KEYS` reading `tokens.main` will hit `undefined` for `stale`; guard it (`if (!tokens?.main)
|
|
302
|
+
continue`, matching the existing loop's `if (!tokens) continue` pattern one function up).
|
|
303
|
+
- Don't confuse this WO's `contrastFindings` addition with `THEME_COMPLETENESS_SURFACES`'s existing
|
|
304
|
+
`STATUS_SURFACES` (`text`/`fill`/`fillText`/`bg` presence-vs-default check) — the new rule is a
|
|
305
|
+
CONTRAST check (numeric ratio), same family as the existing `contrast.<status>.text-on-bg` /
|
|
306
|
+
`contrast.controlBorder.*` findings, not a "surface is deliberately defined" presence check.
|
|
307
|
+
|
|
308
|
+
### Target repo working directory (absolute)
|
|
309
|
+
|
|
310
|
+
`C:\Users\biglmi\Documents\webapps\ui-core-micha`
|
|
311
|
+
|
|
312
|
+
### Required tests to WRITE (Codex writes them; the Orchestrator runs them)
|
|
313
|
+
|
|
314
|
+
Exactly the 4 tests enumerated in Envelope § "Required tests to WRITE" above, extending
|
|
315
|
+
`tests/themeCompleteness.test.js` and `tests/chartDefaults.test.js` (no new files), plus
|
|
316
|
+
`tsc -p tsconfig.build.json --noEmit` clean. Do not add more, do not run the full suite. Affected-areas
|
|
317
|
+
set is exactly those two files.
|
|
318
|
+
|
|
319
|
+
### Preamble (append verbatim)
|
|
320
|
+
|
|
321
|
+
> The text above is the COMPLETE spec — the committed WO file's content, not a plan to refine; there
|
|
322
|
+
> is no separate plan file. Read the nearest `AGENTS.md`, the relevant `.codex/skills/<role>/SKILL.md`, and the
|
|
323
|
+
> app `MEMORY.md` ONLY for conventions. Stay in scope; do not touch auth/permissions/deps/schema/CI
|
|
324
|
+
> unless the spec says so; do not update `MEMORY.md`. Do NOT `git add`/`commit`/`push` — leave every
|
|
325
|
+
> change uncommitted in the working tree for the orchestrator's independent review. WRITE the tests
|
|
326
|
+
> the `Required tests` section calls for AND **RUN the tests you just wrote** to confirm they execute
|
|
327
|
+
> and pass — that is the ONLY test run you do (NOT the app's affected/full suite, NOT any review).
|
|
328
|
+
> The orchestrator re-runs the authoritative set + does the independent review after you finish —
|
|
329
|
+
> those are the gate; your own run does not count as the gate.
|
|
330
|
+
>
|
|
331
|
+
> Narrate continuously: a `PLAN: <step1> | <step2> | …` line up front, then a single-line
|
|
332
|
+
> `PROGRESS: [<n>/<total>] <present-tense action>` before every relevant action (and `… done` on
|
|
333
|
+
> completion), spaced so no gap exceeds ~2 min, stdout unbuffered, plus exactly one final
|
|
334
|
+
> `RESULT: DONE|BLOCKED <reason>`.
|
|
335
|
+
|
|
336
|
+
### Mini-handover
|
|
337
|
+
|
|
338
|
+
Repo: `ui-core-micha` (`C:\Users\biglmi\Documents\webapps\ui-core-micha`), branch `main`. WO:
|
|
339
|
+
`work-orders/THEME-2.md`. Follow `orchestrate-codex`.
|