@rubytech/create-maxy-code 0.1.478 → 0.1.479

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 (100) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/docs/superpowers/plans/2026-07-20-task-1789-reseat-channel-row-fork.md +1244 -0
  3. package/payload/platform/docs/superpowers/plans/2026-07-20-task-1818-loop-gate-app-routes.md +462 -0
  4. package/payload/platform/docs/superpowers/plans/2026-07-20-task-1819-top-level-label-allowlist.md +321 -0
  5. package/payload/platform/docs/superpowers/plans/2026-07-20-task-1831-data-portal-class-derived-allowlist.md +2177 -0
  6. package/payload/platform/docs/superpowers/specs/2026-07-20-task-1789-reseat-channel-row-fork-design.md +201 -0
  7. package/payload/platform/docs/superpowers/specs/2026-07-20-task-1818-loop-gate-app-routes-design.md +217 -0
  8. package/payload/platform/docs/superpowers/specs/2026-07-20-task-1819-top-level-label-allowlist-design.md +80 -0
  9. package/payload/platform/docs/superpowers/specs/2026-07-20-task-1831-data-portal-class-derived-allowlist-design.md +163 -0
  10. package/payload/platform/lib/graph-style/dist/index.d.ts.map +1 -1
  11. package/payload/platform/lib/graph-style/dist/index.js +22 -0
  12. package/payload/platform/lib/graph-style/dist/index.js.map +1 -1
  13. package/payload/platform/lib/graph-style/src/__tests__/parity.test.ts +6 -0
  14. package/payload/platform/lib/graph-style/src/index.ts +20 -0
  15. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +13 -1
  16. package/payload/platform/plugins/cloudflare/PLUGIN.md +26 -1
  17. package/payload/platform/plugins/cloudflare/bin/d1-http.mjs +80 -0
  18. package/payload/platform/plugins/cloudflare/bin/portal-enrol.mjs +17 -2
  19. package/payload/platform/plugins/cloudflare/bin/portal-index-push.mjs +357 -0
  20. package/payload/platform/plugins/cloudflare/bin/schema-exposed-dirs.mjs +103 -0
  21. package/payload/platform/plugins/cloudflare/mcp/__tests__/authorize.test.ts +2 -2
  22. package/payload/platform/plugins/cloudflare/mcp/__tests__/d1-http.test.ts +96 -0
  23. package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-directory-listing.test.ts +120 -0
  24. package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-enrol.test.ts +59 -4
  25. package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-index-push.test.ts +176 -0
  26. package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-index-state-contract.test.ts +75 -0
  27. package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-indexed-download.test.ts +131 -0
  28. package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-sign.test.ts +68 -0
  29. package/payload/platform/plugins/cloudflare/mcp/__tests__/schema-exposed-dirs.test.ts +88 -0
  30. package/payload/platform/plugins/cloudflare/mcp/__tests__/template-config.test.ts +39 -0
  31. package/payload/platform/plugins/cloudflare/skills/data-portal/SKILL.md +68 -1
  32. package/payload/platform/plugins/cloudflare/skills/data-portal/schema.sql +30 -1
  33. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/_lib/portal-sign.mjs +87 -0
  34. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/_lib/session.ts +8 -4
  35. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/_lib/types.ts +10 -0
  36. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/download.ts +107 -1
  37. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/files.ts +82 -2
  38. package/payload/platform/plugins/cloudflare/skills/data-portal/template/index.html +9 -0
  39. package/payload/platform/plugins/cloudflare/skills/data-portal/template/portal.css +56 -0
  40. package/payload/platform/plugins/cloudflare/skills/data-portal/template/portal.js +98 -2
  41. package/payload/platform/plugins/cloudflare/skills/data-portal/template/wrangler.toml +12 -0
  42. package/payload/platform/plugins/docs/references/cloudflare.md +12 -0
  43. package/payload/platform/plugins/scheduling/mcp/dist/__tests__/portal-index-audit.test.d.ts +2 -0
  44. package/payload/platform/plugins/scheduling/mcp/dist/__tests__/portal-index-audit.test.d.ts.map +1 -0
  45. package/payload/platform/plugins/scheduling/mcp/dist/__tests__/portal-index-audit.test.js +66 -0
  46. package/payload/platform/plugins/scheduling/mcp/dist/__tests__/portal-index-audit.test.js.map +1 -0
  47. package/payload/platform/plugins/scheduling/mcp/dist/lib/portal-index-audit.d.ts +41 -0
  48. package/payload/platform/plugins/scheduling/mcp/dist/lib/portal-index-audit.d.ts.map +1 -0
  49. package/payload/platform/plugins/scheduling/mcp/dist/lib/portal-index-audit.js +75 -0
  50. package/payload/platform/plugins/scheduling/mcp/dist/lib/portal-index-audit.js.map +1 -0
  51. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +122 -0
  52. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
  53. package/payload/server/public/activity.html +8 -6
  54. package/payload/server/public/assets/{AdminLoginScreens-DR5eLF-a.js → AdminLoginScreens-DkxQZnvB.js} +1 -1
  55. package/payload/server/public/assets/AdminShell-Cv_nIFGe.js +2 -0
  56. package/payload/server/public/assets/Checkbox-CsTWK8mm.js +1 -0
  57. package/payload/server/public/assets/activity-BbnTiVBT.js +1 -0
  58. package/payload/server/public/assets/{admin-D2KLZnQW.js → admin-BZY3i_Ff.js} +1 -1
  59. package/payload/server/public/assets/{browser-CDWqEiCD.js → browser-BbIiSFKr.js} +1 -1
  60. package/payload/server/public/assets/{calendar-BG7fOpbB.js → calendar-BvxeTHvQ.js} +1 -1
  61. package/payload/server/public/assets/chat-DUKxufRk.js +1 -0
  62. package/payload/server/public/assets/chevron-left-BtfJD6LL.js +1 -0
  63. package/payload/server/public/assets/data-hl1wa-Ax.js +1 -0
  64. package/payload/server/public/assets/{graph-DRloNic4.js → graph-CDSGRoeb.js} +1 -1
  65. package/payload/server/public/assets/graph-labels-C5qLwnWA.js +1 -0
  66. package/payload/server/public/assets/{maximize-2-CzDaBugs.js → maximize-2-CAzH8dED.js} +1 -1
  67. package/payload/server/public/assets/{operator-BZeeyait.js → operator-BK7r8DAB.js} +1 -1
  68. package/payload/server/public/assets/{page-ef-6rRPL.js → page-B5YngOrK.js} +1 -1
  69. package/payload/server/public/assets/{page-B0obcg3b.js → page-BsCS0Dmc.js} +1 -1
  70. package/payload/server/public/assets/{public-9D3MMOkC.js → public-C1Pz-IBs.js} +1 -1
  71. package/payload/server/public/assets/{rotate-ccw-DXEKUhXP.js → rotate-ccw-UDln4Tou.js} +1 -1
  72. package/payload/server/public/assets/{tasks-BB0L7e5a.js → tasks-B-cLsn3p.js} +1 -1
  73. package/payload/server/public/assets/{time-entry-format-CsYAjplS.js → time-entry-format-DPOBIE18.js} +1 -1
  74. package/payload/server/public/assets/{triangle-alert-0lSBIUg-.js → triangle-alert-Dz-CZKo5.js} +1 -1
  75. package/payload/server/public/assets/{useCopyFeedback-jTBQ2h0V.js → useCopyFeedback-wtUHGohk.js} +1 -1
  76. package/payload/server/public/assets/{useSelectionMode-BooArySZ.js → useSelectionMode-sph7AQT5.js} +1 -1
  77. package/payload/server/public/assets/useSubAccountSwitcher-BRIluIKf.css +1 -0
  78. package/payload/server/public/assets/{useVoiceRecorder-PUT8q_sm.js → useVoiceRecorder-DN4jYQ0A.js} +1 -1
  79. package/payload/server/public/brand-defaults.css +1 -0
  80. package/payload/server/public/browser.html +5 -5
  81. package/payload/server/public/calendar.html +6 -6
  82. package/payload/server/public/chat.html +12 -12
  83. package/payload/server/public/data.html +11 -11
  84. package/payload/server/public/graph.html +11 -11
  85. package/payload/server/public/index.html +14 -14
  86. package/payload/server/public/operator.html +14 -14
  87. package/payload/server/public/privacy.html +1 -0
  88. package/payload/server/public/public.html +12 -12
  89. package/payload/server/public/tasks.html +6 -5
  90. package/payload/server/public/vnc-popout.html +1 -0
  91. package/payload/server/server.js +741 -366
  92. package/payload/server/public/assets/AdminShell-D9zaUxPd.js +0 -2
  93. package/payload/server/public/assets/Checkbox-DcbbAIe5.js +0 -1
  94. package/payload/server/public/assets/activity-C9P5NjEZ.js +0 -1
  95. package/payload/server/public/assets/chat-RyH-WYQC.js +0 -1
  96. package/payload/server/public/assets/chevron-left-DmXCr6nB.js +0 -1
  97. package/payload/server/public/assets/data-BaY_LkLR.js +0 -1
  98. package/payload/server/public/assets/graph-labels-DD-GqS4v.js +0 -1
  99. package/payload/server/public/assets/useSubAccountSwitcher-D9knHOKq.css +0 -1
  100. /package/payload/server/public/assets/{useSubAccountSwitcher-BZnzc5C3.js → useSubAccountSwitcher-v8LyBzZN.js} +0 -0
