@micha.bigler/ui-core-micha 3.14.3 → 4.0.0

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.
Files changed (367) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +7 -0
  3. package/dist/auth/UserMenu.js +1 -1
  4. package/dist/auth/apiClient.js +7 -6
  5. package/dist/chat/ChatList.js +1 -1
  6. package/dist/chat/ChatThread.js +2 -1
  7. package/dist/chat/ChatWorkspace.js +1 -1
  8. package/dist/chat/ModelPicker.js +2 -5
  9. package/dist/chat/kitSxRegistry.js +9 -0
  10. package/dist/chat/useChatSocket.js +1 -1
  11. package/dist/components/LoginForm.js +1 -1
  12. package/dist/components/SecurityComponent.js +1 -1
  13. package/dist/components/UserListComponent.js +2 -8
  14. package/dist/components/charts/ChartFrame.js +1 -1
  15. package/dist/components/charts/ScatterChart.js +2 -1
  16. package/dist/components/charts/kitSxRegistry.js +6 -0
  17. package/dist/entries/charts.js +6 -0
  18. package/dist/entries/chat.js +8 -0
  19. package/dist/entries/markdown.js +1 -0
  20. package/dist/index.js +0 -14
  21. package/dist/layout/SectionNav.js +1 -1
  22. package/dist/messaging/AttachmentList.js +2 -2
  23. package/dist/messaging/Composer.js +2 -1
  24. package/dist/messaging/ConversationLaunchers.js +1 -4
  25. package/dist/messaging/ConversationList.js +1 -1
  26. package/dist/messaging/DirectMessageLauncher.js +1 -1
  27. package/dist/messaging/MessagingProvider.js +0 -0
  28. package/dist/messaging/PollCard.js +7 -5
  29. package/dist/messaging/ReadTicks.js +2 -2
  30. package/dist/messaging/Thread.js +5 -3
  31. package/dist/notifications/NotificationBell.js +4 -7
  32. package/dist/notifications/NotificationSettings.js +1 -1
  33. package/dist/onboarding/OnboardingProvider.js +3 -6
  34. package/dist/pages/AccountPage.js +1 -2
  35. package/dist/pages/LoginPage.js +2 -3
  36. package/dist/pages/PasswordChangePage.js +2 -3
  37. package/dist/pages/PasswordInvitePage.js +2 -3
  38. package/dist/pages/PasswordResetRequestPage.js +2 -3
  39. package/dist/pages/SignUpPage.js +2 -3
  40. package/dist/pages/SignupConfirmPage.js +2 -3
  41. package/dist/theme/createAppTheme.js +5 -4
  42. package/dist/theme/kitSxEntry.js +11 -0
  43. package/dist/theme/kitSxRegistry.js +2 -15
  44. package/dist/theme/themeCompleteness.js +3 -12
  45. package/dist/utils/auth-errors.js +4 -3
  46. package/package.json +41 -16
  47. package/.github/workflows/publish.yml +0 -126
  48. package/DESIGN.md +0 -60
  49. package/WORK_ORDERS.md +0 -148
  50. package/dev/entries.jsx +0 -721
  51. package/dev/fixtures.js +0 -26
  52. package/dev/main.jsx +0 -75
  53. package/dev/mockTransport.jsx +0 -128
  54. package/docs/CHART-LAYOUT.md +0 -157
  55. package/docs/DARK-TOKENS.md +0 -140
  56. package/docs/TYPE-SCALE.md +0 -111
  57. package/docs/messaging-deviations.md +0 -118
  58. package/index.html +0 -12
  59. package/renovate.json +0 -10
  60. package/scripts/chart-api-census.mjs +0 -415
  61. package/src/auth/AuthContext.jsx +0 -158
  62. package/src/auth/ReauthModal.jsx +0 -82
  63. package/src/auth/UserMenu.jsx +0 -121
  64. package/src/auth/apiClient.jsx +0 -232
  65. package/src/auth/authApi.jsx +0 -539
  66. package/src/auth/authConfig.jsx +0 -34
  67. package/src/auth/reauth.js +0 -47
  68. package/src/chat/ChatComposer.jsx +0 -36
  69. package/src/chat/ChatList.jsx +0 -87
  70. package/src/chat/ChatThread.jsx +0 -128
  71. package/src/chat/ChatWorkspace.jsx +0 -244
  72. package/src/chat/MarkdownReply.jsx +0 -22
  73. package/src/chat/ModelPicker.jsx +0 -85
  74. package/src/chat/api.js +0 -18
  75. package/src/chat/useChatSocket.js +0 -32
  76. package/src/chat/wire.js +0 -7
  77. package/src/components/AccessCodeManager.jsx +0 -288
  78. package/src/components/AccessCodeSingleUseToggle.jsx +0 -92
  79. package/src/components/AllowedEmailDomainsManager.jsx +0 -92
  80. package/src/components/AuthFactorRequirementCard.jsx +0 -95
  81. package/src/components/BulkInviteCsvTab.jsx +0 -198
  82. package/src/components/EmptyState.jsx +0 -38
  83. package/src/components/LoginForm.jsx +0 -159
  84. package/src/components/MFAComponent.jsx +0 -350
  85. package/src/components/MfaLoginComponent.jsx +0 -252
  86. package/src/components/MobileBottomNav.jsx +0 -82
  87. package/src/components/PasskeysComponent.jsx +0 -252
  88. package/src/components/PasswordChangeForm.jsx +0 -87
  89. package/src/components/PasswordResetRequestForm.jsx +0 -43
  90. package/src/components/PasswordSetForm.jsx +0 -97
  91. package/src/components/ProfileComponent.jsx +0 -348
  92. package/src/components/QrSignupManager.jsx +0 -404
  93. package/src/components/QrSignupValidityManager.jsx +0 -106
  94. package/src/components/RegistrationMethodsManager.jsx +0 -150
  95. package/src/components/SecurityComponent.jsx +0 -141
  96. package/src/components/SocialLoginButtons.jsx +0 -83
  97. package/src/components/SoftChip.jsx +0 -93
  98. package/src/components/StatTile.jsx +0 -39
  99. package/src/components/SupportRecoveryRequestsTab.jsx +0 -482
  100. package/src/components/TurnstileWidget.jsx +0 -99
  101. package/src/components/UserInviteComponent.jsx +0 -76
  102. package/src/components/UserListComponent.jsx +0 -618
  103. package/src/components/charts/BarChart.jsx +0 -102
  104. package/src/components/charts/ChartFrame.jsx +0 -214
  105. package/src/components/charts/LineChart.jsx +0 -126
  106. package/src/components/charts/ScatterChart.jsx +0 -299
  107. package/src/components/charts/TimeSeriesChart.jsx +0 -300
  108. package/src/components/charts/chartDefaults.js +0 -644
  109. package/src/components/charts/chartLabels.js +0 -36
  110. package/src/components/charts/exportChart.js +0 -258
  111. package/src/components/charts/formatters.js +0 -39
  112. package/src/components/charts/palette.js +0 -33
  113. package/src/components/charts/yearTickInterval.js +0 -7
  114. package/src/i18n/authTranslations.ts +0 -2651
  115. package/src/i18n/chartsTranslations.ts +0 -91
  116. package/src/i18n/chatTranslations.ts +0 -55
  117. package/src/i18n/messagingTranslations.ts +0 -120
  118. package/src/i18n/notificationsTranslations.ts +0 -32
  119. package/src/i18n/onboardingTranslations.ts +0 -29
  120. package/src/i18n/sectionNavTranslations.ts +0 -20
  121. package/src/i18n/uiCoreTranslations.js +0 -29
  122. package/src/i18n/userMenuTranslations.ts +0 -5
  123. package/src/index.js +0 -158
  124. package/src/layout/PageLayout.jsx +0 -36
  125. package/src/layout/SectionNav.jsx +0 -320
  126. package/src/messaging/AttachmentList.jsx +0 -145
  127. package/src/messaging/Composer.jsx +0 -197
  128. package/src/messaging/ConversationLaunchers.jsx +0 -51
  129. package/src/messaging/ConversationList.jsx +0 -109
  130. package/src/messaging/DirectMessageLauncher.jsx +0 -112
  131. package/src/messaging/MessageBubble.jsx +0 -183
  132. package/src/messaging/MessagingProvider.jsx +0 -0
  133. package/src/messaging/MessagingScopeConfig.jsx +0 -24
  134. package/src/messaging/PollCard.jsx +0 -163
  135. package/src/messaging/ReactionBar.jsx +0 -43
  136. package/src/messaging/ReadTicks.jsx +0 -82
  137. package/src/messaging/Thread.jsx +0 -195
  138. package/src/messaging/api.js +0 -48
  139. package/src/messaging/composerImageCompression.js +0 -35
  140. package/src/messaging/linkifyText.jsx +0 -37
  141. package/src/notifications/NotificationBell.jsx +0 -84
  142. package/src/notifications/NotificationSettings.jsx +0 -330
  143. package/src/notifications/NotificationsProvider.jsx +0 -224
  144. package/src/notifications/PopupSurface.jsx +0 -105
  145. package/src/notifications/api.js +0 -55
  146. package/src/notifications/feedApi.js +0 -18
  147. package/src/notifications/realtime.jsx +0 -138
  148. package/src/notifications/serviceWorker/sw.js +0 -50
  149. package/src/onboarding/OnboardingProvider.jsx +0 -326
  150. package/src/onboarding/OnboardingWizard.jsx +0 -61
  151. package/src/onboarding/WizardDialogShell.jsx +0 -51
  152. package/src/onboarding/api.js +0 -13
  153. package/src/onboarding/stepSelection.js +0 -16
  154. package/src/onboarding/steps/BrowserPushStep.jsx +0 -121
  155. package/src/onboarding/steps/CompleteNameStep.jsx +0 -46
  156. package/src/onboarding/steps/CookieConsentStep.jsx +0 -133
  157. package/src/onboarding/steps/PwaInstallStep.jsx +0 -47
  158. package/src/pages/AccountPage.jsx +0 -394
  159. package/src/pages/LoginPage.jsx +0 -343
  160. package/src/pages/PasswordChangePage.jsx +0 -62
  161. package/src/pages/PasswordInvitePage.jsx +0 -177
  162. package/src/pages/PasswordResetRequestPage.jsx +0 -68
  163. package/src/pages/SignUpPage.jsx +0 -268
  164. package/src/pages/SignupConfirmPage.jsx +0 -155
  165. package/src/testing/checkKitIntegration.js +0 -233
  166. package/src/theme/createAppTheme.js +0 -423
  167. package/src/theme/fonts.js +0 -3
  168. package/src/theme/index.js +0 -21
  169. package/src/theme/kitSxRegistry.js +0 -285
  170. package/src/theme/themeCompleteness.js +0 -1045
  171. package/src/theme/tokens.js +0 -478
  172. package/src/utils/auth-errors.js +0 -76
  173. package/src/utils/authService.js +0 -223
  174. package/src/utils/resolveErrorText.js +0 -28
  175. package/src/utils/webauthn.js +0 -51
  176. package/tests/AccountPage.profileStatements.test.jsx +0 -162
  177. package/tests/AccountPage.test.jsx +0 -200
  178. package/tests/AuthContext.test.jsx +0 -129
  179. package/tests/BarChart.test.jsx +0 -112
  180. package/tests/BrowserPushStep.test.jsx +0 -110
  181. package/tests/ChartFrame.test.jsx +0 -336
  182. package/tests/ConversationList.test.jsx +0 -144
  183. package/tests/CookieConsentStep.test.jsx +0 -69
  184. package/tests/EmptyState.test.jsx +0 -62
  185. package/tests/LineChart.test.jsx +0 -80
  186. package/tests/MessagingProvider.test.jsx +0 -50
  187. package/tests/MobileBottomNav.test.jsx +0 -319
  188. package/tests/NotificationBell.test.jsx +0 -60
  189. package/tests/NotificationSettings.test.jsx +0 -276
  190. package/tests/NotificationsProvider.test.jsx +0 -240
  191. package/tests/OnboardingProvider.test.jsx +0 -294
  192. package/tests/OnboardingWizard.test.jsx +0 -143
  193. package/tests/PasswordChangeForm.test.jsx +0 -70
  194. package/tests/PasswordInvitePage.test.jsx +0 -142
  195. package/tests/PasswordSetForm.test.jsx +0 -70
  196. package/tests/PopupSurface.test.jsx +0 -142
  197. package/tests/ProfileComponent.refresh.test.jsx +0 -194
  198. package/tests/QrSignupManager.registrationContext.test.jsx +0 -106
  199. package/tests/QrSignupManagerInfoBox.test.jsx +0 -49
  200. package/tests/ScatterChart.test.jsx +0 -270
  201. package/tests/SectionNav.test.jsx +0 -363
  202. package/tests/SignUpPage.test.jsx +0 -208
  203. package/tests/SoftChip.test.jsx +0 -105
  204. package/tests/StatTile.test.jsx +0 -57
  205. package/tests/Thread.test.jsx +0 -151
  206. package/tests/TimeSeriesChart.test.jsx +0 -367
  207. package/tests/UserListComponent.test.jsx +0 -192
  208. package/tests/UserMenu.test.jsx +0 -171
  209. package/tests/apiClientLanguage.test.js +0 -33
  210. package/tests/apiClientPublicPaths.test.js +0 -178
  211. package/tests/authApiLogin.test.js +0 -42
  212. package/tests/authApiRegistration.test.js +0 -31
  213. package/tests/authErrorCodeRendering.test.jsx +0 -77
  214. package/tests/authErrors.test.js +0 -74
  215. package/tests/authTranslations.test.js +0 -74
  216. package/tests/chart-api-census.test.js +0 -366
  217. package/tests/chartAxisTickBand.test.jsx +0 -95
  218. package/tests/chartDefaults.test.js +0 -902
  219. package/tests/chartLabels.test.js +0 -50
  220. package/tests/chartsPalette.test.js +0 -99
  221. package/tests/chatApi.test.js +0 -48
  222. package/tests/chatDriverNames.test.jsx +0 -71
  223. package/tests/chatExports.test.js +0 -3
  224. package/tests/chatList.test.jsx +0 -84
  225. package/tests/chatPicker.test.jsx +0 -82
  226. package/tests/chatSocket.test.jsx +0 -26
  227. package/tests/chatThread.test.jsx +0 -116
  228. package/tests/chatTranslations.test.js +0 -47
  229. package/tests/chatWorkspace.test.jsx +0 -234
  230. package/tests/checkKitIntegration.test.jsx +0 -219
  231. package/tests/createAppTheme.test.js +0 -132
  232. package/tests/createAppThemeDark.test.js +0 -127
  233. package/tests/createAppThemeLightGuard.test.js +0 -40
  234. package/tests/createAppThemePageContrast.test.js +0 -108
  235. package/tests/createAppThemeTypography.test.js +0 -53
  236. package/tests/errorCallSiteGuard.test.js +0 -32
  237. package/tests/exportChart.test.js +0 -313
  238. package/tests/feedApi.test.js +0 -46
  239. package/tests/fixtures/light-theme-baseline.json +0 -2234
  240. package/tests/i18nAggregate.test.js +0 -120
  241. package/tests/i18nGermanVariant.test.js +0 -65
  242. package/tests/loginPageErrorResolution.test.jsx +0 -102
  243. package/tests/messagingApi.test.js +0 -32
  244. package/tests/messagingChunk6.test.jsx +0 -116
  245. package/tests/messagingCompactBubble.test.jsx +0 -64
  246. package/tests/messagingComposer.test.jsx +0 -136
  247. package/tests/messagingComposerChunk5.test.jsx +0 -113
  248. package/tests/messagingContractConformance.test.js +0 -69
  249. package/tests/messagingDirectMessageLauncher.test.jsx +0 -151
  250. package/tests/messagingExports.test.js +0 -21
  251. package/tests/messagingInteractions.test.jsx +0 -136
  252. package/tests/messagingLastMessagePreview.test.jsx +0 -93
  253. package/tests/messagingLinkify.test.jsx +0 -51
  254. package/tests/messagingMessageActions.test.jsx +0 -163
  255. package/tests/messagingMsg6.test.jsx +0 -105
  256. package/tests/messagingMsg6f.test.jsx +0 -155
  257. package/tests/messagingMsg6g.test.jsx +0 -166
  258. package/tests/messagingMsg6h.test.jsx +0 -136
  259. package/tests/messagingMsg6i.test.jsx +0 -129
  260. package/tests/messagingPollRendering.test.jsx +0 -142
  261. package/tests/messagingReactionMerge.test.jsx +0 -77
  262. package/tests/messagingReadTicksTooltip.test.jsx +0 -36
  263. package/tests/messagingThreadReceipts.test.jsx +0 -178
  264. package/tests/messagingThreadingQuoting.test.jsx +0 -87
  265. package/tests/messagingUnreadLifecycle.test.jsx +0 -78
  266. package/tests/notificationsApi.test.js +0 -41
  267. package/tests/notificationsExports.test.js +0 -34
  268. package/tests/onboardingDescriptors.test.js +0 -132
  269. package/tests/packageTreeShaking.test.js +0 -126
  270. package/tests/realtime.test.jsx +0 -219
  271. package/tests/resolveErrorText.test.js +0 -72
  272. package/tests/stepSelection.test.js +0 -53
  273. package/tests/themeCompleteness.test.js +0 -626
  274. package/tests/timeSeriesLegend.test.js +0 -99
  275. package/tests/userScreenTranslations.test.jsx +0 -218
  276. package/tsconfig.build.json +0 -18
  277. package/vite.config.mjs +0 -6
  278. package/work-orders/AUTH-1.md +0 -74
  279. package/work-orders/AUTH-2.md +0 -74
  280. package/work-orders/AUTH-4.md +0 -183
  281. package/work-orders/AUTH-5.md +0 -154
  282. package/work-orders/AUTH-7.md +0 -181
  283. package/work-orders/AUTH-8.md +0 -184
  284. package/work-orders/CHART-1.md +0 -285
  285. package/work-orders/CHART-2.md +0 -222
  286. package/work-orders/CHART-3.md +0 -163
  287. package/work-orders/CHART-4.md +0 -203
  288. package/work-orders/CHART-5.md +0 -226
  289. package/work-orders/CHART-6.md +0 -428
  290. package/work-orders/CHART-7.md +0 -175
  291. package/work-orders/DX-1.md +0 -169
  292. package/work-orders/DX-2.md +0 -188
  293. package/work-orders/DX-3.md +0 -195
  294. package/work-orders/I18N-1.md +0 -254
  295. package/work-orders/I18N-3.md +0 -207
  296. package/work-orders/MSG-3.md +0 -375
  297. package/work-orders/MSG-3b.md +0 -1002
  298. package/work-orders/MSG-3c.md +0 -378
  299. package/work-orders/MSG-3d.md +0 -268
  300. package/work-orders/MSG-3e.md +0 -164
  301. package/work-orders/MSG-3f.md +0 -391
  302. package/work-orders/MSG-6e.md +0 -308
  303. package/work-orders/MSG-6f.md +0 -214
  304. package/work-orders/MSG-6g.md +0 -244
  305. package/work-orders/MSG-6h.md +0 -238
  306. package/work-orders/MSG-6i.md +0 -271
  307. package/work-orders/MSG-6j.md +0 -117
  308. package/work-orders/NOTIF-12.md +0 -214
  309. package/work-orders/NOTIF-13.md +0 -142
  310. package/work-orders/NOTIF-14.md +0 -151
  311. package/work-orders/PRIM-1.md +0 -177
  312. package/work-orders/SHELL-1.md +0 -255
  313. package/work-orders/SHELL-2.md +0 -197
  314. package/work-orders/SHELL-3.md +0 -359
  315. package/work-orders/SHELL-4.md +0 -351
  316. package/work-orders/SHELL-5.md +0 -345
  317. package/work-orders/SHELL-6.md +0 -210
  318. package/work-orders/THEME-1.md +0 -587
  319. package/work-orders/THEME-10.md +0 -303
  320. package/work-orders/THEME-11.md +0 -208
  321. package/work-orders/THEME-2.md +0 -339
  322. package/work-orders/THEME-3.md +0 -210
  323. package/work-orders/THEME-4.md +0 -271
  324. package/work-orders/THEME-5.md +0 -341
  325. package/work-orders/THEME-6.md +0 -247
  326. package/work-orders/THEME-7.md +0 -82
  327. package/work-orders/THEME-8.md +0 -211
  328. package/work-orders/THEME-9.md +0 -194
  329. package/work-orders/UCM-AUTH-10.md +0 -490
  330. package/work-orders/UCM-AUTH-11.md +0 -185
  331. package/work-orders/UCM-AUTH-12.md +0 -98
  332. package/work-orders/UCM-AUTH-13.md +0 -47
  333. package/work-orders/UCM-AUTH-9.md +0 -207
  334. package/work-orders/UCM-CHART-10.md +0 -150
  335. package/work-orders/UCM-CHART-11.md +0 -132
  336. package/work-orders/UCM-CHART-12.md +0 -348
  337. package/work-orders/UCM-CHART-13.md +0 -122
  338. package/work-orders/UCM-CHART-14.md +0 -198
  339. package/work-orders/UCM-CHART-15.md +0 -187
  340. package/work-orders/UCM-CHART-16.md +0 -169
  341. package/work-orders/UCM-CHART-17.md +0 -195
  342. package/work-orders/UCM-CHART-18.md +0 -200
  343. package/work-orders/UCM-CHART-8.md +0 -147
  344. package/work-orders/UCM-CHART-9.md +0 -265
  345. package/work-orders/UCM-CHAT-1.md +0 -190
  346. package/work-orders/UCM-CHAT-2.md +0 -75
  347. package/work-orders/UCM-DEP-1.md +0 -63
  348. package/work-orders/UCM-I18N-4.md +0 -226
  349. package/work-orders/UCM-I18N-5.md +0 -211
  350. package/work-orders/UCM-MSG-20.md +0 -192
  351. package/work-orders/UCM-PRIM-2.md +0 -114
  352. package/work-orders/UCM-SHELL-7.md +0 -134
  353. package/work-orders/UCM-SHELL-8.md +0 -125
  354. package/work-orders/UCM-TEST-1.md +0 -304
  355. package/work-orders/UCM-THEME-13.md +0 -69
  356. package/work-orders/UCM-THEME-14.md +0 -312
  357. package/work-orders/UCM-THEME-15.md +0 -356
  358. package/work-orders/UCM-THEME-16.md +0 -80
  359. package/work-orders/UCM-THEME-17.md +0 -111
  360. package/work-orders/UCM-THEME-18.md +0 -184
  361. package/work-orders/assets/AUTH-4-user-list-card.html +0 -407
  362. package/work-orders/assets/PRIM-1-dashboard-primitives.html +0 -624
  363. package/work-orders/assets/SHELL-2-account-navigation.html +0 -1159
  364. package/work-orders/assets/THEME-1-baseline-reference-sheet.html +0 -1352
  365. package/work-orders/assets/UCM-CHAT-1-ai-chat.html +0 -447
  366. package/work-orders/assets/UCM-THEME-13-dark-prototype.html +0 -390
  367. package/work-orders/assets/UCM-THEME-17-type-scale.html +0 -391
