toga-ai 1.0.654 → 1.0.656

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 (25) hide show
  1. package/knowledge/2.0/apps/_underscore/features/acl-permission-chain.md +13 -0
  2. package/knowledge/2.0/apps/_underscore/features/apirequest-json-content-type.md +28 -2
  3. package/knowledge/2.0/apps/toga-blox/INDEX.md +2 -1
  4. package/knowledge/2.0/apps/toga-blox/features/primary-table-templates.md +32 -1
  5. package/knowledge/2.0/apps/toga-blox/features/table.md +29 -1
  6. package/knowledge/2.0/apps/toga-blox/features/toaster.md +104 -0
  7. package/knowledge/2.0/apps/toga-blox/workflows/dynamic-publish-pipeline.md +63 -1
  8. package/knowledge/2.0/apps/toga2-commerce/INDEX.md +1 -1
  9. package/knowledge/2.0/apps/toga2-commerce/features/order-submit-sync-sequencing.md +15 -2
  10. package/knowledge/2.0/apps/toga2-commerce/workflows/amplify-build-and-deploy.md +50 -6
  11. package/knowledge/2.0/apps/toga2-supply/INDEX.md +1 -1
  12. package/knowledge/2.0/apps/toga2-supply/features/currency-amount-lines-editor.md +141 -2
  13. package/knowledge/2.0/apps/worker2/INDEX.md +1 -0
  14. package/knowledge/2.0/apps/worker2/features/creating-worker-actions.md +17 -2
  15. package/knowledge/2.0/apps/worker2/features/netsuite-opportunity-client-labels.md +138 -0
  16. package/knowledge/2.0/apps/worker2/features/netsuite-opportunity-sync.md +66 -7
  17. package/knowledge/2.0/apps/worker2/features/notification-email.md +19 -2
  18. package/knowledge/2.0/standards/frontend-deploy.md +8 -3
  19. package/knowledge/2.0/standards/frontend.md +29 -6
  20. package/knowledge/INDEX.md +2 -2
  21. package/knowledge/clients/quad/features/multi-currency-item-pricing.md +47 -3
  22. package/knowledge/clients/quad/profile.md +6 -0
  23. package/knowledge/sessions/2026-08-26-blox-toaster-peer-deps-apeterson.md +86 -0
  24. package/knowledge/standalone/apps/claude/workflows/mcp-tool-usage.md +19 -2
  25. package/package.json +1 -1
@@ -65,6 +65,13 @@ writable). Without it the field is rejected on write **and** is unreadable:
65
65
  VISIBILITY too.** Concrete symptom (TRUE-79191): `Measures.measureType` was registered but ungranted,
66
66
  so it came back absent and the frontend unit dropdowns were empty. When a field renders blank with no
67
67
  error, check for a missing `AclFieldPermissions` grant before suspecting the selector or the data.
68
+ - **⚠ Sibling columns of the SAME table routinely carry DIFFERENT role sets, so verify per field
69
+ before you add one to a `fields=` list — and verify as the LEAST-privileged role.** Concrete case
70
+ (`Client_Quad.Currencies`, 2026-08-26): `code` (1424) and `symbol` (1425) are granted to roles
71
+ 1/7/8/9, but `position` (1997) only to 7/8/9. Adding `currency.position` to an existing read would
72
+ have 403'd the **whole** request for every user holding only role 1 — while working perfectly for a
73
+ developer whose own account also carries role 7. **A dev/admin account hides this class of bug
74
+ completely**; a "just one more field" addition is a permission change, not a display change.
68
75
  - **`AclFieldPermissions` is `UNIQUE (recordFieldId, roleId)`** (Client blank DDL) — guard inserts
69
76
  with `NOT EXISTS`. For a **read-only, server-written** field (one populated by a `postPost`
70
77
  interceptor rather than the API caller), grant `isWritable = 0`.
@@ -403,6 +410,12 @@ hardcoded `Core.RecordFields` id literals instead of a subselect.
403
410
  and every repo is on the **same branch** so the generated model matches the DB.
404
411
 
405
412
  ## Change history
413
+ - 2026-08-26 - Added the **verify-per-sibling-field, verify-as-the-least-privileged-role** rule:
414
+ columns of the same table often carry different role sets, so adding one more field to a `fields=`
415
+ list is a permission change. `Client_Quad.Currencies` grants `code` (1424) and `symbol` (1425) to
416
+ roles 1/7/8/9 but `position` (1997) only to 7/8/9, so requesting `currency.position` would have
417
+ 403'd the whole read for role-1-only users while looking fine to a developer who also holds role 7 -
418
+ a dev/admin account hides this class of bug entirely. (bala)
406
419
  - 2026-08-26 - Added the **action-flag gate** (`Core.AclActions` + `Client_*.AclActionPermissions`),
407
420
  a third gate alongside record CRUD and record scripts: `Page.php` (~L1285-1302) defaults every
408
421
  action flag to `false` and only a matching `AclActionPermissions` row flips it true, so a missing
@@ -6,8 +6,8 @@ project: _Underscore
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-07-28
10
- owners: ["jcardinal"]
9
+ updated: 2026-08-26
10
+ owners: ["jcardinal", "ajean"]
11
11
  files:
12
12
  - _underscore/ApiRequest.php
13
13
  related:
@@ -74,7 +74,33 @@ case-insensitive scan of already-set headers, so a caller-supplied `Content-Type
74
74
  save) lives **inside `execute()`** and would affect every framework caller, so it is deferred
75
75
  pending architecture review. Do **not** work around it per-caller.
76
76
 
77
+ - **Hand-rolled `Logs.Api` inserts must set `isAuthRequest`, `instanceId` and `hostname` — they are
78
+ NOT NULL with no defaults.** `_ApiRequest`'s own logging sets all three (`ApiRequest.php:260-264`),
79
+ so a helper that writes its own log row while only setting `direction`/`source`/`method`/`route`
80
+ throws `Column 'X' cannot be null` on **every** insert. Because such helpers are usually a
81
+ *wrapper* around the real call, the throw propagates out of the wrapped call and, under a
82
+ `catch(Throwable)`, turns the whole feature into a **silent no-op that still reports success**.
83
+ Two worker2 handlers shipped with exactly this bug and one went unnoticed for months — see
84
+ [netsuite-opportunity-sync](../../worker2/features/netsuite-opportunity-sync.md#gotchas--known-issues).
85
+ Prefer letting `_ApiRequest` log rather than writing `Logs.Api` by hand.
86
+ - **⚠ Auto-logging persists the `Authorization` header in PLAINTEXT.** `ApiRequest.php:267` writes
87
+ the full request headers to `Logs.Api.requestHeaders`, so any component that sends a bearer
88
+ token/API key and does not `setLogging(false)` is depositing that credential into the logs DB on
89
+ every call. Known live instance: `_underscore/Component/Api/Clickup/Clickup.php` (which also
90
+ **hardcodes** its token in committed source — flagged for a rotate-and-move-to-config ticket; 11
91
+ worker2 files use it). When adding a new component, decide deliberately: log and accept the header
92
+ exposure, strip/redact the auth header before the call is logged, or `setLogging(false)`.
93
+ - **`Logs.Api` is 1.4M+ rows and `source` is NOT indexed.** Any diagnostic query must be bounded by
94
+ `dtStamp` (indexed) or it times out — `WHERE source = '…'` alone will not return.
95
+
77
96
  ## Change history
97
+ - 2026-08-26 — Documented the **manual-insert column contract** (`isAuthRequest`, `instanceId`,
98
+ `hostname` are NOT NULL with no defaults, and `_ApiRequest` sets them at `ApiRequest.php:260-264`),
99
+ after a hand-rolled `logged()` helper in two worker2 handlers threw on every insert and silently
100
+ no-op'd an entire feature behind a `catch(Throwable)`. Also recorded that auto-logging persists the
101
+ **`Authorization` header in plaintext** into `Logs.Api.requestHeaders` (`ApiRequest.php:267`) — the
102
+ reason `_Component_Api_Clickup`'s hardcoded token needs rotation — and that `Logs.Api.source` is
103
+ unindexed at 1.4M+ rows, so queries must be bounded by `dtStamp`. (ajean)
78
104
  - 2026-08-05 — Documented (no code change) that the `direction = 'OUT'` api-log row is
79
105
  **committed immediately** inside `execute()` (`transactionCommit(DB_CLIENT_LOGS)`), so it
80
106
  survives a later rollback and `Logs_<Client>.Api` is definitive evidence of whether an outbound
@@ -7,8 +7,9 @@
7
7
  | [AdvancedSelect (virtualized single/multi select)](features/advanced-select.md) | `AdvancedSelect<T>` is a **fully controlled, virtualized** single/multi select built from scratch (not react-select) on **`@tanstack/react-virtual`**, for large | toga-blox/src/components/AdvancedSelect/AdvancedSelect.tsx, toga-blox/src/components/AdvancedSelect/AdvancedSelect.types.ts, toga-blox/src/components/AdvancedSelect/AdvancedSelect.module.css |
8
8
  | [API client (axios wrapper, auth, table-data fetchers)](features/api-client.md) | `src/api/` is a thin **axios** wrapper that standardizes the **2.0 API envelope**, manages auth (Bearer + refresh), serializes complex query options, and provid | toga-blox/src/reactQuery/queryHelpers.ts, toga-blox/src/api/index.ts, toga-blox/src/api/axiosInstance.ts, toga-blox/src/api/apiFunctions.ts, toga-blox/src/api/auth.ts, toga-blox/src/api/genericApi.ts, toga-blox/src/api/types.ts, toga-blox/src/api/tableData |
9
9
  | [BaseInput (react-hook-form field factory)](features/base-input.md) | `BaseInput` is a **form-field factory** driven by react-hook-form. | toga-blox/src/components/BaseInput/BaseInput.tsx, toga-blox/src/components/BaseInput/BaseInput.types.ts, toga-blox/src/components/BaseInput/BaseInput.module.css, toga-blox/src/components/BaseInput/components |
10
- | [Primary Table templates (server/client, sizing, virtualization)](features/primary-table-templates.md) | `src/templates/PrimaryTable/` is the **production, wired-up table** built on the [Table component](table.md). | toga-blox/src/templates/PrimaryTable/PrimaryTable.tsx, toga-blox/src/templates/PrimaryTable/PrimaryTableServerTemplate.tsx, toga-blox/src/templates/PrimaryTable/PrimaryTableClientTemplate.tsx, toga-blox/src/templates/PrimaryTable/PrimaryTableHeaderCell.tsx, toga-blox/src/templates/PrimaryTable/PrimaryTableBodyCell.tsx, toga-blox/src/templates/PrimaryTable/PrimaryTableRow.tsx, toga-blox/src/templates/PrimaryTable/PrimaryTableExpandableRow.tsx, toga-blox/src/templates/PrimaryTable/types.ts |
10
+ | [Primary Table templates (server/client, sizing, virtualization)](features/primary-table-templates.md) | `src/templates/PrimaryTable/` is the **production, wired-up table** built on the [Table component](table.md). | toga-blox/src/components/Table/themeConfig/toga.module.css, toga-blox/src/templates/PrimaryTable/PrimaryTable.tsx, toga-blox/src/templates/PrimaryTable/PrimaryTableServerTemplate.tsx, toga-blox/src/templates/PrimaryTable/PrimaryTableClientTemplate.tsx, toga-blox/src/templates/PrimaryTable/PrimaryTableHeaderCell.tsx, toga-blox/src/templates/PrimaryTable/PrimaryTableBodyCell.tsx, toga-blox/src/templates/PrimaryTable/PrimaryTableRow.tsx, toga-blox/src/templates/PrimaryTable/PrimaryTableExpandableRow.tsx, toga-blox/src/templates/PrimaryTable/types.ts |
11
11
  | [TableRecordModal (record-detail modal shell)](features/table-record-modal.md) | `TableRecordModal` is a **generic, presentational modal shell** for showing a single table record (row) in detail — typically opened from a table row click. | toga-blox/src/components/TableRecordModal/TableRecordModal.tsx, toga-blox/src/components/TableRecordModal/index.ts, toga-blox/src/components/TableRecordModal/tableRecordModal.module.css |
12
12
  | [Table component (cells, action cells, filters & sorts, hooks, theming)](features/table.md) | The `Table` component (`src/components/Table/`) is the **TanStack Table v8** building block behind the [Primary Table templates](primary-table-templates.md). | toga-blox/src/components/Table/hooks/useFetchTablePageMeta.ts, toga-blox/src/api/types.ts, toga-blox/src/components/Table/index.ts, toga-blox/src/components/Table/types.ts, toga-blox/src/components/Table/utils/buildTanstackColumns.tsx, toga-blox/src/components/Table/utils/resolveCellType.tsx, toga-blox/src/components/Table/components/cellTypes, toga-blox/src/components/Table/components/actionCells, toga-blox/src/components/Table/components/columnFiltersAndSorts, toga-blox/src/components/Table/hooks, toga-blox/src/components/Table/themeConfig |
13
13
  | [Talos AI-Assistant Component (launcher + slide-out chat panel)](features/talos-assistant.md) | `Talos` is a **shared, pure-UI** AI-assistant component in `@agilant/toga-blox`: a header launcher button (`TalosLauncher`) plus a slide-out chat panel (`TalosP | toga-blox/src/components/Talos/TalosLauncher.tsx, toga-blox/src/components/Talos/TalosPanel.tsx, toga-blox/src/components/Talos/TalosMessage.tsx, toga-blox/src/components/Talos/types.ts, toga-blox/src/components/Talos/theme.ts, toga-blox/src/components/Talos/helpers.tsx, toga-blox/src/components/Talos/stub.ts, toga-blox/src/components/Talos/Talos.module.css, toga-blox/src/components/Talos/index.ts, toga-blox/src/components/index.ts |