@@ -0,0 +1,321 @@
1
+ # Task 1819 — Top-Level Label Allowlist Implementation Plan
2
+
3
+ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
+
5
+ **Goal:** Make the two failing top-level-label tests pass by resolving the real disagreement between the derived allowlist and the client mirror, and register `CashEntry` as a top-level label across every registry that gates one.
6
+
7
+ **Architecture:** Two independent tasks. Task 1 is the 1819 correctness fix: one label into `STATIC_TOP_LEVEL_LABELS` plus the doc comment that would have prevented the drift. Task 2 registers `CashEntry` across six surfaces in the shared `graph-style` lib and the two UI label sets. A reviewer can accept Task 1 and reject Task 2.
8
+
9
+ **Tech Stack:** TypeScript, vitest, Node 22.22.0 via nvm.
10
+
11
+ ## Global Constraints
12
+
13
+ - Run everything under Node 22.22.0 (`source ~/.nvm/nvm.sh && nvm use 22.22.0`). The repo's jsdom vitest env requires `require(esm)`, which needs Node >= 20.19 / >= 22.12.
14
+ - Working directory is the worktree: `/Users/neo/getmaxy/maxy-code/.claude/worktrees/task-1819-top-level-label-allowlist`. All paths below are relative to it.
15
+ - Never edit or rebuild through `maxy-code/platform/lib/graph-style/dist` while it is a symlink to the parent checkout. Task 2 Step 1 replaces it with a local build.
16
+ - Do not edit either test's assertions. The tests are correct; the sets are wrong.
17
+ - Every commit carries the trailers:
18
+ ```
19
+ Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
20
+ Session: 693bcfd0-f04e-49ed-8ebe-593e59be24c2
21
+ ```
22
+
23
+ ---
24
+
25
+ ### Task 1: Add `InboundInvoice` to the static allowlist
26
+
27
+ `InboundInvoice` is a genuine operator-entry top-level label. Commit `7b225f814` moved its row from `schema-construction.md`'s parsed `## Top-level node types` table into `schema-base.md`'s `## Node Types` table, which the derivation deliberately never parses because it mixes in child types. `STATIC_TOP_LEVEL_LABELS` is the compartment for exactly that case.
28
+
29
+ **Files:**
30
+ - Modify: `maxy-code/platform/ui/server/lib/top-level-labels.ts:25-69`
31
+ - Test (existing, do not edit): `maxy-code/platform/ui/server/lib/top-level-labels.test.ts`
32
+ - Test (existing, do not edit): `maxy-code/platform/ui/server/routes/__tests__/graph-default-topLevel.test.ts`
33
+
34
+ **Interfaces:**
35
+ - Consumes: nothing from other tasks.
36
+ - Produces: `STATIC_TOP_LEVEL_LABELS` gains the member `'InboundInvoice'`. Task 2 adds `'CashEntry'` to this same set.
37
+
38
+ - [ ] **Step 1: Run the two tests to confirm they fail**
39
+
40
+ ```bash
41
+ cd maxy-code/platform/ui
42
+ source ~/.nvm/nvm.sh && nvm use 22.22.0
43
+ npx vitest run server/lib/top-level-labels.test.ts server/routes/__tests__/graph-default-topLevel.test.ts
44
+ ```
45
+
46
+ Expected: `Test Files 2 failed (2)`, `Tests 2 failed | 12 passed (14)`. Both failures are the same set diff, with `InboundInvoice` present in expected and absent from received.
47
+
48
+ - [ ] **Step 2: Add the label**
49
+
50
+ In `maxy-code/platform/ui/server/lib/top-level-labels.ts`, inside `STATIC_TOP_LEVEL_LABELS`, add `'InboundInvoice'` immediately after `'Invoice',` (line 51) so the two invoice labels read together:
51
+
52
+ ```ts
53
+ 'Invoice',
54
+ // Supplier invoice. Declared in schema-base.md's `## Node Types` table
55
+ // (promoted there from schema-construction.md's top-level table by
56
+ // 7b225f814), which this module never parses — so it is static, not
57
+ // derived. Top-level because it is operator-entry with a natural key
58
+ // (accountId, supplier, confirmationNumber), unlike its InvoiceLine /
59
+ // InvoicePayment / Credit children.
60
+ 'InboundInvoice',
61
+ ```
62
+
63
+ - [ ] **Step 3: Document the reverse migration**
64
+
65
+ The existing doc comment on `STATIC_TOP_LEVEL_LABELS` covers only the forward direction. Replace the comment at lines 25-29 with:
66
+
67
+ ```ts
68
+ /**
69
+ * Top-level labels not (yet) sourced from a vertical `## Top-level node types`
70
+ * section. Membership moves in both directions, and both are load-bearing:
71
+ *
72
+ * - A vertical GAINS a top-level section: its labels move from here into
73
+ * the derived union, and the STATIC copy is removed in the same edit.
74
+ * - A label is PROMOTED INTO `schema-base.md`: it must be ADDED here in the
75
+ * same edit. `schema-base.md` has no top-level section and is never
76
+ * parsed (its `## Node Types` table mixes in child types), so a promotion
77
+ * silently deletes the label from the derived set. This is what happened
78
+ * to `InboundInvoice` in 7b225f814 and it is what Task 1819 fixed.
79
+ */
80
+ ```
81
+
82
+ - [ ] **Step 4: Run the two tests to verify they pass**
83
+
84
+ ```bash
85
+ cd maxy-code/platform/ui
86
+ source ~/.nvm/nvm.sh && nvm use 22.22.0
87
+ npx vitest run server/lib/top-level-labels.test.ts server/routes/__tests__/graph-default-topLevel.test.ts
88
+ ```
89
+
90
+ Expected: `Test Files 2 passed (2)`, `Tests 14 passed (14)`.
91
+
92
+ The `keeps STATIC_TOP_LEVEL_LABELS disjoint from the table-derived labels` test in the same file must still pass — it proves `InboundInvoice` is genuinely absent from every parsed table, confirming static is the right home.
93
+
94
+ - [ ] **Step 5: Commit**
95
+
96
+ ```bash
97
+ git add maxy-code/platform/ui/server/lib/top-level-labels.ts
98
+ git commit -m "fix: restore InboundInvoice to the top-level label allowlist (1819)
99
+
100
+ Commit 7b225f814 promoted the InboundInvoice row out of
101
+ schema-construction.md's parsed top-level table into schema-base.md's
102
+ Node Types table. That table is never parsed — it mixes child types —
103
+ so the derived allowlist silently lost a real operator-entry label and
104
+ the deep-equals guard against the client mirror went red.
105
+
106
+ The client mirror was right. STATIC_TOP_LEVEL_LABELS is the compartment
107
+ for base-schema labels with no top-level section, and InboundInvoice had
108
+ never been added to it.
109
+
110
+ Also documents the reverse migration on STATIC_TOP_LEVEL_LABELS. The
111
+ comment covered only 'vertical gains a section, label leaves static' and
112
+ was silent on 'label promoted into base, label enters static' — the
113
+ direction that caused this.
114
+
115
+ Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
116
+ Session: 693bcfd0-f04e-49ed-8ebe-593e59be24c2"
117
+ ```
118
+
119
+ ---
120
+
121
+ ### Task 2: Register `CashEntry` as a top-level label
122
+
123
+ `CashEntry` was added by the same commit and is absent from every registry, so it fails no test but has no `/graph` chip. It is money "not attached to any invoice" with no parent label, so unlike a child label it cannot be reached by drilling down — without a chip it is unreachable except by search.
124
+
125
+ **Files:**
126
+ - Modify: `maxy-code/platform/lib/graph-style/src/index.ts` — colour table, icon table, `pickShortLabel`, `pickDisplayName`
127
+ - Modify: `maxy-code/platform/ui/app/lib/graph-labels.ts:139-191` — `FILTER_TOP_LEVEL_LABELS`
128
+ - Modify: `maxy-code/platform/ui/server/lib/top-level-labels.ts` — `STATIC_TOP_LEVEL_LABELS`
129
+ - Test (existing): `maxy-code/platform/lib/graph-style/src/__tests__/icons.test.ts`, `parity.test.ts`
130
+ - Test (existing): `maxy-code/platform/ui/app/lib/__tests__/graph-labels.test.ts`
131
+
132
+ **Interfaces:**
133
+ - Consumes: `STATIC_TOP_LEVEL_LABELS` from Task 1.
134
+ - Produces: `GRAPH_LABEL_COLOURS.CashEntry === '#7D5A2B'`; `iconForLabel('CashEntry')` returns a non-null SVG string; `CashEntry` is a member of both `FILTER_TOP_LEVEL_LABELS` and `STATIC_TOP_LEVEL_LABELS`.
135
+
136
+ - [ ] **Step 1: Replace the dist symlink with a local build**
137
+
138
+ `dist` currently points at the parent checkout. Building through it would write to the shared checkout other sessions use.
139
+
140
+ ```bash
141
+ cd /Users/neo/getmaxy/maxy-code/.claude/worktrees/task-1819-top-level-label-allowlist
142
+ ls -ld maxy-code/platform/lib/graph-style/dist # confirm it is a symlink (leading 'l')
143
+ rm -f maxy-code/platform/lib/graph-style/dist
144
+ source ~/.nvm/nvm.sh && nvm use 22.22.0
145
+ cd maxy-code/platform
146
+ ./ui/node_modules/.bin/tsc -p lib/graph-style/tsconfig.json
147
+ ls -ld lib/graph-style/dist # now a real directory ('d')
148
+ ```
149
+
150
+ Expected: `tsc` exits 0 and `dist` is a real directory. Use `ui/node_modules/.bin/tsc` explicitly — the libs have no `package.json`, so a bare `npx tsc` resolves to an unrelated package.
151
+
152
+ - [ ] **Step 2: Write the failing test**
153
+
154
+ Add to `maxy-code/platform/lib/graph-style/src/__tests__/parity.test.ts`, inside the `palette invariants` describe block:
155
+
156
+ ```ts
157
+ it("registers CashEntry as its own hue, distinct from the invoice labels", () => {
158
+ expect(GRAPH_LABEL_COLOURS.CashEntry).toBe("#7D5A2B");
159
+ expect(GRAPH_LABEL_COLOURS.CashEntry).not.toBe(GRAPH_LABEL_COLOURS.Invoice);
160
+ expect(GRAPH_LABEL_COLOURS.CashEntry).not.toBe(GRAPH_LABEL_COLOURS.InboundInvoice);
161
+ });
162
+ ```
163
+
164
+ - [ ] **Step 3: Run it to verify it fails**
165
+
166
+ ```bash
167
+ cd maxy-code/platform/lib/graph-style
168
+ source ~/.nvm/nvm.sh && nvm use 22.22.0
169
+ ../../ui/node_modules/.bin/vitest run
170
+ ```
171
+
172
+ Expected: FAIL on the new test with `expected undefined to be '#7D5A2B'`. The `icons.test.ts` coverage test still passes at this point, because `CashEntry` is not yet in the colour table.
173
+
174
+ - [ ] **Step 4: Add the colour**
175
+
176
+ In `maxy-code/platform/lib/graph-style/src/index.ts`, append to the END of the `GRAPH_LABEL_COLOURS` object, after `Hypothesis: '#9A8C3E',` (line 147):
177
+
178
+ ```ts
179
+
180
+ // Ledger cash movement (schema-base.md, added by 7b225f814). One movement
181
+ // of money attached to no invoice — operator-entry with no parent to drill
182
+ // down from, so it is a top-level chip. Burnished olive-gold sits in the
183
+ // money register beside Invoice's brown without colliding with it.
184
+ //
185
+ // Deliberately appended at the END rather than beside the ledger family:
186
+ // SHAPE_BY_LABEL assigns shapes by index position in ALL_GRAPH_LABELS
187
+ // (this object's key order), so a mid-table insert would silently change
188
+ // the rendered shape of every label after it.
189
+ CashEntry: '#7D5A2B',
190
+ ```
191
+
192
+ - [ ] **Step 5: Run the tests to see the icon gate fail**
193
+
194
+ ```bash
195
+ cd maxy-code/platform/lib/graph-style
196
+ source ~/.nvm/nvm.sh && nvm use 22.22.0
197
+ ../../ui/node_modules/.bin/vitest run
198
+ ```
199
+
200
+ Expected: the new palette test now PASSES, and `icons.test.ts` now FAILS with `CashEntry` listed in the missing-glyph array. This is the coverage gate doing its job.
201
+
202
+ - [ ] **Step 6: Add the icon**
203
+
204
+ In the same file, append to the END of the `LABEL_ICONS` object (the Lucide `banknote` glyph):
205
+
206
+ ```ts
207
+ CashEntry: '<rect width="20" height="12" x="2" y="6" rx="2"></rect><circle cx="12" cy="12" r="2"></circle><path d="M6 12h.01"></path><path d="M18 12h.01"></path>',
208
+ ```
209
+
210
+ - [ ] **Step 7: Add the caption branches**
211
+
212
+ `CashEntry`'s properties are `accountId`, `entryId`, `direction`, `amount`, `date`, `description`. The generic caption fallthrough only checks `name`, `title`, `summary`, `givenName`, `subject`, `text`, so without a branch every node renders as the literal string `CashEntry`. Both caption functions carry per-label branches and both need one.
213
+
214
+ In `pickShortLabel`, after the `WhatsAppGroup` branch and before the `Message` branch:
215
+
216
+ ```ts
217
+ } else if (primaryLabel === 'CashEntry') {
218
+ const desc = typeof props.description === 'string' ? props.description : ''
219
+ if (desc.length > 0) {
220
+ return desc.length > 24 ? desc.slice(0, 24) + '…' : desc
221
+ }
222
+ ```
223
+
224
+ In `pickDisplayName`, add the matching untruncated branch in the same relative position:
225
+
226
+ ```ts
227
+ } else if (primaryLabel === 'CashEntry') {
228
+ const desc = typeof props.description === 'string' ? props.description : ''
229
+ if (desc.length > 0) return desc
230
+ ```
231
+
232
+ - [ ] **Step 8: Run the graph-style suite to verify it passes**
233
+
234
+ ```bash
235
+ cd maxy-code/platform/lib/graph-style
236
+ source ~/.nvm/nvm.sh && nvm use 22.22.0
237
+ ../../ui/node_modules/.bin/vitest run
238
+ ```
239
+
240
+ Expected: all tests pass, including the icon-coverage test and the hex-format invariant.
241
+
242
+ - [ ] **Step 9: Rebuild dist so the UI sees the new symbols**
243
+
244
+ ```bash
245
+ cd maxy-code/platform
246
+ source ~/.nvm/nvm.sh && nvm use 22.22.0
247
+ ./ui/node_modules/.bin/tsc -p lib/graph-style/tsconfig.json
248
+ ```
249
+
250
+ Expected: exit 0.
251
+
252
+ - [ ] **Step 10: Add `CashEntry` to both label sets**
253
+
254
+ In `maxy-code/platform/ui/app/lib/graph-labels.ts`, inside `FILTER_TOP_LEVEL_LABELS`, after `'InboundInvoice',` (line 166):
255
+
256
+ ```ts
257
+ 'CashEntry',
258
+ ```
259
+
260
+ In `maxy-code/platform/ui/server/lib/top-level-labels.ts`, inside `STATIC_TOP_LEVEL_LABELS`, after the `'InboundInvoice',` entry added in Task 1:
261
+
262
+ ```ts
263
+ // Ledger cash movement, declared in schema-base.md. Operator-entry with
264
+ // a natural key (accountId, entryId) and no parent label, so it is
265
+ // reachable only as a chip.
266
+ 'CashEntry',
267
+ ```
268
+
269
+ Both sets must change together — the deep-equals test from Task 1 fails if only one does. That failure is the guard working.
270
+
271
+ - [ ] **Step 11: Run the full UI graph-label surface**
272
+
273
+ ```bash
274
+ cd maxy-code/platform/ui
275
+ source ~/.nvm/nvm.sh && nvm use 22.22.0
276
+ npx vitest run server/lib/top-level-labels.test.ts \
277
+ server/routes/__tests__/graph-default-topLevel.test.ts \
278
+ app/lib/__tests__/graph-labels.test.ts \
279
+ app/data/__tests__/dynamic-chips.test.ts
280
+ ```
281
+
282
+ Expected: all four files pass. The hex-duplicate-rejection test in `graph-labels.test.ts` is the one that proves `#7D5A2B` collides with nothing.
283
+
284
+ - [ ] **Step 12: Commit**
285
+
286
+ ```bash
287
+ git add maxy-code/platform/lib/graph-style/src/index.ts \
288
+ maxy-code/platform/lib/graph-style/src/__tests__/parity.test.ts \
289
+ maxy-code/platform/ui/app/lib/graph-labels.ts \
290
+ maxy-code/platform/ui/server/lib/top-level-labels.ts
291
+ git commit -m "feat(graph): register CashEntry as a top-level label
292
+
293
+ CashEntry arrived in schema-base.md with 7b225f814 and was registered
294
+ nowhere, so /graph offered no chip for it. It is money attached to no
295
+ invoice and has no parent label, so unlike a child label it cannot be
296
+ reached by drilldown — without a chip it is unreachable except by search.
297
+
298
+ Six surfaces: colour, icon, both caption functions, the client chip
299
+ mirror, and the server static allowlist.
300
+
301
+ The colour is appended at the end of GRAPH_LABEL_COLOURS rather than
302
+ beside the ledger family on purpose. SHAPE_BY_LABEL assigns shapes by
303
+ index position in that object's key order, so a mid-table insert would
304
+ have silently changed the rendered shape of ~40 other labels.
305
+
306
+ Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
307
+ Session: 693bcfd0-f04e-49ed-8ebe-593e59be24c2"
308
+ ```
309
+
310
+ ---
311
+
312
+ ## Verification (after both tasks)
313
+
314
+ ```bash
315
+ cd maxy-code/platform/ui
316
+ source ~/.nvm/nvm.sh && nvm use 22.22.0
317
+ npx tsc --noEmit
318
+ npx vitest run
319
+ ```
320
+
321
+ Expected: `tsc` exits 0. The full suite has no failures attributable to these files. Compare any residual red against the parent checkout on `main` before treating it as caused by this diff.