@@ -1,271 +0,0 @@
1
- # THEME-4 — Make it impossible for a kit component to silently defeat the baseline
2
-
3
- **Target repo:** `ui-core-micha` (branch `main` — this repo has no `develop`)
4
- **Tier:** 3 (shared core)
5
- **Review:** independent `reviewer` — mandatory (new logic). **`ui_reviewer` becomes mandatory too if
6
- the check surfaces findings that require touching a component's rendering**, which is likely; see
7
- "What test 2 will probably do".
8
- **Version target:** the next **minor** after `THEME-3` lands — a new exported check is additive API.
9
- Read the published version at implementation time; do **not** hardcode a number from this file.
10
- **Strand:** `DS-18`, first half
11
- **Sequencing:** **after `THEME-3`.** See Risks — that work order is in flight in these exact files.
12
-
13
- ---
14
-
15
- ## A. Envelope
16
-
17
- ### Goal
18
-
19
- A kit component can put a property in its own `sx` that the baseline already sets as a
20
- `styleOverrides` default. Inline `sx` wins, so the baseline default becomes inert — the theme is
21
- complete, green, and has no effect.
22
-
23
- This is not hypothetical. It happened in `SHELL-3`: `MobileBottomNav` duplicated `borderTop` and
24
- `borderColor` inline, killing the two defaults the same work order had just registered.
25
- `SHELL-4` fixed it by hand and added a test asserting key-disjointness for that one component
26
- (`tests/MobileBottomNav.test.jsx:215`). **Make that mechanical for the whole kit.**
27
-
28
- ### Why the whole kit, measured
29
-
30
- - **51 `.jsx` files under `src/` carry an `sx=` prop.**
31
- - **The baseline styles 23 MUI component keys** — `MuiAlert`, `MuiBottomNavigation`,
32
- `MuiBottomNavigationAction`, `MuiButton`, `MuiCard`, `MuiCheckbox`, `MuiChip`, `MuiContainer`,
33
- `MuiCssBaseline`, `MuiDialog`, `MuiDivider`, `MuiDrawer`, `MuiFilledInput`, `MuiFormControlLabel`,
34
- `MuiIconButton`, `MuiInput`, `MuiMenu`, `MuiOutlinedInput`, `MuiPaper`, `MuiSelect`,
35
- `MuiTableCell`, `MuiTextField`, `MuiTooltip`.
36
- - `SHELL-4`'s test covers **one** component pair. The other 50 files are unchecked.
37
-
38
- `MobileBottomNav` was not special. `ChartFrame`, `UserMenu`, `LoginForm`, `PageLayout` and the input
39
- managers all render MUI components the baseline styles **and** carry their own `sx`.
40
-
41
- ### Why the assertion cannot see this
42
-
43
- `assertThemeComplete` proves the theme **has** a value; nothing proves any component **uses** it.
44
- And a hex-value grep does not catch it either, because the duplicated value is usually *correct* — it
45
- is in the wrong layer, not the wrong colour. Reviewing for "no hardcoded colours" passes it. The one
46
- thing that caught it was a human reading a diff.
47
-
48
- ### Scope
49
-
50
- **1. A convention, already demonstrated.** A kit component that carries its own `sx` for a MUI
51
- component the baseline styles **exports that `sx` object**. `MobileBottomNav` already does
52
- (`MOBILE_BOTTOM_NAV_ROOT_SX`, `MOBILE_BOTTOM_NAV_ACTION_SX`) — follow that shape rather than
53
- inventing a second one. A small registry maps each exported object to the MUI key it targets.
54
-
55
- **2. An exported check.** Same finding contract as the existing assertion —
56
- `{ findings: [{ surface, reason }] }` — so consumers and tests handle one shape, not two. For each
57
- registry entry, assert the key sets of the component's `sx` and the baseline's `styleOverrides` for
58
- that MUI key are **disjoint**. A collision names the component, the MUI key and the property.
59
-
60
- **3. A bypass check, so the convention cannot be skipped in silence.** A source-level scan that flags
61
- a kit component file containing an inline `sx={{ … }}` object literal which is not exported.
62
- **Precedent in this repo:** `reportThemeAdoption(sources)` already takes source strings and regexes
63
- them for `createTheme(` versus `createAppTheme(` — same module, same shape, so this is an established
64
- pattern here rather than a new mechanism.
65
-
66
- **4. Wire it as a hard failure in ucm's own suite.**
67
-
68
- **This check cannot turn any consuming app red.** It is entirely internal: ucm's components against
69
- ucm's baseline, run in ucm's tests. An earlier concern that a new invariant might break cockpit's
70
- fresh adoption was raised and, on designing it, does not apply — an app's *own* components shadowing
71
- the baseline is the broader case and is a named follow-up below.
72
-
73
- ### What test 2 will probably do, and what to do about it
74
-
75
- **Expect findings.** 51 files have never been checked against 23 styled component keys. A clean first
76
- run would be a pleasant surprise, not the base case.
77
-
78
- - **Each finding is resolved by `SHELL-4`'s rule: one home per property.** The component owns what
79
- keeps it functional on any theme; the theme owns what makes it look like this estate. A property in
80
- both layers is the defect.
81
- - **Do not exempt your way to green.** The exemption arm exists for a component that genuinely must
82
- override the baseline for its own purpose, with a stated reason — the same contract
83
- `assertThemeComplete` uses, where an exemption without a reason is itself a finding. A mass
84
- exemption converts this work order into a no-op.
85
- - **If the finding count is large enough that fixing them all exceeds this work order, stop and
86
- report** with the list. Splitting into "land the check plus the fixes it can absorb" and "the
87
- remainder as a follow-up" is a scope decision for the operator, not something to absorb silently.
88
-
89
- ### Non-goals / do not touch
90
-
91
- - **`DS-18`'s second half — "which components *can violate* a rule".** That is the shadow-array idea:
92
- nine MUI components read `shadows[…]`, three are declared, six would become findings. It is
93
- deliberately **out of scope** because it rests on a `grep 'shadows\['` **lower bound** and its
94
- findings demand *new* theme entries — pressure toward the gold-plating the estate's YAGNI guardrail
95
- rejects. Follow-up, with the heuristic labelled as a lower bound wherever it appears.
96
- - **App-side scanning.** An app's own components can shadow the baseline too (a `Header` putting
97
- `borderColor` in `sx` over a `MuiAppBar` default). Real, and a follow-up — `reportThemeAdoption`
98
- already shows the shape for it.
99
- - **No rendering-based check.** Asserting that each of 23 components tracks a changed theme needs a
100
- fixture per component: expensive, fragile, and not what this WO buys. `SHELL-4`'s cross-theme
101
- render test stays the pattern for individual components.
102
- - **No baseline token or component-default change**, unless a finding forces one — and then it is a
103
- fix, listed, not a redesign.
104
- - No change to `assertThemeComplete`'s own surface registry, `createAppTheme`'s signature, or any
105
- component's public props.
106
-
107
- ### Risks
108
-
109
- - **`THEME-3` is in flight in this repo right now.** Verified: `src/theme/tokens.js`,
110
- `src/theme/themeCompleteness.js`, `tests/createAppTheme.test.js` and
111
- `tests/themeCompleteness.test.js` are all modified in the working tree with Codex running. **Those
112
- are exactly this work order's files.** Do not start concurrently: let `THEME-3` land and publish,
113
- then `git pull` and work from that state. Check `git status` and `git log origin/main..HEAD` first.
114
- - **The convention is only as strong as its adoption**, which is what item 3 exists to guarantee. If
115
- item 3 is dropped, the check degrades to "whatever someone remembered to export".
116
- - **Known bound, state it in the code rather than discovering it later:** the check sees only `sx`
117
- objects a component exports, at their top level. A **conditional or nested** `sx` is not covered —
118
- `MobileBottomNav`'s own `emphasis` circle is exactly such a case. This is a lower bound on
119
- shadowing, not coverage, and must be documented as such so nobody reads green as proof.
120
- - **No staging net.** A version bump on `main` publishes to npm; the independent review is the only
121
- gate and cannot be back-filled.
122
-
123
- ### Required tests to WRITE
124
-
125
- 1. **Non-vacuity, reconstructing the real incident.** A fixture component whose exported `sx`
126
- duplicates a baseline `styleOverrides` key produces a finding naming the component, the MUI key
127
- and the property. This is `SHELL-3`'s arrangement; the test must fail if the check is inert.
128
- 2. **The current kit.** Run the check across the whole registry and assert the result is empty —
129
- after fixing whatever it legitimately finds (see above).
130
- 3. **The bypass check** flags an inline non-exported `sx={{ … }}` in a fixture source string and does
131
- **not** flag an exported one.
132
- 4. **The exemption contract matches the existing one:** an exemption with a reason suppresses exactly
133
- one finding; an exemption without a reason is itself a finding.
134
- 5. `SHELL-4`'s existing `MobileBottomNav` disjointness test still passes, and is **not** replaced by
135
- the generic check — the specific test documents that component's split, the generic one guards the
136
- kit. Keeping both is deliberate.
137
-
138
- Plus `tsc -p tsconfig.build.json --noEmit` clean. **No full-suite run** — the affected set is the
139
- theme module's specs plus any component spec a fix touches.
140
-
141
- ### Verification
142
-
143
- Static work with no visual surface of its own, so the standing rendered gate does not apply **unless
144
- a finding forces a component change** — then the two-width side-by-side applies to that component,
145
- and `ui_reviewer` becomes mandatory alongside it. Say in the register note which of the two happened.
146
-
147
- The check's own value is proven by test 1, not by a screenshot: a check that cannot fail is worth
148
- nothing, and that is the assertion this work order actually has to make about itself.
149
-
150
- ### Parity guardrail
151
-
152
- No intended change to any rendered output. If the kit renders differently after this work order, it
153
- is because a real shadowing defect was fixed — and every such change must be listed in the register
154
- note, not folded in as tidying.
155
-
156
- ---
157
-
158
- ## B. Implementation map
159
-
160
- *Filled by the Orchestrator on `git pull` — see `AGENTS.md` → "Work Order".*
161
-
162
- ### Execution directive (read this first)
163
-
164
- > **If you are the implementer reading this work order as your own specification: this section is
165
- > NOT addressed to you.** It tells the Orchestrator how to invoke you. **You ARE that invocation —
166
- > do NOT shell out to `codex exec`.**
167
- >
168
- > Implement through `codex exec` in the background — invoked directly via Bash (never the
169
- > `debugger`/`*_coder` Agent wrappers) with BOTH flags `--skip-git-repo-check` and
170
- > `--dangerously-bypass-approvals-and-sandbox`. **Pass the WO via stdin, not as a positional
171
- > argument** (a positional arg hits Windows' command-line length limit — proven repeatedly in this
172
- > repo). Fallback to direct Claude implementation only on Codex quota/rate-limit/non-zero exit — and
173
- > note that the fallback flips authorship, so the independent `reviewer` stays mandatory either way.
174
- >
175
- > **Two things this repo has learned the hard way, both on the two immediately preceding work
176
- > orders:** Codex committed its own change and wrote a self-reported review into
177
- > `WORK_ORDERS.md` on `SHELL-3` **and** on `SHELL-4`. Read `git log origin/main..HEAD` and
178
- > `git status` before your own review; an implementer commit is a blocker to surface, and a register
179
- > row naming a review the Orchestrator did not itself start is invalid.
180
-
181
- ### Context package
182
-
183
- **Precondition confirmed:** `THEME-3` is landed and published (`1b25117`, register row `done`).
184
- `git log --oneline -3` at hand-off time shows the Orchestrator's own docs commits on top of it, no
185
- implementer commit — clean to start from.
186
-
187
- **The established `sx`-export convention (scope item 1's shape to follow), already shipped in
188
- `src/components/MobileBottomNav.jsx`:**
189
- ```js
190
- export const MOBILE_BOTTOM_NAV_ROOT_SX = {
191
- position: 'fixed', left: 0, right: 0, bottom: 0,
192
- borderTop: '1px solid', borderColor: 'divider',
193
- paddingBottom: 'env(safe-area-inset-bottom)',
194
- };
195
- export const MOBILE_BOTTOM_NAV_ACTION_SX = { minWidth: 0, maxWidth: 'none' };
196
- ```
197
- Both are plain top-level `export const` object literals, used directly as (or spread into) the
198
- `sx` prop on the MUI element they style. This is the shape the registry (item 1) should match
199
- against — a component "carries its own `sx` for a MUI component the baseline styles" means: look for
200
- `<BottomNavigation`, `<Button`, `<Card`, etc. (the 23 baseline-styled MUI component names) receiving
201
- an `sx=` prop inside `src/**/*.jsx`, then check whether that `sx` is a top-level exported identifier
202
- (covered) or an inline/conditional literal (item 3's bypass check should flag the latter if it isn't
203
- exported).
204
-
205
- **The exemption contract to mirror exactly (scope item 2 + required test 4), from
206
- `src/theme/themeCompleteness.js:333-350` (`assertThemeComplete`):**
207
- ```js
208
- export function assertThemeComplete(theme, { exemptions = [] } = {}) {
209
- const declaredExemptions = [...(theme?.themeCompleteness?.exemptions || []), ...exemptions];
210
- const validExemptions = new Set();
211
- const findings = [];
212
- for (const exemption of declaredExemptions) {
213
- if (!exemption?.surface || !exemption?.reason?.trim()) {
214
- findings.push({ surface: `exemption.${exemption?.surface || 'unknown'}`,
215
- reason: 'A completeness exemption must name a surface and include a reason.' });
216
- continue;
217
- }
218
- validExemptions.add(exemption.surface);
219
- }
220
- ...
221
- }
222
- ```
223
- The new check's `{ findings: [{ surface, reason }] }` return shape and exemption handling should be
224
- structurally identical to this, not a reinvention — same two failure modes (missing reason is itself
225
- a finding; a valid exemption suppresses exactly one finding).
226
-
227
- **The bypass-check precedent (scope item 3), from `src/theme/themeCompleteness.js:370-379`
228
- (`reportThemeAdoption`):**
229
- ```js
230
- export function reportThemeAdoption(sources = []) {
231
- const normalized = sources.map((entry, index) => typeof entry === 'string'
232
- ? { path: `source-${index + 1}`, source: entry }
233
- : { path: entry.path || `source-${index + 1}`, source: entry.source || '' });
234
- const themeBypassPaths = normalized
235
- .filter(({ source }) => /\bcreateTheme\s*\(/.test(source) && !/\bcreateAppTheme\s*\(/.test(source))
236
- .map(({ path }) => path);
237
- ...
238
- }
239
- ```
240
- Same module, same input shape (an array of `{ path, source }` or raw source strings), same
241
- regex-over-source-text technique — the new bypass check takes the same input shape and regexes for
242
- an inline `sx={{ ... }}` object literal that is not a reference to a top-level exported identifier.
243
-
244
- **Where to put the new code:** co-locate in `src/theme/themeCompleteness.js` alongside
245
- `reportThemeAdoption` (the WO's own "same module" language for item 3), or a new sibling file if
246
- the additions make that file unwieldy — Codex's call, but export everything new from
247
- `src/theme/index.js` and `src/index.js` (follow the existing export list pattern in both) so the
248
- check is part of the public API per the WO's "additive API is a minor" versioning note.
249
-
250
- **Discovery is the actual task, not pre-solved here:** the WO's own measurement (51 `.jsx` files
251
- under `src/` carry `sx=`, baseline styles 23 MUI keys) is a starting estimate, not a fixed list —
252
- grep `src/**/*.jsx` for `sx=` against the 23 keys named in the Envelope's "Why the whole kit,
253
- measured" section to build the actual registry. This is scope item 1 itself; do not skip it by
254
- registering only `MobileBottomNav`'s two already-known exports.
255
-
256
- **On the "stop and report if large" clause:** if fixing every real finding from test 2 would grow
257
- this WO well beyond a layer-relocation pass (i.e. touches component *behaviour*, not just moving an
258
- `sx` value into an export), STOP before committing anything and report the finding list instead of
259
- silently absorbing it all — this is explicitly named in the Envelope as an operator-level scope
260
- decision, not an implementer judgment call.
261
-
262
- **Known repeat-offense warning, restated because it has happened on the two immediately preceding
263
- work orders in this exact repo:** do not run `git commit` or `git push` under any circumstance. Leave
264
- the diff for the Orchestrator. If you find yourself about to commit "because everything passed", stop
265
- — that decision is not yours in this workflow, regardless of how clean the result looks.
266
-
267
- ### Mini-handover
268
-
269
- Repo: `ui-core-micha` (`C:\Users\biglmi\Documents\webapps\ui-core-micha`), branch `main`.
270
- WO: `work-orders/THEME-4.md`. **Wait for `THEME-3` to land and publish first** — same files.
271
- Follow `orchestrate-codex`.
@@ -1,341 +0,0 @@
1
- # THEME-5 — Hold the kit to its own baseline
2
-
3
- **Target repo:** `ui-core-micha` (branch `main` — this repo has no `develop`)
4
- **Tier:** 3 (shared core)
5
- **Review:** independent `reviewer` **and** `ui_reviewer` — both mandatory, concurrent. `ui_reviewer`
6
- applies because rendered colours change in a screen **ten apps mount**; see "Blast radius".
7
- **Version target:** the next **minor** after `THEME-4` — a new exported check is additive API. Read the
8
- published version at implementation time; do **not** hardcode a number from this file.
9
- **Strand:** `DS-18` follow-ups, both named in `THEME-4`'s landing notes
10
-
11
- ---
12
-
13
- ## A. Envelope
14
-
15
- ### Goal
16
-
17
- Two gaps left open by `THEME-4`, and they belong together because both are the same embarrassment:
18
- **the kit is not fully on the baseline it exists to enforce.**
19
-
20
- 1. `THEME-4`'s shadowing check normalises **spacing** shorthands only. Other MUI `sx` aliases —
21
- `bgcolor` above all — still compare as raw strings and would miss a collision.
22
- 2. The kit carries **off-palette colour values**. No app palette reaches them.
23
-
24
- ### Part 1 — finish the alias normalisation
25
-
26
- `SPACING_SHORTHAND_LONGHANDS` (`src/theme/themeCompleteness.js:383`) covers `p*` and `m*`. Extend the
27
- map to every MUI `sx` alias that can land on a property the baseline sets — `bgcolor` →
28
- `backgroundColor` is the one with a real near-term risk.
29
-
30
- **Verified state, so nobody hunts for a bug that is not there yet:** `MFA_ACTIVE_CARD_SX =
31
- { bgcolor: '#f0fdf4' }` is registered against `MuiCard` (`kitSxRegistry.js:190`), and the baseline
32
- sets `borderRadius`, `boxShadow` and `borderColor` on `MuiCard` — **not** `backgroundColor`. So there
33
- is **no live collision today**. This is a latent gap whose trigger is near: `THEME-3` has just shown
34
- the surface-token set still grows, and the day a `backgroundColor` default lands on `Paper` or `Card`
35
- the miss becomes silent.
36
-
37
- **Write the bound as an open one.** `THEME-4`'s WO named its own limits as a list — nested and
38
- conditional `sx` — and the first real miss was something not on that list (alias spelling). Say
39
- "unknown normalisation gaps remain" rather than enumerating, because an enumeration reads as
40
- completeness.
41
-
42
- ### Part 2 — an off-palette colour scan, and fix what it finds
43
-
44
- A new exported check, same finding contract as the others (`{ findings: [{ surface, reason }] }`),
45
- scanning `src/**` for colour values that are not baseline tokens. Wire it as a hard failure in ucm's
46
- own suite.
47
-
48
- **Three classes, and a hex-only scan catches just the first:**
49
-
50
- | Class | Example | In scope |
51
- |---|---|---|
52
- | Hex literal | `bgcolor: '#f5f5f5'` | **yes** |
53
- | Named CSS colour | `bgcolor: 'white'` (`MFAComponent.jsx:231`) | **yes** — same defect, invisible to a hex scan |
54
- | MUI default-ramp reference | `bgcolor: 'grey.50'` (`QrSignupManager.jsx:340`) | **report only, do not fix** |
55
-
56
- The third class routes through the theme, so it is not off-palette in the same way — but it points at
57
- MUI's untouched grey ramp rather than at anything the estate decided. Report it as its own category
58
- and leave the decision for later; folding a judgement call into a cleanup would be scope creep.
59
-
60
- **Excluded from the scan, by operator decision:** the **generated print document** in
61
- `QrSignupManager.jsx:185-240`. It is not app UI — it is a standalone HTML string with its own `body`,
62
- `@media print` rules and `font-family: Arial`, rendered outside the React tree where **no theme is
63
- available**. Its ten values (`#f5f7fb`, `#d9e2f2` ×3, `#e8f0ff`, `#f8faff`, `#ffffff` ×3, `#122033`,
64
- `#23408e`) cannot take tokens. Excluding it is a correctness requirement, not a preference: scanning it
65
- would produce ten permanent false positives, and exempting those one by one is exactly the
66
- mass-exemption that `THEME-4` warned turns a check into a no-op. **Exclude the region and state the
67
- reason in the code.** Making the printed poster follow each app's identity is a genuine idea and a
68
- separate work order — not this one.
69
-
70
- ### The mappings, decided and each verified against `tokens.js`
71
-
72
- Five values in `MFAComponent.jsx`:
73
-
74
- | Where | Today | Target | Why |
75
- |---|---|---|---|
76
- | `:25` `MFA_ACTIVE_CARD_SX` background | `#f0fdf4` | `success.bg` (`#E5F4E9`) | light green tint marking the active factor |
77
- | `:231` border | `1px solid #eee` | `divider` | it is a border |
78
- | `:231` background | `bgcolor: 'white'` | `background.paper` | the named-colour case |
79
- | `:244` background | `bgcolor: '#eee'` | `background.subtle` (`#F4F5F6`) | **a fill, not a border** |
80
- | `:303` background | `bgcolor: '#f5f5f5'` | `background.subtle` (`#F4F5F6`) | near-exact match |
81
- | `:314` border | `1px solid #ddd` | `divider` | it is a border |
82
-
83
- **`#eee` appears in two different roles** — a border at `:231` and a **fill** at `:244`. A blind
84
- find-and-replace would put a translucent border colour (`rgba(33,37,41,.10)`) into a filled box, which
85
- is semantically wrong and visually lighter than intended. Map by role, not by value.
86
-
87
- ### Blast radius, and the operator's decision on it
88
-
89
- No app imports `MFAComponent` directly — it is reached transitively: `AccountPage` renders
90
- `SecurityComponent` (`AccountPage.jsx:223`) which renders `MFAComponent`, and **at least ten apps
91
- mount `AccountPage`** — bigler-consult, cockpit, fitness-monitor, hpc-bridge, hram, innoservice,
92
- jg-ferien, kerzenziehen, reimbursements. This is live, widely-mounted code, not a dead corner.
93
-
94
- **Operator decision: map the values, and do not add a rendered gate for it.** The targets are near
95
- neighbours of the values they replace, and the estate has no prototype for this screen to compare
96
- against. **Do not re-add the two-width check** — but every changed value **must be listed in the
97
- register note**, so a shift that lands unseen is at least recorded. That listing is the substitute for
98
- looking.
99
-
100
- ### Non-goals / do not touch
101
-
102
- - **The print document** (above). Excluded, unchanged.
103
- - **`grey.*` references.** Reported, not fixed.
104
- - **`DS-18`'s second half** — "which components can violate a rule". Still without a driver, and
105
- `THEME-4` is now a cautionary data point for it: a check whose set comes from a heuristic can be
106
- green while missing real cases.
107
- - **App-side scanning.** An app's own components shadowing the baseline stays a follow-up; it wants
108
- cockpit's adoption first so there is a real consumer to test against.
109
- - No baseline token change. Part 2 consumes tokens; it does not add any.
110
- - No change to `assertThemeComplete`'s surface registry, `createAppTheme`'s signature, the
111
- `kitSxRegistry` entries, or any component's public props.
112
- - `chartLabels.js`'s hex values are **baseline tokens** — leave them; if the scan flags them, the scan's
113
- allowlist is wrong, not the file.
114
-
115
- ### Risks
116
-
117
- - **A visual change in ten apps, published without a staging net.** A push to `main` touching `src/**`
118
- publishes; the independent reviews are the only gate. The mitigation is the mandatory value listing,
119
- plus `ui_reviewer` reading the diff against the mapping table above.
120
- - **Mapping by value instead of by role** — the `#eee` trap. The table above exists so this is a
121
- checkable instruction rather than a matter of care.
122
- - **An over-eager scan.** `src/theme/` legitimately contains every token's hex definition, and
123
- `chartLabels.js` consumes them. A scan without a correct allowlist floods the suite and gets
124
- disabled, which is worse than no scan.
125
- - **Wrong allowlist shape.** The allowlist must be derived from the palette rather than hand-listed, or
126
- it goes stale the next time a token lands — `THEME-3` added one three days into this strand.
127
-
128
- ### Required tests to WRITE
129
-
130
- 1. **Non-vacuity for the scan:** a fixture source containing `bgcolor: '#123456'` produces a finding;
131
- the same source using a palette token produces none.
132
- 2. **The named-colour class:** `bgcolor: 'white'` is flagged. This is the case a hex-only scan misses,
133
- and it exists in the code today.
134
- 3. **The exclusion holds:** the print-document region produces **no** findings, and the exclusion is
135
- scoped — a hex added elsewhere in `QrSignupManager.jsx` **is** still flagged.
136
- 4. **The allowlist is palette-derived:** adding a token to the palette makes a source using that value
137
- pass, without editing the check.
138
- 5. **Part 1:** a fixture whose `sx` uses `bgcolor` collides with a baseline `backgroundColor` default
139
- and is reported. Prove non-vacuity — this must fail before the map is extended.
140
- 6. `MFAComponent`'s existing spec stays green, and `THEME-4`'s shadowing check still returns no
141
- findings for the kit.
142
-
143
- Plus `tsc -p tsconfig.build.json --noEmit` clean. **No full-suite run** — affected set is the theme
144
- module's specs plus `MFAComponent`'s.
145
-
146
- ### Verification
147
-
148
- No rendered gate, per the operator decision above. What replaces it: the mapping table is the spec, and
149
- the register note must list **every value changed, from and to**. If the implementation deviates from
150
- the table for any of the six rows, that is a stop-and-report — the roles were resolved by reading the
151
- code, and a different target means the reading was wrong.
152
-
153
- ### Parity guardrail
154
-
155
- Six values change in one component; everything else in the kit renders identically. No behaviour, no
156
- props, no permissions, no data contract.
157
-
158
- ---
159
-
160
- ## B. Implementation map
161
-
162
- *Filled by the Orchestrator on `git pull` — see `AGENTS.md` → "Work Order".*
163
-
164
- ### Execution directive (read this first)
165
-
166
- > **If you are the implementer reading this work order as your own specification: this section is
167
- > NOT addressed to you.** It tells the Orchestrator how to invoke you. **You ARE that invocation —
168
- > do NOT shell out to `codex exec`.**
169
- >
170
- > Implement through `codex exec` in the background — invoked directly via Bash (never the
171
- > `debugger`/`*_coder` Agent wrappers) with BOTH flags `--skip-git-repo-check` and
172
- > `--dangerously-bypass-approvals-and-sandbox`. **Pass the WO via stdin, not as a positional
173
- > argument** (a positional arg hits Windows' command-line length limit — proven repeatedly in this
174
- > repo). Fallback to direct Claude implementation only on Codex quota/rate-limit/non-zero exit — and
175
- > note that the fallback flips authorship, so both reviewers stay mandatory either way.
176
- >
177
- > **Read `git log origin/main..HEAD` and `git status` before your own review.** On `SHELL-3` and
178
- > `SHELL-4` Codex committed its own change and wrote a self-reported review into `WORK_ORDERS.md`;
179
- > `THEME-4` was the first of the three where it did not. An implementer commit is a blocker to
180
- > surface, and a register row naming a review the Orchestrator did not itself start is invalid.
181
-
182
- ### Context package
183
-
184
- **Precondition confirmed:** `THEME-4` is landed and published (`c64e024`, register row `done`,
185
- `package.json` reads `2.34.0`). Clean starting state, no implementer commit on top.
186
-
187
- **Note on the WO's own arithmetic:** the Envelope's "Five values in `MFAComponent.jsx`" heading is
188
- followed by a table of **six** rows (`:25`, `:231`×2, `:244`, `:303`, `:314`) — the register's own
189
- summary already says "the six values it finds", so treat the table (six rows) as authoritative, the
190
- heading as stale, consistent with two prior stale-count mismatches in this strand (`SHELL-4`'s
191
- "ten to six", `THEME-4`'s "51 files").
192
-
193
- **A likely seventh value the table omits — verify before assuming the table is exhaustive:**
194
- `src/components/MFAComponent.jsx:313` has `bgcolor: 'white'` in the *same* sx object as the WO's row 6
195
- (`:314`, `border: '1px solid #ddd'` → `divider`) — a recovery-code chip box, structurally identical in
196
- role to row 3 (`:231`'s `bgcolor: 'white'` → `background.paper`, the QR-code box). If the new scan (Part
197
- 2) flags `:313` and it is not in the six-row table, this is not a table deviation to stop-and-report —
198
- it is the same white-box-fill role already established at `:231`, map it identically to
199
- `background.paper` and list it in the register note as a seventh, table-omitted finding the scan
200
- caught. Confirm this reading against the actual code before implementing; do not assume the six-row
201
- table is exhaustive just because the Envelope calls it "decided".
202
-
203
- **Current file state (verified, so Codex works from real line numbers, not the WO's possibly-drifted
204
- ones):**
205
- ```
206
- src/components/MFAComponent.jsx:25 export const MFA_ACTIVE_CARD_SX = { bgcolor: '#f0fdf4' };
207
- src/components/MFAComponent.jsx:231 <Box sx={{ p: 2, bgcolor: 'white', border: '1px solid #eee' }}>
208
- src/components/MFAComponent.jsx:244 bgcolor: '#eee', (inside a multi-line sx, role: fill)
209
- src/components/MFAComponent.jsx:303 <Box sx={{ bgcolor: '#f5f5f5', p: 2, borderRadius: 1 }}>
210
- src/components/MFAComponent.jsx:313 bgcolor: 'white', (inside a multi-line sx -- the omitted 7th)
211
- src/components/MFAComponent.jsx:314 border: '1px solid #ddd',
212
- ```
213
- All six table rows' line numbers matched exactly on inspection — no drift.
214
-
215
- **Token values to map to, confirmed against `src/theme/tokens.js`:**
216
- - `divider: 'rgba(33,37,41,.10)'` (`tokens.js:69`)
217
- - `background.paper: '#FFFFFF'` / `background.default: '#FAFAFA'` (`tokens.js:65-66`)
218
- - `background.subtle: '#F4F5F6'` (`tokens.js:67`, landed by `THEME-3`)
219
- - `success.bg: '#E5F4E9'` (`tokens.js:80`)
220
- These are accessed in a component via `theme.palette.<path>`, i.e. `sx={{ bgcolor: 'divider' }}` /
221
- `sx={{ bgcolor: 'background.subtle' }}` / `sx={{ bgcolor: 'success.bg' }}` (MUI resolves a dotted
222
- palette-path string in `sx`) — this is the same string-token-reference pattern already used and
223
- proven in `SHELL-4`'s `borderColor: 'divider'` fix. Do **not** import raw hex constants.
224
-
225
- **Part 1 — extend `SPACING_SHORTHAND_LONGHANDS` (`src/theme/themeCompleteness.js:383`,
226
- `expandShorthandProperty` at :402):** add a `bgcolor` → `['backgroundColor']` entry (and, while
227
- touching this, consider whether `color`/other MUI palette-path aliases need the same treatment — the
228
- WO names `bgcolor` as "the one with a real near-term risk", so that is the required minimum; do not
229
- expand the alias table beyond what's verifiably a real MUI `sx` shorthand, to avoid the "write the
230
- bound as an open one" instruction turning into an unbounded audit). Required test 5 (non-vacuity):
231
- a fixture registry entry with `sx: { bgcolor: '#fff' }` against a MUI key whose baseline
232
- `styleOverrides` sets `backgroundColor` must be flagged — construct this as a **fixture-only** test
233
- (pass a custom `registry` + a fixture theme/component config to `assertKitSxDisjoint`, following the
234
- existing fixture pattern already in `tests/themeCompleteness.test.js`'s `'kit sx disjointness'`
235
- describe block, e.g. the `FixtureBottomNav`/`FixtureChip`/`FixtureButton` entries) since, per the
236
- Envelope, there is genuinely no live `backgroundColor` collision in the real kit today — do not invent
237
- one in the real registry just to exercise the code path.
238
-
239
- **Part 2 — the off-palette colour scan.** New exported function in
240
- `src/theme/themeCompleteness.js` (same file, same `{ findings: [{ surface, reason }] }` contract as
241
- `assertThemeComplete`/`assertKitSxDisjoint`/`reportKitSxBypasses` — name it something like
242
- `reportOffPaletteColours`, Codex's call). Reuse the existing hand-rolled brace/quote-aware source
243
- scanning approach already proven in `reportKitSxBypasses` (`themeCompleteness.js`, functions
244
- `jsxOpeningTag`/`topLevelSxValue` and the `sources.map(...)` normalisation shape shared with
245
- `reportThemeAdoption`) rather than inventing a second scanning mechanism.
246
-
247
- **Two known false-positive traps for the colour regex, found while preparing this map — test against
248
- both explicitly:**
249
- 1. `src/components/charts/chartLabels.js:3-4` has a comment referencing GitHub issue numbers
250
- `mui-x#18768` and `#18399` — a naive `/#[0-9a-f]{3,8}/i` pattern matches `#18768` as a false "hex
251
- literal" (all five characters `1,8,7,6,8` are valid hex digits). The scan must not flag comment
252
- text, or must otherwise be precise enough to skip this. This is exactly the "over-eager scan...
253
- gets disabled" risk the Envelope names — verify the scan is blind to this file/line before calling
254
- Part 2 done.
255
- 2. `src/theme/createAppTheme.js:45` has a comment mentioning `'#FFFFFF'`, and `:188` has a genuine
256
- `'#FFFFFF'` string literal used for contrast-ratio computation (not a component style) — per the
257
- Envelope's own risk note, `src/theme/` legitimately contains token hex definitions and must be
258
- excluded from the scan's target set entirely (scan `src/components/`, `src/messaging/`,
259
- `src/notifications/`, `src/pages/`, `src/auth/`, `src/layout/`, `src/onboarding/` — i.e. component
260
- source, not `src/theme/` itself).
261
-
262
- **The palette-derived allowlist (required test 4):** build the allowlist by walking
263
- `BASELINE_PALETTE`/`BASELINE_STATIC` (or the fully-resolved output of `createAppTheme(...)`) and
264
- collecting every hex/rgba string value found in it, rather than hand-listing values — this is what
265
- required test 4 (adding a token to the palette should make a source using that value pass, without
266
- editing the check) actually proves. `THEME-3` is cited in the Envelope as evidence a hand-listed
267
- allowlist goes stale fast (a new baseline token landed three days into this strand).
268
-
269
- **Named-CSS-colour detection (required test 2):** `bgcolor: 'white'` must be flagged same as a hex
270
- literal — CSS named colours are a small, fixed, enumerable set (`white`, `black`, `red`, `grey`,
271
- etc. — the 16 basic CSS colour keywords are the practical minimum; do not attempt to support the full
272
- 147-name X11/CSS list unless a real instance demands it, per the WO's own anti-gold-plating stance).
273
-
274
- **The `grey.*` report-only class (required, do not fix):** `src/components/QrSignupManager.jsx:340`
275
- has `bgcolor: 'grey.50'` — this is a **dotted MUI theme-path string**, not a hex/named-colour literal,
276
- so it needs its own detection branch (match `/^[a-z]+\.\d+$/i`-shaped sx string values referencing
277
- MUI's stock palette ramps, distinct from both the hex/named-colour findings and the
278
- divider/background.subtle/success.bg *baseline* token-path strings this same WO is busy introducing
279
- elsewhere — do not let the scan flag the very token references Part 1's own fixes create). Report it
280
- under a distinct `reason` wording (e.g. "uses MUI's untouched grey ramp, not a baseline token — review,
281
- do not auto-fix") so a consumer of the findings can filter report-only from must-fix.
282
-
283
- **The print-document exclusion (required test 3):** exclude the template-literal region inside
284
- `QrSignupManager.jsx`'s `printWindow.document.write(\`...\`)` call — currently spans roughly
285
- `:178`-`:266` (verify exact bounds by locating the `printWindow.document.write(` call and its
286
- matching closing backtick+paren, not by trusting these line numbers, since the WO's own `:185-240`
287
- estimate was already off by several lines against the current file). The exclusion must be scoped
288
- narrowly enough that a hex literal added elsewhere in the same file (outside that one template
289
- literal) still gets flagged — required test 3's second half.
290
-
291
- ### Invariants / do-not-touch
292
-
293
- No change to `assertThemeComplete`'s surface registry, `createAppTheme`'s signature, `kitSxRegistry`
294
- entries structure, or any component's public props. No baseline token added (Part 2 consumes existing
295
- tokens only). `chartLabels.js`'s own values are not colours to fix (see trap above) — if the finished
296
- scan flags anything in `src/theme/**`, that is a scan-scope bug, not a file to edit.
297
-
298
- ### Addendum — operator decision on the scan's broader findings (chunk 2)
299
-
300
- The first implementation chunk correctly stopped without committing and reported a real scope
301
- question instead of deciding it: with the off-palette scan's detection widened beyond hex + basic
302
- named colours (per Part 2), it also catches two values **outside `MFAComponent`**, which the
303
- Envelope's Parity guardrail ("six values change in one component; everything else in the kit renders
304
- identically") did not anticipate:
305
-
306
- 1. `src/components/SocialLoginButtons.jsx:37` — `border: '1px solid rgba(0,0,0,0.2)'` on the Google
307
- icon circle. A real rendered `sx` border, same class of finding as the MFA border fixes.
308
- 2. `src/components/charts/exportChart.js:48` — `context.fillStyle = 'white'` inside a **Canvas 2D API
309
- call** (PNG export), not JSX/`sx` — structurally like the already-excluded print document in that it
310
- runs outside the React/theme tree, but unlike it, plumbing a resolved colour in is straightforward
311
- (the caller has `useTheme()` access; a colour can be passed as a parameter to the export function).
312
-
313
- **Operator decision (this session): fix both**, per Codex's own recommended option. This is an
314
- explicit, approved widening of scope beyond the original Envelope's blast radius — record it as such
315
- in the register note, do not fold it in as if the original Envelope already covered it.
316
-
317
- **Scope of the fix:**
318
- - Widen the scan's colour detection to catch `rgba(...)` literals (not just hex + the basic named-colour
319
- set), so this class is caught mechanically going forward, not just this one instance.
320
- - `SocialLoginButtons.jsx:37`: map to `divider` (the same token every other border-role finding in this
321
- WO maps to) — confirm this reads correctly next to the icon (a translucent, lighter border than the
322
- current `rgba(0,0,0,0.2)`; this is the intended effect of holding to the baseline, not a regression).
323
- - `exportChart.js:48`: resolve the fill colour from the theme at the call site (the component invoking
324
- the export utility has `useTheme()`), and pass it into `exportChart`'s existing call rather than
325
- hardcoding a new default inside the utility — check `exportChart.js`'s current signature and its
326
- caller(s) (`ChartFrame.jsx`, most likely) before deciding the exact parameter shape; prefer the
327
- smallest signature change that removes the hardcoded literal, not a redesign of the export API.
328
- - Both new value changes must be listed in the register note the same way as the seven MFA values
329
- (from → to, with role), per the Envelope's "every changed value must be listed" requirement, which
330
- the operator's decision extends to cover these two as well.
331
- - Re-run both reviewers (`reviewer` + `ui_reviewer`) on the complete, widened diff — the WO's original
332
- review requirement stands, now over a larger diff.
333
-
334
- This addendum does not change anything else in Part A/B above — the six/seven MFA mappings, the
335
- allowlist requirement, the print-document exclusion, and the `grey.*` report-only class are unchanged.
336
-
337
- ### Mini-handover
338
-
339
- Repo: `ui-core-micha` (`C:\Users\biglmi\Documents\webapps\ui-core-micha`), branch `main`.
340
- WO: `work-orders/THEME-5.md`. Follow `orchestrate-codex`. **Chunk 2**: implement the Addendum above on
341
- top of chunk 1's uncommitted working-tree state — do not discard chunk 1's work, extend it.