14
+ | [Toaster — host-token styling contract](features/toaster.md) | The blox `Toaster` is a CSS-Module component whose every visual property reads a `--toaster-*` custom property supplied by the **host app**. | toga-blox/src/components/Toaster/Toaster.module.css, toga-blox/src/components/Toaster/Toaster.tsx, toga-blox/src/components/Toaster/ToasterContext.tsx, toga2-commerce/src/styles/index.css, toga2-commerce/src/components/Toasters/ToasterList.tsx |
14
15
  | [Dynamic npm Publish Pipeline (branch → channel)](workflows/dynamic-publish-pipeline.md) | How `@agilant/toga-blox` (checkout folder `toga-blox-npm`, registry repo key `toga-blox`) publishes a per-environment npm **channel** (dist-tag) from a `_<mode> | toga-blox/.github/workflows/publish.yml, toga-blox/package.json, toga-blox/src/utils/getFontAwesomeIcon.tsx |
@@ -6,9 +6,10 @@ project: TOGa Blox
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-08-17
9
+ updated: 2026-08-26
10
10
  owners: [apeterson]
11
11
  files:
12
+ - toga-blox/src/components/Table/themeConfig/toga.module.css
12
13
  - toga-blox/src/templates/PrimaryTable/PrimaryTable.tsx
13
14
  - toga-blox/src/templates/PrimaryTable/PrimaryTableServerTemplate.tsx
14
15
  - toga-blox/src/templates/PrimaryTable/PrimaryTableClientTemplate.tsx
@@ -82,8 +83,29 @@ spacer rows computed from the virtualizer item `.start`/`.end` minus `scrollMarg
82
83
  `supply-modal-table` skin **disables virtualization** (renders all rows, min-height 300px).
83
84
  Sticky columns use a `--sticky-offset` CSS variable summed from neighboring column widths.
84
85
 
86
+ ## The "Show more" hover affordance is CSS-driven, not JS-driven
87
+
88
+ A truncated body cell reveals its "Show more" toggle **on hover via CSS only**:
89
+ `.bodyCell:hover .showMoreWrapper:not(.expandedWrapper) button` in
90
+ `themeConfig/toga.module.css` (plus a `:focus-visible` rule so keyboard users can reach it).
91
+ `Cellstyles.module.css` already shipped `.toggle { opacity: 0 }` + a hover rule — the CSS
92
+ hover-reveal was the original design. `PrimaryTableBodyCell` must **not** inline-set the collapsed
93
+ `opacity`; inline styles beat the cascade and hand visibility back to React state. Layout props
94
+ (flex/sizing) stay inline; visibility does not. The React `isTruncated` state is now for
95
+ **capability detection only** (does this cell need a toggle at all), and `clearTruncationHint`
96
+ runs unconditionally — it no longer no-ops while `isExpanded`.
97
+
85
98
  ## Gotchas
86
99
 
100
+ - **Never gate a hover affordance on a JS `mouseleave` inside a virtualized table.** `mouseleave`
101
+ is not guaranteed to fire: a virtualized row can translate out from under a stationary cursor on
102
+ wheel-scroll, and any early-return in the clear handler strands the "hovered" flag set. The toggle
103
+ then stays visible on cells the mouse is nowhere near. Drive visibility from CSS `:hover`, which
104
+ **cannot** get stuck, and keep JS state for capability detection.
105
+ - **Residual (accepted):** a stale `isTruncated` still keeps the flex wrapper mounted, so that one
106
+ cell's text ellipsizes marginally earlier until the next `mouseleave`. Cosmetically invisible;
107
+ clearing it properly would need a per-cell scroll listener.
108
+
87
109
  - Frozen widths measure only **mounted** rows; virtualized tables size from the first paint set.
88
110
  - **Header labels must never abbreviate or overlap.** The full header width is a hard floor
89
111
  (above `maxColumnWidth`, `minColumnWidth`, and pinned `columnWidths`). Measure header width
@@ -98,6 +120,15 @@ Sticky columns use a `--sticky-offset` CSS variable summed from neighboring colu
98
120
  not the column set.
99
121
 
100
122
  ## Change history
123
+ - 2026-08-26 — Fixed: the "Show more" toggle got stuck visible on cells the mouse was not hovering.
124
+ `.toggle` already had `opacity: 0` + a CSS hover rule, but `PrimaryTableBodyCell` inline-set
125
+ `opacity: 1` unconditionally (inline beats the cascade), so visibility depended entirely on the
126
+ `isTruncated` state set on `mouseenter`/cleared on `mouseleave` — and `mouseleave` is not
127
+ guaranteed to fire (virtualized row translating out from under a stationary cursor on wheel-scroll;
128
+ `clearTruncationHint` no-opping while `isExpanded`). Visibility is now CSS `:hover`-driven
129
+ (`.bodyCell:hover .showMoreWrapper:not(.expandedWrapper) button` + `:focus-visible`), the collapsed
130
+ inline `opacity` was removed, and the `isExpanded` guard dropped from `clearTruncationHint`.
131
+ Shipped in `1.0.334-sandbox-client.136`. (apeterson)
101
132
  - 2026-08-17 — Fixed clipped/abbreviated headers: full header width is now a hard floor for every
102
133
  column (not capped by max-width, not overridden by `minColumnWidth`, applied even to pinned
103
134
  `columnWidths` — the old `return def.size` bypass left pinned columns clipped). Added a
@@ -6,7 +6,7 @@ project: TOGa Blox
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-08-25
9
+ updated: 2026-08-26
10
10
  owners: [apeterson]
11
11
  files:
12
12
  - toga-blox/src/components/Table/hooks/useFetchTablePageMeta.ts
@@ -60,6 +60,15 @@ alignment (CVA `cellWrapperVariants`), expandable, and copyable behavior. Empty/
60
60
  render `EmptyCell`. If `imageUrlField` is set, the URL is resolved separately and passed to
61
61
  `ImageCell`.
62
62
 
63
+ **The expandable wrap is destructive, and is now denied for status types.** When the table-meta
64
+ flag `isExpandableCell` is set on a field, the expandable branch does **not** wrap the
65
+ already-rendered `content` — it discards it and re-renders the **raw `value`** inside
66
+ `<ExpandableCell maxLength={40} expandable>`. Any rich cell type loses its component that way
67
+ (a status column rendered as truncated text with a "Show more" toggle instead of a badge).
68
+ `NEVER_EXPANDABLE_TYPES` (`STATUS`, `STATUS_BADGE`) now gates that branch, so status columns keep
69
+ their badge regardless of the meta flag. Fixing it in the renderer covers every client and
70
+ environment instead of chasing per-client `isExpandableCell` data rows.
71
+
63
72
  ## Cell types (`components/cellTypes/`)
64
73
 
65
74
  | Component | Type | Renders |
@@ -153,6 +162,16 @@ layer and emits it — see
153
162
 
154
163
  ## Gotchas
155
164
 
165
+ - **`isExpandableCell` still clobbers every other rich cell type.** Only `STATUS`/`STATUS_BADGE`
166
+ are protected today. `URGENCY`, `BOOLEAN`, `CURRENCY`, `DATE`, `AVATAR` and `CLIENT` carry the
167
+ **same latent defect** — set the flag on one of those fields and the cell degrades to raw
168
+ truncated text. The fuller fix is inverting the deny-list into an **allowlist** (expandable only
169
+ for free-text/default cells); deliberately not done yet.
170
+ - **A cell-rendering difference between local and a deployed environment is usually DB data, not
171
+ code.** `isExpandableCell` is a per-field flag in the **server's table meta**, so the same blox
172
+ build renders differently against two databases. Diff the branches over the cell-rendering files
173
+ **first** (`git diff <feature> origin/_sandbox-client -- src/components/Table/...`); if that comes
174
+ back empty, stop reading code and go look at the table-meta rows.
156
175
  - `MIN_COLUMN_WIDTH = 120` is the shrink floor only for columns with **no** explicit width.
157
176
  - **Never truncate header labels.** `truncateCells` (`.truncateCells .headerCellLabel` in
158
177
  `toga.module.css`) is for **body** values only; it must apply only `white-space: nowrap` to
