toga-ai 1.0.377 → 1.0.378

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.
@@ -3,5 +3,5 @@
3
3
  | Doc | Summary | Files |
4
4
  |-----|---------|-------|
5
5
  | [Database Changes (dbchanges2) Repository Architecture](architecture.md) | `dbchanges2` is the **schema-migration / SQL change-set repository** for the entire 2.0 platform. | Core/, Client/, Client_<Tenant>/, Logs/, Logs_Client/, _modules/ |
6
- | [Surface Layer Schema (UI presentation/config tables)](features/surface-layer-schema.md) | The persistent schema for the platform-wide **Surface** UI presentation/configuration layer (see the `_underscore` [surface-resolver](../../_underscore/features | dbchanges2/Client/2026-06-25a - SurfaceClientTables.sql, dbchanges2/Client_Compass/2026-06-25d - SalesOrderSurfaceClientSeed.sql, _underscore/Model/Client/ThemeToken.php, toga25-supply/src/themeConfig.json, dbchanges2/Core/2026-06-25a - SurfaceCoreTables.sql, dbchanges2/Core/2026-06-25b - SurfaceRecordsAndFields.sql, dbchanges2/Core/2026-06-25c - SalesOrderLoginSurfaceSeed.sql, dbchanges2/Core/2026-06-29a - ItemsSurfaceSeed.sql, dbchanges2/Core/2026-06-29b - SurfaceMetaPublicReadAcl.sql, dbchanges2/Client/2026-06-29c - SurfaceRecordScriptAcl.sql, dbchanges2/Core/2026-06-29c - SurfaceDebugPhpMethodFix.sql, dbchanges2/Core/2026-06-29d - VendorItemsSurfaceSeed.sql, dbchanges2/Core/2026-06-29e - InventorySurfaceSeed.sql, dbchanges2/Core/2026-06-30a - SurfaceMetaGroupAndSalesOrderSections.sql, dbchanges2/Client/2026-06-30a - SurfaceMetaGroupAcl.sql, dbchanges2/Client_Compass/2026-06-30a - SalesOrderDisplaySectionManagerOverrides.sql, dbchanges2/Client_CompassCanada/2026-06-30a - SalesOrderSurfaceManagerOverrides.sql, dbchanges2/Client_Quad/2026-06-30a - SalesOrderSurfaceClientOverrides.sql, dbchanges2/Client/2026-06-25a - SurfaceClientTables.sql, dbchanges2/Client/2026-06-25b - SurfaceClientSeed.sql, dbchanges2/Client/2026-06-25c - SurfaceClientAcl.sql, dbchanges2/Client/2026-06-03- BLANK_CLIENT_DATABASE.sql, dbchanges2/Core/2026-07-17h - Update - ClearApprovalsFilterButtonConfig.sql, dbchanges2/Client_Compass/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_Compass/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql, dbchanges2/Client_CompassCanada/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_CompassCanada/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql, dbchanges2/Client_Quad/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_Quad/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql |
6
+ | [Surface Layer Schema (UI presentation/config tables)](features/surface-layer-schema.md) | The persistent schema for the platform-wide **Surface** UI presentation/configuration layer (see the `_underscore` [surface-resolver](../../_underscore/features | dbchanges2/Client/2026-06-25a - SurfaceClientTables.sql, dbchanges2/Client_Compass/2026-06-25d - SalesOrderSurfaceClientSeed.sql, _underscore/Model/Client/ThemeToken.php, toga25-supply/src/themeConfig.json, dbchanges2/Core/2026-06-25a - SurfaceCoreTables.sql, dbchanges2/Core/2026-06-25b - SurfaceRecordsAndFields.sql, dbchanges2/Core/2026-06-25c - SalesOrderLoginSurfaceSeed.sql, dbchanges2/Core/2026-06-29a - ItemsSurfaceSeed.sql, dbchanges2/Core/2026-06-29b - SurfaceMetaPublicReadAcl.sql, dbchanges2/Client/2026-06-29c - SurfaceRecordScriptAcl.sql, dbchanges2/Core/2026-06-29c - SurfaceDebugPhpMethodFix.sql, dbchanges2/Core/2026-06-29d - VendorItemsSurfaceSeed.sql, dbchanges2/Core/2026-06-29e - InventorySurfaceSeed.sql, dbchanges2/Core/2026-06-30a - SurfaceMetaGroupAndSalesOrderSections.sql, dbchanges2/Client/2026-06-30a - SurfaceMetaGroupAcl.sql, dbchanges2/Client_Compass/2026-06-30a - SalesOrderDisplaySectionManagerOverrides.sql, dbchanges2/Client_CompassCanada/2026-06-30a - SalesOrderSurfaceManagerOverrides.sql, dbchanges2/Client_Quad/2026-06-30a - SalesOrderSurfaceClientOverrides.sql, dbchanges2/Client/2026-06-25a - SurfaceClientTables.sql, dbchanges2/Client/2026-06-25b - SurfaceClientSeed.sql, dbchanges2/Client/2026-06-25c - SurfaceClientAcl.sql, dbchanges2/Client/2026-06-03- BLANK_CLIENT_DATABASE.sql, dbchanges2/Core/2026-07-17h - Update - ClearApprovalsFilterButtonConfig.sql, dbchanges2/Client_Compass/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_Compass/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql, dbchanges2/Client_CompassCanada/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_CompassCanada/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql, dbchanges2/Client_Quad/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_Quad/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql, dbchanges2/Core/2026-07-20a - Update - HideAdminNotesSectionByDefault.sql, dbchanges2/Core/2026-07-20b - Update - NotesSectionFieldElements.sql, dbchanges2/Client_Compass/2026-07-20a - AdminNotesSectionVisibilityOverride.sql, dbchanges2/Client_Compass/2026-07-20b - NotesSectionFieldsOverride.sql, dbchanges2/Client_CompassCanada/2026-07-20a - AdminNotesSectionVisibilityOverride.sql, dbchanges2/Client_CompassCanada/2026-07-20b - NotesSectionFieldsOverride.sql, dbchanges2/Client_Quad/2026-07-20a - NotesSectionFieldsOverride.sql |
7
7
  | [2.0 New-Client Onboarding (manual process)](workflows/client-onboarding.md) | How to manually stand up a new 2.0 client (tenant). | Client/, Client_<Tenant>/, Core/, Logs_Client/ |
@@ -6,7 +6,7 @@ project: Database Changes
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-07-17
9
+ updated: 2026-07-20
10
10
  owners: [jcardinal, apeterson]
11
11
  files:
12
12
  - dbchanges2/Client/2026-06-25a - SurfaceClientTables.sql
@@ -38,6 +38,13 @@ files:
38
38
  - dbchanges2/Client_CompassCanada/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql
39
39
  - dbchanges2/Client_Quad/2026-07-17a - SalesOrderApprovalActionsOverride.sql
40
40
  - dbchanges2/Client_Quad/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql
41
+ - dbchanges2/Core/2026-07-20a - Update - HideAdminNotesSectionByDefault.sql
42
+ - dbchanges2/Core/2026-07-20b - Update - NotesSectionFieldElements.sql
43
+ - dbchanges2/Client_Compass/2026-07-20a - AdminNotesSectionVisibilityOverride.sql
44
+ - dbchanges2/Client_Compass/2026-07-20b - NotesSectionFieldsOverride.sql
45
+ - dbchanges2/Client_CompassCanada/2026-07-20a - AdminNotesSectionVisibilityOverride.sql
46
+ - dbchanges2/Client_CompassCanada/2026-07-20b - NotesSectionFieldsOverride.sql
47
+ - dbchanges2/Client_Quad/2026-07-20a - NotesSectionFieldsOverride.sql
41
48
  related:
42
49
  - ../../_underscore/features/surface-resolver.md
43
50
  ---
@@ -167,6 +174,45 @@ to `{}` so Core carries **no** `_status` default. Every client — even Quad, wh
167
174
  old default — now declares the full filter config via its own `CONFIG` override. This makes the Core
168
175
  seed a true neutral default for the filter button, matching the action-button rule above.
169
176
 
177
+ ## Display-section visibility — two patterns (marker vs field-driven)
178
+
179
+ A record-modal **display SECTION**'s own `Surfaces.isVisible` can never be client-overridden (the
180
+ cascade keys on `surfaceElementId`, never a Surface's own `isVisible` — see gotcha). Section
181
+ visibility is therefore always carried by an **element**, in one of two patterns depending on whether
182
+ the section has per-client field content:
183
+
184
+ - **Marker pattern (whole-section on/off)** — a section with fixed content (invoices / shipments /
185
+ additional-order-details / admin-notes) carries a single hidden TEXT **`sectionVisibility` marker
186
+ element** (`config.role='sectionVisibility'`); that element's `isVisible` *is* the section's
187
+ visibility. A client flips the section by overriding the marker's `IS_VISIBLE`.
188
+ - **Field-driven pattern (per-client field set)** — a section whose fields vary per client (notes)
189
+ models **each field as a real `FIELD` `SurfaceElement`** (the source of truth for that field's label
190
+ + visibility). No marker element: the FE **DERIVES** the section's visibility as "visible iff ≥1
191
+ field element is visible" (see
192
+ [surface-frontend](../../toga25-supply/features/surface-frontend.md)). This is the third section
193
+ pattern, alongside the card sections (`cardType` → grid renderer) and the marker toggles.
194
+
195
+ ### Core neutral default + client opt-in (admin-notes & notes, 2026-07-20)
196
+ Both sections follow the Core-neutral-default → client-opt-in rule (the same rule as the action/filter
197
+ buttons above): Core seeds the section **off**, each client opts in via a `SurfaceOverride`.
198
+
199
+ - **admin-notes (marker pattern).** `Core/2026-07-20a` flips the admin-notes section's
200
+ `sectionVisibility` marker `isVisible=0`, so the section is **hidden by default**. Resolved
201
+ **id-agnostically** by `Surfaces.slug='admin-notes'` + `config.role='sectionVisibility'` (never a
202
+ hardcoded element id). **Compass + Compass Canada** opt the section back on with a client-wide
203
+ `IS_VISIBLE='1'` override on that same element (`Client_Compass/2026-07-20a`,
204
+ `Client_CompassCanada/2026-07-20a`); every other client stays hidden.
205
+ - **notes (field-driven pattern).** `Core/2026-07-20b` migrates the two previously-hardcoded FE fields
206
+ (`reasonForRequest`, `shippingInstructions`) into two `FIELD` `SurfaceElements` under the `notes`
207
+ surface, both `isVisible=0` in Core (**default = neither field → the section is hidden**). Per-client
208
+ `IS_VISIBLE` overrides: **Quad → shippingInstructions only** (`Client_Quad/2026-07-20a`); **Compass +
209
+ Compass Canada → both** (`Client_Compass/2026-07-20b`, `Client_CompassCanada/2026-07-20b`).
210
+ - **A note field's value binding is a nested-array lookup, not a flat column.** Note text lives in
211
+ `order.salesOrderNotes[]` (each entry has `salesOrderNoteType.slug` + `note`), not a flat order
212
+ field. Each notes `FIELD` element names its note type in **`config.noteTypeSlug`** (`request` /
213
+ `shipping`); the FE resolves `salesOrderNotes[].note` by that slug (client-agnostic). Per-client slug
214
+ variance is handled by a **`CONFIG` override** on the element (REPLACE semantics) — no FE change.
215
+
170
216
  ## ThemeTokens — per-tenant, physically isolated in each client DB
171
217
 
172
218
  `ThemeTokens` lives **inside each tenant's own database** (`Client_Compass.ThemeTokens`,
@@ -320,6 +366,18 @@ rule resumes.
320
366
  override is added). **Open follow-up.**
321
367
 
322
368
  ## Change history
369
+ - 2026-07-20 — Applied the Core-neutral-default → client-opt-in pattern to two SalesOrder display
370
+ sections. **admin-notes** (marker pattern): `Core/2026-07-20a` hides it by default (marker
371
+ `isVisible=0`, resolved id-agnostically by `Surfaces.slug`+`config.role='sectionVisibility'`);
372
+ Compass + Compass Canada opt back in via a client-wide `IS_VISIBLE` override
373
+ (`Client_Compass`/`Client_CompassCanada/2026-07-20a`). **notes** (new field-driven pattern):
374
+ `Core/2026-07-20b` migrates the two hardcoded FE note fields into `FIELD` SurfaceElements (both
375
+ `isVisible=0` = neither by default), with per-client `IS_VISIBLE` overrides — Quad = shipping only
376
+ (`Client_Quad/2026-07-20a`), Compass + Compass Canada = both (`Client_*/2026-07-20b`). Documented the
377
+ two display-section visibility patterns (marker for whole-section on/off vs field-driven where the FE
378
+ derives section visibility from "≥1 field visible") and note-field value binding via
379
+ `config.noteTypeSlug` into `order.salesOrderNotes[]` (per-client slug variance via a `CONFIG`
380
+ override). (apeterson)
323
381
  - 2026-07-17 — Applied the Core-neutral-default → client-opt-in pattern to the sales-order action &
324
382
  filter buttons across Compass, CompassCanada, and Quad (`Client_*/2026-07-17a`+`b`). Cleared the
325
383
  Core approvals-filter `_status` default (`Core/2026-07-17h`) so every client declares its own filter
@@ -9,6 +9,6 @@
9
9
  | [Column Visibility (URL-driven show/hide columns)](features/column-visibility.md) | A "Columns" header button that opens a modal listing every column from the table meta, lets the user show/hide columns, adjusts the table live, and persists the | toga25-supply/src/components/ColumnVisibilityModal/, toga25-supply/src/pages/SalesOrders/SalesOrders.tsx, toga25-supply/src/pages/SalesOrders/viewModel/useSalesOrdersPageViewModel.tsx, toga25-supply/src/pages/SalesOrders/hooks/useSalesOrdersTableData.tsx |
10
10
  | [Meta-Driven Page & Table Setup](features/meta-driven-table-data.md) | A page in this app is **meta-driven end to end**: the page view model fetches *page meta* (labels, sections, ACL) and *table meta* (the columns/fields + table s | toga25-supply/src/pages/SalesOrders/viewModel/useSalesOrdersPageViewModel.tsx, toga25-supply/src/pages/SalesOrders/hooks/useSalesOrdersTableState.ts, toga25-supply/src/hooks/useTablePageMeta.ts, toga-blox-npm/dist/hooks/useFetchPageMeta.d.ts, toga-blox-npm/dist/hooks/useFetchTablePageMeta.d.ts, toga-blox-npm/dist/hooks/useAssignTableFieldLabels.d.ts, toga-blox-npm/dist/components/Table/hooks/useTableData.d.ts |
11
11
  | [Record Modals & Nested Tables](features/record-modals-and-nested-tables.md) | The repo's family of modal + nested-table patterns layered over toga-blox `TableRecordModal` and `PrimaryTable*Layout`. | toga25-supply/src/layout/ItemRecordModalLayout/, toga25-supply/src/layout/SalesOrderRecordModalLayout/, toga25-supply/src/layout/SalesOrderItemsTableLayout/, toga25-supply/src/layout/ItemFulfillmentModal/, toga25-supply/src/layout/GenericNestedTables/, toga25-supply/src/hooks/useTableCellInteractions.ts |
12
- | [Surface Frontend (DB-driven UI consumption, src/surface/)](features/surface-frontend.md) | The frontend consumer of the platform-wide Surface layer — DB-driven UI config fetched from `GET /v2/surfaces/meta?slug=<slug>` instead of statically-imported J | toga25-supply/src/surface/useFetchSurfaceMeta.ts, toga25-supply/src/pages/SalesOrders/helpers/surfaceBundleToTenantFields.ts, toga25-supply/src/pages/SalesOrders/helpers/buildPatchedTenantFields.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/viewModel/useSalesOrderRecordModalLayoutModel.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/SalesOrderView.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/layoutComponents/SalesOrderSummaryGrid.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/getDetailSections.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/index.ts, toga25-supply/src/surface/evaluateSurfaceRule.ts, toga25-supply/src/surface/actionRegistry.ts, toga25-supply/src/surface/componentRegistry.tsx, toga25-supply/src/surface/SurfaceActionBar.tsx, toga25-supply/src/surface/SurfaceSection.tsx, toga25-supply/src/surface/resolve.ts, toga25-supply/src/surface/types.ts, toga25-supply/src/surface/index.ts, toga25-supply/src/pages/Login/LoginPage.tsx, toga25-supply/src/pages/SalesOrders/SalesOrders.tsx, toga25-supply/src/pages/SalesOrders/view/SurfaceRowActions.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/sections/SalesOrderTopBar.tsx, toga25-supply/src/pages/Items/ItemsPage.tsx, toga25-supply/src/pages/Items/viewModel/useItemsPageViewModel.tsx, toga25-supply/src/pages/VendorItems/VendorItemsPage.tsx, toga25-supply/src/pages/VendorItems/viewModel/useVendorItemsPageViewModel.tsx, toga25-supply/src/pages/Inventory/Inventory.tsx, toga25-supply/src/pages/Inventory/viewModel/useInventoryPageViewModel.tsx, toga25-supply/src/pages/Inventory/viewModel/FIELDS/index.ts, toga25-supply/src/fieldsConfig/index.ts |
12
+ | [Surface Frontend (DB-driven UI consumption, src/surface/)](features/surface-frontend.md) | The frontend consumer of the platform-wide Surface layer — DB-driven UI config fetched from `GET /v2/surfaces/meta?slug=<slug>` instead of statically-imported J | toga25-supply/src/surface/useFetchSurfaceMeta.ts, toga25-supply/src/pages/SalesOrders/helpers/surfaceBundleToTenantFields.ts, toga25-supply/src/pages/SalesOrders/helpers/buildPatchedTenantFields.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/viewModel/useSalesOrderRecordModalLayoutModel.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/SalesOrderView.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/layoutComponents/SalesOrderSummaryGrid.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/getDetailSections.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/sections/SalesOrderNotesSection.tsx, toga25-supply/src/pages/SalesOrders/helpers/cleanOrder.ts, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/index.ts, toga25-supply/src/surface/evaluateSurfaceRule.ts, toga25-supply/src/surface/actionRegistry.ts, toga25-supply/src/surface/componentRegistry.tsx, toga25-supply/src/surface/SurfaceActionBar.tsx, toga25-supply/src/surface/SurfaceSection.tsx, toga25-supply/src/surface/resolve.ts, toga25-supply/src/surface/types.ts, toga25-supply/src/surface/index.ts, toga25-supply/src/pages/Login/LoginPage.tsx, toga25-supply/src/pages/SalesOrders/SalesOrders.tsx, toga25-supply/src/pages/SalesOrders/view/SurfaceRowActions.tsx, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/sections/SalesOrderTopBar.tsx, toga25-supply/src/pages/Items/ItemsPage.tsx, toga25-supply/src/pages/Items/viewModel/useItemsPageViewModel.tsx, toga25-supply/src/pages/VendorItems/VendorItemsPage.tsx, toga25-supply/src/pages/VendorItems/viewModel/useVendorItemsPageViewModel.tsx, toga25-supply/src/pages/Inventory/Inventory.tsx, toga25-supply/src/pages/Inventory/viewModel/useInventoryPageViewModel.tsx, toga25-supply/src/pages/Inventory/viewModel/FIELDS/index.ts, toga25-supply/src/fieldsConfig/index.ts |
13
13
  | [AWS Amplify Multi-Environment Deployment](workflows/amplify-deployment.md) | How `toga25-supply` deploys to **all** of its environments on AWS Amplify from a **single shared `amplify.yml`**. | toga25-supply/amplify.yml, toga25-supply/src/api/api.ts, toga25-supply/src/hooks/useAuthenticationFlow.ts, toga25-supply/vite.config.ts, toga25-supply/package.json |
14
14
  | [Cypress Testing Harness (component + e2e)](workflows/cypress-testing.md) | The Cypress test harness for the `toga25-supply` frontend, bootstrapped from scratch (`cypress` was already a dependency but there was no config, no `cypress/` | toga25-supply/cypress.config.ts, toga25-supply/cypress/tsconfig.json, toga25-supply/cypress/support/component.tsx, toga25-supply/cypress/support/component-index.html, toga25-supply/cypress/support/e2e.ts, toga25-supply/cypress/support/commands.ts, toga25-supply/cypress/support/fixtures.ts, toga25-supply/cypress/support/mocks/useApprovalModalViewModel.ts, toga25-supply/cypress/component/SalesOrderApprovalModalsLayout.cy.tsx, toga25-supply/cypress/component/RecordApprovalModalLayout.cy.tsx, toga25-supply/cypress/component/EnterPoNumberModal.cy.tsx, toga25-supply/cypress/e2e/salesOrderApproval.cy.ts |
@@ -6,7 +6,7 @@ project: TOGa 2.5 Supply
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-07-13
9
+ updated: 2026-07-20
10
10
  owners: [jcardinal, apeterson]
11
11
  files:
12
12
  - toga25-supply/src/surface/useFetchSurfaceMeta.ts
@@ -16,6 +16,8 @@ files:
16
16
  - toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/SalesOrderView.tsx
17
17
  - toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/layoutComponents/SalesOrderSummaryGrid.tsx
18
18
  - toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/getDetailSections.tsx
19
+ - toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/view/sections/SalesOrderNotesSection.tsx
20
+ - toga25-supply/src/pages/SalesOrders/helpers/cleanOrder.ts
19
21
  - toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/helpers/index.ts
20
22
  - toga25-supply/src/surface/evaluateSurfaceRule.ts
21
23
  - toga25-supply/src/surface/actionRegistry.ts
@@ -173,6 +175,31 @@ three bespoke renderers `detailSection`/`locationCard`/`totalsCard` are untouche
173
175
  `sectionVisibility` marker element). **Decision (confirmed by the developer this session): KEEP the
174
176
  adapter approach — do NOT replace it with a direct `<SurfaceSection>` swap.** The bespoke grid
175
177
  renderers and the `TenantFields` seam are the deliberate integration point.
178
+
179
+ ### `displayToggle` sections — marker vs field-driven (the notes section)
180
+ `buildSection`'s `displayToggle` branch handles **two** shapes (mirroring the schema's two
181
+ display-section patterns — see
182
+ [surface-layer-schema](../../dbchanges2/features/surface-layer-schema.md)):
183
+ - **Field-carrying section (notes)** — the branch maps every `FIELD`-`renderType` element to a field
184
+ config via `elementToFieldConfig` (now carrying **`config.noteTypeSlug`**) and **DERIVES** the
185
+ section's `isVisible` as `fields.some(f => f.isVisible)` — no `sectionVisibility` marker needed. It
186
+ emits both `isVisible` and the `fields[]` array.
187
+ - **Pure-toggle section (invoices / shipments / additional-order-details / admin-notes)** — no `FIELD`
188
+ elements, so it falls back to the single `sectionVisibility` marker element's `isVisible`.
189
+
190
+ **`SalesOrderNotesSection`** consumes the field-driven shape: it renders **only the visible note
191
+ slots** and resolves each value from `order.salesOrderNotes[]` by
192
+ `salesOrderNoteType.slug === field.noteTypeSlug` (note text is a nested-array entry, not a flat order
193
+ column). When no surface `fields` are supplied it falls back to the **legacy flat props**
194
+ (`reasonForRequest` / `shippingInstructions`, flattened by `cleanOrder`) so non-migrated JSON clients
195
+ still render — see the `cleanOrder` slug gotcha below.
196
+
197
+ **Reusable pattern (field-driven display section):** for a section whose content varies per client,
198
+ model each field as a `FIELD` element (label + visibility source of truth), derive section visibility
199
+ from "≥1 field visible", and bind an array-derived value via element `config` (here `noteTypeSlug`)
200
+ resolved on the FE. This is the presentation counterpart of the schema's field-driven pattern and the
201
+ third section pattern alongside card sections (`cardType` → grid renderer) and marker toggles.
202
+
176
203
  - **Roster gate — `SALES_ORDER_SURFACE_MIGRATED_CLIENTS = [COMPASS, COMPASSCANADA, QUAD]`** (an
177
204
  in-code roster in `surfaceBundleToTenantFields.ts`; the view-model
178
205
  `useSalesOrderRecordModalLayoutModel.tsx` consults it). The view-model resolves sections from
@@ -222,6 +249,14 @@ seeding NYCHH/Prudential/SPGlobal is deferred; the Client-DB prod cross-cluster
222
249
  intentionally gated in `getDetailSections`: `shipments` is **permanently hidden** (the view-model
223
250
  hardcodes `shipmentsData: []` and `useShipments` is commented out; the section gates on
224
251
  `shipmentsData.length > 0`), and `invoices` is data-gated on `invoiceData.length > 0`.
252
+ - **`cleanOrder.ts` flattens notes by the WRONG note-type slugs (latent blank-notes bug).**
253
+ `cleanOrder` builds the legacy flat `order.reasonForRequest` / `order.shippingInstructions` via
254
+ `getNoteBySlug(notes, "reasonForRequest")` / `("shippingInstructions")`, but the API's actual
255
+ `salesOrderNoteType.slug` values are **`request`** / **`shipping`**. So for any client whose notes
256
+ use the real slugs (e.g. Compass) those flat fields resolve to `""` and the legacy notes render
257
+ blank. The new field-driven notes path resolves by the element's `config.noteTypeSlug` (the correct
258
+ slug) so it is unaffected; the flat path only survives as the non-migrated-client fallback in
259
+ `SalesOrderNotesSection`. Fixing `cleanOrder`'s slugs is the durable follow-up for JSON clients.
225
260
  - **The surface `record` shape must match the rule field namespace — wrap as `{ order }`.** Seeded
226
261
  Tier-1 rules namespace their field as `order._status`, so `getByPath(record, "order._status")` only
227
262
  resolves if the host passes `record={{ order }}`. Passing the bare order object resolves to
@@ -258,6 +293,18 @@ seeding NYCHH/Prudential/SPGlobal is deferred; the Client-DB prod cross-cluster
258
293
  treat type-checking as pending. Runtime `GET /v2/surfaces/{slug}/meta` also not yet exercised.
259
294
 
260
295
  ## Change history
296
+ - 2026-07-20 — Made the SalesOrders `notes` display section **field-driven** per client.
297
+ `buildSection`'s `displayToggle` branch now handles field-carrying sections: it maps each `FIELD`
298
+ element to a field config (`elementToFieldConfig` now carries `config.noteTypeSlug`) and **derives**
299
+ section visibility as "≥1 field visible" — no `sectionVisibility` marker needed (pure-toggle sections
300
+ invoices/shipments/additional-order-details/admin-notes still fall back to their marker element).
301
+ `SalesOrderNotesSection` renders only the visible note slots and resolves each value from
302
+ `order.salesOrderNotes[].note` by `salesOrderNoteType.slug === config.noteTypeSlug`, with a legacy
303
+ flat-prop fallback for non-migrated JSON clients. Recorded the reusable field-driven-display-section
304
+ pattern (third section pattern, alongside card sections and marker toggles). Discovered a latent
305
+ blank-notes bug in `cleanOrder.ts` (flattens by the wrong slugs
306
+ `reasonForRequest`/`shippingInstructions` vs the API's actual `request`/`shipping`) — the surface
307
+ resolver reads by the correct slug and bypasses it. (apeterson)
261
308
  - 2026-07-13 — Fixed two SalesOrders row-actions bugs: (1) the portal dismiss overlay in
262
309
  `SurfaceRowActions.tsx` propagated an outside-click up the React component tree to the row handler
263
310
  and opened the record modal — added `e.stopPropagation()` (+ close) on the overlay `onClick`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.377",
3
+ "version": "1.0.378",
4
4
  "description": "TOGA Technology Team Claude Knowledge System — shared AI coding harness with skills, knowledge base CLI, and project installer for Claude Code.",
5
5
  "keywords": [
6
6
  "claude",