@@ -198,6 +217,15 @@ layer and emits it — see
198
217
  requires `npm run build` before it takes effect at runtime.
199
218
 
200
219
  ## Change history
220
+ - 2026-08-26 — Fixed: status columns rendered as truncated text with a "Show more" toggle instead of
221
+ a badge. Root cause was in `resolveCellType` — the `isExpandableCell` branch **discards** the
222
+ rendered `content` and re-renders the raw `value` in `ExpandableCell`. Added
223
+ `NEVER_EXPANDABLE_TYPES` (`STATUS`, `STATUS_BADGE`) to gate it. Recorded that the same defect is
224
+ latent for `URGENCY`/`BOOLEAN`/`CURRENCY`/`DATE`/`AVATAR`/`CLIENT` (an allowlist is the fuller
225
+ fix, not done). Also recorded the debugging lesson: the "works locally, broken on deployed
226
+ `_sandbox-client`" symptom was **not** a code difference — the branch diff over the cell-rendering
227
+ files was empty; `isExpandableCell` was set in the sandbox-client DB and unset locally. Shipped in
228
+ `1.0.334-sandbox-client.136`. (apeterson)
201
229
  - 2026-08-25 — `useFetchTablePageMeta` now prefers **server-supplied `filterOptions`** and skips the
202
230
  `recordRoute` fetch for those fields (query list + index lookup share one `needsFetchedOptions`
203
231
  predicate so they can't skew); `filterOptions[].uuid` made optional and `surfaceSlug` declared on
@@ -0,0 +1,104 @@
1
+ ---
2
+ title: Toaster — host-token styling contract
3
+ framework: "2.0"
4
+ repo: toga-blox
5
+ project: TOGa Blox
6
+ client: shared
7
+ type: feature
8
+ status: active
9
+ updated: 2026-08-26
10
+ owners: [apeterson]
11
+ files:
12
+ - toga-blox/src/components/Toaster/Toaster.module.css
13
+ - toga-blox/src/components/Toaster/Toaster.tsx
14
+ - toga-blox/src/components/Toaster/ToasterContext.tsx
15
+ - toga2-commerce/src/styles/index.css
16
+ - toga2-commerce/src/components/Toasters/ToasterList.tsx
17
+ related:
18
+ - ../architecture.md
19
+ - ../../../standards/frontend.md
20
+ - ../../toga2-commerce/architecture.md
21
+ ---
22
+
23
+ ## Summary
24
+
25
+ The blox `Toaster` is a CSS-Module component whose every visual property reads a
26
+ `--toaster-*` custom property supplied by the **host app**. It is the clearest working example of
27
+ the blox styling contract described in `frontend.md` §13(e) — and of that contract's failure mode:
28
+ a host that defines **zero** tokens gets a component that renders **unstyled**, because every
29
+ declaration is invalid-at-computed-value-time and dropped.
30
+
31
+ As of 2026-08-26 the component ships **default values via `var(--token, fallback)`**, so it renders
32
+ fully styled with no host configuration, while any host-defined `--toaster-*` token still wins.
33
+ The blox-side changes are **merged and published** as of 2026-08-26 in
34
+ `@agilant/toga-blox@1.0.334-sandbox-client.136` (dist-tag `sandbox-client`). The commerce-side
35
+ rewiring (`TRUE-80707`) is still a separate branch — verify that half against the installed app.
36
+
37
+ ## How it works
38
+
39
+ ### Token layer with fallbacks (the pattern to copy)
40
+
41
+ Every declaration in `Toaster.module.css` is written `var(--toaster-x, <literal default>)`. This was
42
+ chosen over adding a `:root` token block inside blox because:
43
+
44
+ - blox ships **no** `:root` token block anywhere (§13e), and
45
+ - `dist/main.css` is **uncompiled** and must not be imported by consumers (§13f),
46
+
47
+ so a `:root` block would need a stylesheet import that no consumer makes. Fallbacks need nothing
48
+ imported. **This is the generalisable rule for any blox component that reads host tokens: ship
49
+ `var(--token, fallback)`, never a bare `var(--token)`.**
50
+
51
+ ### Do NOT declare a property on an element that also receives a host override class
52
+
53
+ `.prefixIcon` and `.closeBtn` deliberately declare **no `color`**. The host's `iconColor` /
54
+ `closeIconColor` classes land on those same elements at **equal specificity**, so a `color`
55
+ declared in the module would be resolved by **stylesheet source order** and could silently beat the
56
+ host's class (supply's mint/crimson icons losing to a grey default). They inherit from `.base`
57
+ instead, which any host class reliably overrides. In-code comments record this so it is not
58
+ "helpfully" re-added.
59
+
60
+ ### Host wiring — the variant-remap mechanism
61
+
62
+ The supported way for a host to express toast variants is to define the `--toaster-*` layer once,
63
+ then have each variant class **remap only the `--toaster-default-*` tokens** that blox's `.base`
64
+ already reads. Do **not** style toasts with utility classes on a wrapper — Tailwind utilities and
65
+ blox's `.base` land at equal specificity and compete unpredictably.
66
+
67
+ ```css
68
+ :root { --toaster-padding: 1.25rem; /* … full token set … */ }
69
+ .commerceToaster--error { --toaster-default-bg: …; --toaster-default-text: …; }
70
+ ```
71
+
72
+ `toga25-supply` defines the full set (~33 tokens) in `src/themeConfig.json`; `toga2-commerce` now
73
+ defines it in `src/styles/index.css` with `.commerceToaster--{success,error,restricted,default}`
74
+ variant classes consumed by `ToasterList.tsx`. Commerce's result was verified by `tsc -b` / `vite
75
+ build` and by inspecting the emitted CSS for the tokens and all four variant classes — **not
76
+ visually in a browser**.
77
+
78
+ ## Gotchas
79
+
80
+ - **A missing `var()` wrapper fails silently.** Two declarations read `min-width: (--toaster-min-width)`
81
+ / `max-width: (--toaster-max-width)` — no `var()`, so the parser dropped both. `toga25-supply`
82
+ masked this by re-declaring `min-width` on `.supplyToaster`; commerce had nothing to mask it, which
83
+ is how it surfaced. A host override can hide a blox CSS bug indefinitely.
84
+ - **`border-width` + `border-color` with no `border-style` renders no border at all.** `.base`
85
+ previously set the first two only; `border-style` (plus `border-radius`, `font-family`,
86
+ `font-size`, `margin-block`) has been added.
87
+ - **Order placement in commerce does not raise a success toast** — do not use it to test toast
88
+ styling. See `../../toga2-commerce/features/order-submit-sync-sequencing.md`.
89
+ - Commerce's `restricted` (orange) variant is commerce-only; supply has no equivalent. Commerce's
90
+ palette has no `crimson-600`, so supply's error icon color maps to `crimson-500`.
91
+
92
+ ## Change history
93
+
94
+ - 2026-08-26 — The blox-side fallback work above was committed, merged to `_sandbox-client` and
95
+ **published** as `1.0.334-sandbox-client.136`; superseded the earlier "working-tree, not yet
96
+ merged or published" caveat. (apeterson)
97
+ - 2026-08-26 — Toaster now ships **default styling** via `var(--token, fallback)` on every custom
98
+ property (renders styled with zero host config; host tokens still win) and gained the missing
99
+ `border-style`/`border-radius`/`font-family`/`font-size`/`margin-block` on `.base`. Fixed two
100
+ declarations missing their `var()` wrapper (`min-width`/`max-width`), which supply had been
101
+ masking. Recorded the deliberate **no `color` on `.prefixIcon`/`.closeBtn`** decision (equal
102
+ specificity with the host's `iconColor`/`closeIconColor` classes). `toga2-commerce` rewired to
103
+ supply's variant-remap mechanism and given the full `--toaster-*` token layer, replacing the
104
+ competing Tailwind-utility styling. (apeterson)
@@ -6,7 +6,7 @@ project: TOGa Blox
6
6
  client: shared
7
7
  type: workflow
8
8
  status: active
9
- updated: 2026-08-04
9
+ updated: 2026-08-26
10
10
  owners: [jcardinal, apeterson]
11
11
  files:
12
12
  - toga-blox/.github/workflows/publish.yml
@@ -93,6 +93,52 @@ environment needs its own maintained `_<mode>` branch in `toga-blox-npm`.
93
93
  copy on the pushed branch, a new `_<mode>` channel will **not** publish unless the branch you push
94
94
  carries the wildcard-trigger version. When standing up a new channel, merge from a branch that has
95
95
  the dynamic `publish.yml` (or update it first).
96
+ - **Do NOT judge a blox branch's staleness by its behind-count.** `feature-new-table` reports
97
+ **"0 ahead / 47 behind"** `_sandbox-client` and `git merge-base --is-ancestor` says it is fully
98
+ contained — which reads as "stale, already merged, wrong base". **It is not.** Those 47 commits are
99
+ almost entirely `Merge branch 'feature-new-table' into _sandbox-client` and
100
+ `chore: bump version to 1.0.3xx` — **release plumbing generated ON `_sandbox-client` by the publish
101
+ flow and never merged back**. The actual source difference is **2 files** (`src/global.css`,
102
+ `src/index.ts`); the rest of the 334-file diff is `.claude/knowledge/` docs and `publish.yml`.
103
+ `feature-new-table` is the **active development branch** (tip 2026-08-24, `feat: prefer
104
+ server-supplied filter options in table meta`) and is the correct base. Verified 2026-08-26.
105
+ Corollary: the `publish.yml` divergence noted above is a **non-issue for publishing**, because
106
+ Actions runs the workflow on the **pushed** branch (`_sandbox-client`), which carries the dynamic
107
+ `_*` trigger.
108
+ - **A declared peer can be phantom — check before working around it.** Verified 2026-08-26:
109
+ `react-router-dom` appeared in blox's `peerDependencies` but only three files referenced it, two of
110
+ them tests; the single production reference was a **dead `import { Link }`** on line 1 of
111
+ `src/components/old/BaseButton/BaseButton.tsx` (the component renders an injected `linkComponent`
112
+ prop instead). The peer declaration and the dead import were removed and are **published** as of
113
+ 2026-08-26 in `1.0.334-sandbox-client.136`; `react-router-dom` stays a
114
+ **devDependency** (`^6.30.1`) for the tests' `MemoryRouter`. Verified clean build, zero
115
+ `react-router-dom` references in `dist/`, and vitest identical to baseline. This peer was the
116
+ stated reason consumers pass `--legacy-peer-deps` against a router-7 app.
117
+ - **A feature branch that never touches the version line merges without a version conflict —
118
+ and that is why the bump has to happen afterwards.** Observed 2026-08-26: `feature-new-table` sat
119
+ at base `1.0.322` while `_sandbox-client` was at `1.0.332`. The merge auto-resolved the `version`
120
+ line to `1.0.332` with **no conflict**, because only `_sandbox-client` had ever edited it (the
121
+ "47 behind" commits are that same release plumbing — see the gotcha above). The bump to `1.0.333`
122
+ was then made **on `_sandbox-client`**, at the developer's explicit direction. That **deviates
123
+ from the `deploy-sandbox-client` skill's "never commit the bump directly to `_sandbox-client`"
124
+ rule.** It was safe *only* because the feature branch does not carry the version line, so nothing
125
+ could be clobbered — **record this as a one-off, not a new default.** CI then published base+1 →
126
+ `1.0.334-sandbox-client.136`.
127
+ - **`gh` is not installed on every dev machine.** The skill's `gh run watch` monitoring step simply
128
+ does not work there. Fall back to polling the registry:
129
+ `npm view @agilant/toga-blox@sandbox-client version` (or `npm dist-tag ls @agilant/toga-blox`)
130
+ until the new version appears — the registry is the authoritative confirmation anyway.
131
+ - **Consuming apps pin exactly, so a publish is only half the deploy.** After
132
+ `1.0.334-sandbox-client.136` shipped, `toga25-supply` on `_sandbox-client` was still pinned to
133
+ `1.0.333-sandbox-client.134` and needed a pin bump + reinstall. Likewise the feature branch stays
134
+ at its old base version after the bump lands on `_sandbox-client` — expect the two to be out of
135
+ step and don't read it as a problem.
136
+ - **⚠ Credentials have been found in the local git remote URL.** Verified 2026-08-26: the `origin`
137
+ remote for the `toga-blox-npm` checkout had a **GitHub PAT embedded in plaintext in the URL**
138
+ (visible to anything that runs `git remote get-url origin`, and to any tool that reads
139
+ `.git/config`). Check for this and re-point the remote at SSH or a credential helper; treat any
140
+ token found this way as compromised and rotate it. This is the local-config sibling of the
141
+ committed-`.npmrc` violation already recorded in `../../../standards/frontend.md`.
96
142
  - **FontAwesome v7 `style`-prop TS2322** (fixed 2026-07-21 in `getFontAwesomeIcon.tsx`, and a
97
143
  reusable pattern for any consumer). FA v7 types the `FontAwesomeIcon` `style` prop as
98
144
  `CSSProperties & CSSVariables`, where `CSSVariables` requires a `--fa-*` custom-property index
@@ -122,6 +168,22 @@ environment needs its own maintained `_<mode>` branch in `toga-blox-npm`.
122
168
  the pattern the consuming apps should follow (see the commerce workflow's secret-hygiene note).
123
169
 
124
170
  ## Change history
171
+ - 2026-08-26 — Deployed `1.0.334-sandbox-client.136` (`feature-new-table` → `_sandbox-client`, 6
172
+ files, no conflicts) and recorded three workflow gotchas from it: (1) a feature branch that never
173
+ touches the `version` line merges without a version conflict, which is why the bump lands on
174
+ `_sandbox-client` afterwards — a documented **deviation** from the `deploy-sandbox-client` skill's
175
+ "never bump on `_sandbox-client`" rule, safe here only because of that, not a new default;
176
+ (2) `gh` is not installed on every machine, so verify the publish by polling
177
+ `npm view @agilant/toga-blox@sandbox-client version` instead of `gh run watch`; (3) consuming apps
178
+ pin exactly and need a separate pin bump + reinstall. Also flagged that a **GitHub PAT was found
179
+ in plaintext in the local `origin` remote URL** (rotate + re-point at SSH/credential helper), and
180
+ marked the phantom `react-router-dom` peer removal as merged and published. (apeterson)
181
+ - 2026-08-26 — Corrected the branch-topology misreading: `feature-new-table`'s "0 ahead / 47 behind"
182
+ is release plumbing generated on `_sandbox-client`, not staleness — it remains the active dev
183
+ branch and correct base (real source delta: 2 files). Noted the `publish.yml` divergence is a
184
+ non-issue because Actions runs the pushed branch's copy. Removed the **phantom
185
+ `react-router-dom` peer** (its only production reference was a dead `Link` import in
186
+ `old/BaseButton`); it is now a devDependency for tests only. Working-tree, uncommitted. (apeterson)
125
187
  - 2026-08-04 — Recorded the prod/beta `.scss`-only build gotcha: the `_production`/`_beta`
126
188
  `build` copies only `src/**/*.scss`, so a component shipped with a plain `.css` + matching
127
189
  `import "./X.css"` publishes JS referencing a stylesheet absent from the tarball, breaking
@@ -16,6 +16,6 @@
16
16
  | [Multi-Tenant Resolution & Theming](features/multi-tenant-theming.md) | `toga2-commerce` serves multiple clients from one codebase. | src/themeConfig/themes.json, src/themeConfig/ThemeContext.tsx, src/themeConfig/types.ts, src/components/ThemeSwitcher/ThemeSwitcher.tsx, src/components/AuthLayout/AuthLayout.tsx, src/api/axiosInstance.ts, src/contexts/AuthContext.tsx, tailwind.config.js |
17
17
  | [Order-submit sync sequencing (useSubmitOrder) — why these calls must not run in parallel](features/order-submit-sync-sequencing.md) | Submitting an order from the cart fires **two independent sync routines** — one for the sales-order header (`syncSalesOrderData`) and one for the line items (`s | toga2-commerce/src/pages/OrderDetails/hooks/useSubmitOrder.ts, toga2-commerce/src/api/syncSalesOrdersDataFromLocalStorageCartToApi.ts, toga2-commerce/src/api/syncSalesOrderItemsFromLocalStorageCartToApi.ts |
18
18
  | [Config-Driven Shipping Cost Waiver (Standard Ground free for computer kits)](features/shipping-cost-waiver-gating.md) | On the toga2-commerce **Cart** page, a shipping option's **cost** can be waived by config using the same `PrimaryItemShippingRule` vocabulary that drives expedi | toga2-commerce/src/pages/Cart/helpers/shippingOptionGates.ts, toga2-commerce/src/pages/Cart/viewModel/FIELDS/shared/shippingOptionGates.ts, toga2-commerce/src/pages/Cart/CartPage.tsx |
19
- | [AWS Amplify Build & Deploy (non-prod environments)](workflows/amplify-build-and-deploy.md) | How `toga2-commerce` (React + Vite, "commerce2-react") builds and deploys on **AWS Amplify**. | toga2-commerce/amplify.yml, toga2-commerce/.gitattributes, toga2-commerce/package.json, toga2-commerce/.github/workflows/sync-stage-environments.yml |
19
+ | [AWS Amplify Build & Deploy (non-prod environments)](workflows/amplify-build-and-deploy.md) | How `toga2-commerce` (React + Vite, "commerce2-react") builds and deploys on **AWS Amplify**. | toga2-commerce/amplify.yml, toga2-commerce/.gitattributes, toga2-commerce/package.json, toga2-commerce/.npmrc, toga2-commerce/vite.config.ts, toga2-commerce/.github/workflows/sync-stage-environments.yml |
20
20
  | [Cart e2e — Cypress conventions & harness (toga2-commerce)](workflows/cypress-testing.md) | The Cypress **e2e** convention set for `toga2-commerce`, and the first **active** e2e coverage for the **Cart** page (`cartV2.cy.ts`, slice 1 — 12 tests, verifi | toga2-commerce/cypress/e2e/cartPage/cartV2.cy.ts, toga2-commerce/cypress/fixtures/cart/fetchSingleUserAdmin.json, toga2-commerce/cypress/fixtures/cart/fetchLocations.json, toga2-commerce/cypress/fixtures/cart/fetchUserShippingMethods.json, toga2-commerce/cypress/support/commands.ts, toga2-commerce/cypress/support/e2e.ts, toga2-commerce/src/pages/Cart/CartPage.tsx, toga2-commerce/src/pages/Cart/view/cartForm/CartForm.tsx, toga2-commerce/src/pages/Cart/view/cartForm/CartFormSection.tsx, toga2-commerce/src/pages/Cart/view/cartTable/CartContentsTable.tsx, toga2-commerce/src/pages/Cart/view/cartTable/CartTableItem.tsx, toga2-commerce/src/components/Inputs/AdvancedInput.tsx, toga2-commerce/src/components/BaseButton/BaseButton.tsx |
21
21
  | [Diagnosing ERR_HTTP2_PROTOCOL_ERROR (one client fails, everyone else is fine)](workflows/http2-protocol-error-diagnosis.md) | When a Chromium browser (Chrome / Edge) shows **`ERR_HTTP2_PROTOCOL_ERROR`** loading a `*.togacommerce.com` tenant for **one client/network but works for the TO | |
@@ -6,8 +6,8 @@ project: TOGa Commerce
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-08-14
10
- owners: ["bala"]
9
+ updated: 2026-08-26
10
+ owners: ["bala", "apeterson"]
11
11
  files:
12
12
  - toga2-commerce/src/pages/OrderDetails/hooks/useSubmitOrder.ts
13
13
  - toga2-commerce/src/api/syncSalesOrdersDataFromLocalStorageCartToApi.ts
@@ -134,9 +134,22 @@ Three changes, in `toga2-commerce`:
134
134
  - **⚠ Omitting a line from the rebuilt cart DELETES it from a placed order.** `processItems` with
135
135
  `getDeleteItems = true` derives the delete set by difference, so "don't re-add this one" and
136
136
  "destroy this one" are the same instruction on this path.
137
+ - **There is NO success toaster on order placement — by design, not a bug.** `useSubmitOrder` calls
138
+ `addToaster` **only in its `catch` block** (`status: 'error'`). Both success paths navigate away
139
+ before anything could render: cart → `createNewSalesOrderSubmit()` →
140
+ `navigate("/order-details?uuid=…&type=orderPlaced")` (no `addToaster` anywhere in it); edit-order →
141
+ `window.location.href = getSupplyRedirectLink(orderUuid)`. **Consequence for debugging: placing an
142
+ order is not a valid way to test toaster styling.** Use a path that stays mounted — add/edit
143
+ shipping address (Cart or Account), Account → My Settings, or Cart → add new user; for the error
144
+ variant, force a submit failure to hit the catch block. See
145
+ [blox Toaster](../../toga-blox/features/toaster.md).
137
146
 
138
147
  ## Change history
139
148
 
149
+ - 2026-08-26 — Recorded that order placement raises **no success toaster by design** (`addToaster`
150
+ is only in the `catch`; both success paths navigate away), and listed the mounted-path
151
+ alternatives for testing toaster styling. (apeterson)
152
+
140
153
  - 2026-08-14 — Recorded **how order lines are actually written**, learned while adding a
141
154
  server-side order guard: the header sync `delete`s `salesOrderItems` from the edit `PUT` (line
142
155
  20), and lines are written **one request at a time** — new lines via the nested
@@ -6,16 +6,19 @@ project: TOGa Commerce
6
6
  client: shared
7
7
  type: workflow
8
8
  status: active
9
- updated: 2026-07-21
10
- owners: ["jcardinal"]
9
+ updated: 2026-08-26
10
+ owners: ["jcardinal", "apeterson"]
11
11
  files:
12
12
  - toga2-commerce/amplify.yml
13
13
  - toga2-commerce/.gitattributes
14
14
  - toga2-commerce/package.json
15
+ - toga2-commerce/.npmrc
16
+ - toga2-commerce/vite.config.ts
15
17
  - toga2-commerce/.github/workflows/sync-stage-environments.yml
16
18
  related:
17
19
  - ../../toga2-supply/workflows/amplify-build-and-deploy.md
18
20
  - ../../toga-blox/workflows/dynamic-publish-pipeline.md
21
+ - ../../../standards/frontend.md
19
22
  ---
20
23
 
21
24
  ## Summary
@@ -69,6 +72,10 @@ full cross-repo publish-then-build model. **The channel must exist before the ap
69
72
 
70
73
  ## Edge cases & escalation
71
74
 
75
+ > The 2026-08-26 commerce-side fixes below (`.npmrc` flag, added peers, `resolve.dedupe`, the
76
+ > `--toaster-*` token layer, the `ToasterList` rewiring) are **working-tree on branch `TRUE-80707`** —
77
+ > uncommitted, unmerged, and not in any deployed build.
78
+
72
79
  - **All the toga2-supply gotchas apply** (console build spec overriding repo `amplify.yml`;
73
80
  CRLF breaking block-scalar parsing; Vite silently falling back to `.env`/beta when a mode's env
74
81
  file is missing). See the related doc.
@@ -77,14 +84,44 @@ full cross-repo publish-then-build model. **The channel must exist before the ap
77
84
  only triggers on branches listed in `on.push.branches` and only tags branches with an explicit
78
85
  `elif` case — creating the branch alone does nothing; the workflow file must be present on that
79
86
  branch (GitHub Actions runs the workflow version on the pushed branch).
80
- - **`--legacy-peer-deps` is required** because blox declares `react-router-dom@^6` as a peer while
87
+ - **`--legacy-peer-deps` is required** because blox declared `react-router-dom@^6` as a peer while
81
88
  commerce uses `react-router-dom@7` (npm 7+ `ERESOLVE` otherwise). All non-prod build scripts use it.
89
+ (That peer was **phantom** and was removed from blox on 2026-08-26 — see the blox publish-pipeline
90
+ doc — but the flag stays until a build without it is proven.)
91
+ - **When one app installs a shared lib and a sibling app does not, compare `.npmrc` BEFORE touching
92
+ peer ranges.** A local `npm i` in commerce failed `ERESOLVE` on blox's router peer while
93
+ `toga25-supply` installed cleanly against the **same** blox version and the **same** router major.
94
+ The difference was not the peer range: supply carries `legacy-peer-deps=true` in its committed
95
+ `.npmrc` and commerce did not. Fix was adding `legacy-peer-deps=true` to commerce's `.npmrc` — a
96
+ tracked file, so it also reaches the Amplify build (the amplify.yml flag alone does not cover a
97
+ developer's local install).
82
98
  - **`--legacy-peer-deps` disables npm's peer auto-install**, so any blox peer that is NOT in
83
99
  commerce's own `dependencies` and NOT in blox's `dependencies` must be added explicitly, or Vite/
84
100
  Rollup fails with `failed to resolve import "<pkg>"`. Concretely, commerce had to add the table
85
- peers: `@tanstack/react-table@^8`, `react-table@^7.8.0`, `react-table-sticky@^1.1.3`. Check
86
- `npm view @agilant/toga-blox@<tag> peerDependencies` against commerce deps when a resolve error
87
- appears.
101
+ peers: `@tanstack/react-table@^8`, `react-table@^7.8.0`, `react-table-sticky@^1.1.3`, and on
102
+ 2026-08-26 `@fortawesome/free-solid-svg-icons@^6.7.2` + `react-multi-select-component@^4.3.4`.
103
+ Check `npm view @agilant/toga-blox@<tag> peerDependencies` against commerce deps when a resolve
104
+ error appears.
105
+ - **A BARREL import is what drags in peers you never use.** The failure text was
106
+ `Rollup failed to resolve import "@fortawesome/free-solid-svg-icons" from
107
+ node_modules/@agilant/toga-blox/dist/components/Input/Input.js`, triggered by
108
+ `AuthLayout.tsx` doing `import { EnvironmentBadge } from "@agilant/toga-blox"` — the package
109
+ index pulls `Input` and `MultiSelect` along with it. A deep import would not have surfaced it, so
110
+ expect the missing-peer set to be blox's **whole** surface, not the components you reference.
111
+ - **`resolve.dedupe` was missing from commerce's `vite.config.ts`** (a `frontend.md` §11 MUST), which
112
+ made consuming blox via a local symlink hazardous: `toga-blox-npm/node_modules/` contains its own
113
+ `react@18.3.1`/`react-dom@18.3.1`, and because blox ships **unbundled**, imports resolve against
114
+ the nearest `node_modules` — under a symlink that is blox's own, giving a second React copy. This
115
+ is precisely why supply's symlink workflow works (it has always deduped
116
+ `react`/`react-dom`/`@tanstack/react-table`) and commerce's did not. Commerce now dedupes
117
+ `react`, `react-dom`, `react-hook-form`, `react-router-dom`, `framer-motion`,
118
+ `@tanstack/react-query`, `@tanstack/react-table`.
119
+ - **`package.json` pins blox with a CARET** (`"@agilant/toga-blox": "^1.0.322-sandbox-client.117"`),
120
+ violating `frontend.md` §13(a) — some published versions ship an empty `dist`, and a caret can
121
+ float you onto one. Pin exact. Related: the `TRUE-80707` branch pin is **11 versions behind** the
122
+ `_sandbox-client` branch pin (`1.0.333-sandbox-client.134`); reconcile before merging.
123
+ - **Secret hygiene re-confirmed unremediated 2026-08-26** — the live tokens are still in the tracked
124
+ `.npmrc` in **both** `toga2-commerce` and `toga25-supply`. See the remediation below.
88
125
  - **Secret hygiene (open remediation):** `toga2-commerce/.npmrc` is **git-tracked** — it is listed
89
126
  in `.gitignore` but was committed before that, so git still tracks it, and it holds a live
90
127
  FontAwesome registry token and a live npm auth token in plaintext. Remediation: (1) **rotate both
@@ -95,6 +132,13 @@ full cross-repo publish-then-build model. **The channel must exist before the ap
95
132
 
96
133
  ## Change history
97
134
 
135
+ - 2026-08-26 — Dependency-resolution findings from a local commerce build: root-caused an
136
+ `ERESOLVE` to the **missing `legacy-peer-deps=true` in commerce's tracked `.npmrc`** (supply had
137
+ it) rather than blox's peer range; recorded the barrel-import trigger for missing peers (added
138
+ `@fortawesome/free-solid-svg-icons`, `react-multi-select-component`); added the previously absent
139
+ `resolve.dedupe` to `vite.config.ts` and explained why supply can symlink blox safely and commerce
140
+ could not; flagged the caret blox pin and the 11-version pin drift on `TRUE-80707`; re-confirmed
141
+ the committed `.npmrc` tokens are still unremediated. All working-tree, uncommitted. (apeterson)
98
142
  - 2026-07-21 — Reworked `amplify.yml` to a **fully dynamic inline build** (no per-branch `case`, no
99
143
  `npm run <script>`): derive mode from `$AWS_BRANCH`, dynamic `npm install
100
144
  "@agilant/toga-blox@$MODE"`, `npx tsc -b` (composite), `npx vite build --mode "$MODE"`. Re-export
@@ -3,7 +3,7 @@
3
3
  | Doc | Summary | Files |
4
4
  |-----|---------|-------|
5
5
  | [TOGa Supply (toga2-supply) Architecture](architecture.md) | `toga2-supply` is the **React + Vite frontend** for TOGa Supply — warehouse fulfillment tooling (shipment selection, fulfill & ship against carrier APIs, NetSui | toga2-supply/src/api/toga.ts, toga2-supply/src/pages/ShipmentItems/view/ShipmentItemsPage.tsx, toga2-supply/src/pages/EditShipment/view/EditShipmentPage.tsx, toga2-supply/src/pages/EditShipment/api/UpdateShipmentApi.ts, toga2-supply/src/pages/Shipments/view/components/ShipmentsCardTableForm/ShipmentsCardTableForm.tsx |
6
- | [Per-currency amount lines (CurrencyAmountLines / CurrencyAmountList) and child-row diffing](features/currency-amount-lines-editor.md) | The shared UI for "one amount per currency" on a parent record — an item's prices, a vendor item's costs. | toga2-supply/src/components/ui/CurrencyAmountLines.tsx, toga2-supply/src/pages/Items/api/itemsApi.ts, toga2-supply/src/pages/VendorItems/api/vendorItemsApi.ts |
6
+ | [Per-currency amount lines (CurrencyAmountLines / CurrencyAmountList) and child-row diffing](features/currency-amount-lines-editor.md) | The shared UI for "one amount per currency" on a parent record — an item's prices, a vendor item's costs. | toga2-supply/src/components/ui/CurrencyAmountLines.tsx, toga2-supply/src/pages/Items/api/itemsApi.ts, toga2-supply/src/pages/VendorItems/api/vendorItemsApi.ts, toga2-supply/src/pages/Items/view/modals/viewEdit/ItemsModalContentTemplate.tsx, toga2-supply/src/pages/VendorItems/view/modals/edit/VendorItemsModalContentTemplate.tsx, toga2-supply/src/utils/formatCurrency.tsx |
7
7
  | [Fulfill & Ship](features/fulfill-and-ship.md) | Fulfill & Ship lets a warehouse user select sales-order line items, enter serials, pick a carrier/method, and in one action: create the Item Fulfillment records | _underscore/Trait/Netsuite/SalesOrder.php, dbchanges2/Client_Growrk/2026-08-10e - GrowrkUpsServiceMethodCodes.sql, toga2-supply/src/pages/EditShipment/view/EditShipmentPage.tsx, _underscore/Model/Client/Measure.php, _underscore/Model/Client/TrackingNumber.php, toga2-supply/src/pages/EditShipment/helpers/ShipmentDetailsForm/getEditShipmentFormOptions.ts, toga2-supply/src/pages/EditShipment/helpers/ShipmentDetailsForm/validateFormOnSubmit.ts, toga2-supply/src/pages/EditShipment/helpers/ShipmentDetailsForm/checkDimensions.ts, toga2-supply/src/components/ui/Tables/BasicTable/BasicTable.tsx, toga2-supply/src/components/ui/Tables/types.ts, toga2-supply/src/components/ui/GoogleMapsLink.tsx, toga2-supply/src/pages/ShipmentItems/view/forms/ShipmentItemsTable.tsx, toga2-supply/src/pages/ShipmentItems/api/ShipmentItemsApi.ts, toga2-supply/src/pages/ShipmentItems/types.ts, toga2-supply/src/pages/EditShipment/viewModel/FIELDS/RETURNLABELFIELDS.json, toga2-supply/src/pages/EditShipment/view/components/forms/EditShipmentForm.tsx, toga2-supply/src/components/ui/BaseInput/UnitSelect.tsx, toga2-supply/src/pages/EditShipment/view/modals/SerialNumbersModal.tsx, toga2-supply/src/pages/ShipmentItems/view/ShipmentItemsPage.tsx, toga2-supply/src/pages/EditShipment/view/EditShipmentPage.tsx, toga2-supply/src/pages/EditShipment/view/components/forms/EditShipmentForm.tsx, toga2-supply/src/pages/EditShipment/view/components/SelectedShipmentItemsTable.tsx, toga2-supply/src/pages/EditShipment/view/helpers/ShipmentDetailsForm/renderEditShipmentFormInput.tsx, toga2-supply/src/pages/EditShipment/viewModel/FIELDS/DUMMYUPDATESHIPMENTFIELDS.json, toga2-supply/src/pages/EditShipment/helpers/ShipmentDetailsForm/renderEditShipmentFormInput.tsx, toga2-supply/tailwind.config.cjs, toga2-supply/src/pages/EditShipment/view/modals/ReturnShippingModal.tsx, toga2-supply/src/styles/index.scss, toga2-supply/src/components/ui/BaseInput/BaseInput.tsx, toga2-supply/src/pages/EditShipment/api/UpdateShipmentApi.ts, toga2-supply/src/pages/EditShipment/viewModel/signatureTypes.ts, toga2-supply/src/pages/EditShipment/view/modals/SelectReturnAddressModal.tsx, toga2-supply/src/pages/EditShipment/helpers/ShipmentDetailsForm/formatShipmentData.ts, toga2-supply/src/pages/EditShipment/types.ts, toga2-supply/src/pages/Shipments/view/ShipmentsPage.tsx, toga2-supply/src/pages/Shipments/view/components/ShipmentsCardTableForm/ShipmentsCardTableForm.tsx, toga2-supply/src/pages/Shipments/api/ShipmentsApi.ts, toga2-supply/src/pages/Shipments/types.ts, toga2-supply/src/pages/FulfilledShipments/view/FulfilledShipmentsPage.tsx, toga2-supply/src/components/ui/CardTable/CardTable.tsx, toga2-supply/src/components/ui/CardTable/types.ts, toga2-supply/src/assets/pen-line.svg, _underscore/Model/Client/ItemFulfillment.php, _underscore/Trait/Netsuite/ItemFulfillment.php, _underscore/Component/Library/Carriers/Ups/Ups.php |
8
8
  | [Order-details field config (valueKey resolution) & the hardcoded Customer name](features/order-detail-field-config-and-customer-name.md) | The supply order-details modal is **config-driven**: each host has a JSON field list under `src/pages/Orders/view/OrderView/viewModel/FIELDS/<HOST>/`, and every | toga2-supply/src/utils/formatCustomerName.tsx, toga2-supply/src/pages/Orders/view/OrderView/components/invoices/OrderContentSection.tsx, toga2-supply/src/pages/Orders/view/OrderView/viewModel/FIELDS/, toga2-supply/src/pages/Orders/view/OrderView/viewModel/useOrderDetailsViewModel.ts, toga2-supply/src/api/toga.ts |
9
9
  | [Table-data request filters (`additionalData` → `getDataTableData`)](features/table-data-additional-filters.md) | A listing page adds its own row filters to a table-view data request by passing an **`additionalData`** prop down to the shared `useFetchData` hook, which forwa | toga2-supply/src/components/ui/Tables/hooks/useFetchData.tsx, toga2-supply/src/api/toga.ts, toga2-supply/src/pages/VendorItems/VendorItemsPage.tsx |