toga-ai 1.0.370 → 1.0.371

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.
@@ -21,7 +21,7 @@
21
21
  | [NetSuite REST Client (_Component_Api_Netsuite) — record writes & SuiteQL](features/netsuite-rest-client.md) | `_Component_Api_Netsuite` is the **2.0 `_underscore` NetSuite REST client** — the shared primitive every worker2/api2 NetSuite caller uses for record GETs, Suit | _underscore/Component/Api/Netsuite/Netsuite.php |
22
22
  | [Per-Client Database Connections & the Local Logs Trap](features/per-client-database-connections.md) | When `_underscore` serves a request for a client it opens **three distinct per-client database connections**, not one. | _underscore/Database.php, _underscore/ApiRequest.php, _underscore/Model/Client/Logs/Api.php |
23
23
  | [Recursive Item Fulfillments (upstream mirroring)](features/recursive-item-fulfillments.md) | In a multi-tier supply chain a sales order (SO) spawns a purchase order (PO) that becomes another SO downstream, and so on. | _underscore/Model/Client/ItemFulfillment.php, _underscore/Model/Client/ItemFulfillmentItem.php, _underscore/Model/Client/ItemFulfillmentItemUnit.php, _underscore/Model/Client/ItemFulfillmentPackage.php, _underscore/Model/Compass/AdvanceShippingNotice.php, dbchanges2/Core/2026-02-13 - 75601 - RecursiveItemFulfillmentCreation.sql, dbchanges2/Core/2026-06-04 - RecursiveItemFulfillmentPut.sql, dbchanges2/Client_Compass/2026-07-02a - FixSA133377TrackingSerialAndDuplicateIF.sql |
24
- | [Surface Resolver (_Model_Core_Surface::resolve — replaces Page::meta)](features/surface-resolver.md) | The runtime for the platform-wide **Surface** UI presentation layer: 9 `_underscore` models plus a cached resolver, `_Model_Core_Surface::resolve(&$api, string | _underscore/Model/Core/Surface.php, _underscore/Model/Client/AclRecordScript.php, _underscore/Model/Core/RecordScript.php, dbchanges2/Core/2026-06-30a - SurfaceMetaGroupAndSalesOrderSections.sql, dbchanges2/Client/2026-06-30a - SurfaceMetaGroupAcl.sql, dbchanges2/Client_Quad/2026-07-01a - GrantSurfacesMetaGroupScriptAcl.sql, dbchanges2/Client_CompassCanada/2026-07-01a - GrantSurfacesMetaGroupScriptAcl.sql, dbchanges2/Core/2026-06-29b - SurfaceMetaPublicReadAcl.sql, dbchanges2/Client/2026-06-29c - SurfaceRecordScriptAcl.sql, dbchanges2/Core/2026-06-29c - SurfaceDebugPhpMethodFix.sql, dbchanges2/Client_Compass/2026-07-15f - SalesOrderRecordActionsRemoveDeadConfigRuleOverrides.sql, _underscore/Model/Core/SurfaceElement.php, _underscore/Model/Core/Action.php, _underscore/Model/Core/Vocabulary.php, _underscore/Model/Core/VocabularyTerm.php, _underscore/Model/Core/Message.php, _underscore/Model/Client/SurfaceOverride.php, _underscore/Model/Client/MessageTranslation.php, _underscore/Model/Client/ThemeToken.php, _underscore/Model/Core/Page.php |
24
+ | [Surface Resolver (_Model_Core_Surface::resolve — replaces Page::meta)](features/surface-resolver.md) | The runtime for the platform-wide **Surface** UI presentation layer: 9 `_underscore` models plus a cached resolver, `_Model_Core_Surface::resolve(&$api, string | _underscore/Model/Core/Surface.php, _underscore/Model/Client/AclRecordScript.php, _underscore/Model/Core/RecordScript.php, dbchanges2/Core/2026-06-30a - SurfaceMetaGroupAndSalesOrderSections.sql, dbchanges2/Client/2026-06-30a - SurfaceMetaGroupAcl.sql, dbchanges2/Client_Quad/2026-07-01a - GrantSurfacesMetaGroupScriptAcl.sql, dbchanges2/Client_CompassCanada/2026-07-01a - GrantSurfacesMetaGroupScriptAcl.sql, dbchanges2/Core/2026-06-29b - SurfaceMetaPublicReadAcl.sql, dbchanges2/Client/2026-06-29c - SurfaceRecordScriptAcl.sql, dbchanges2/Core/2026-06-29c - SurfaceDebugPhpMethodFix.sql, dbchanges2/Client_Compass/2026-07-15f - SalesOrderRecordActionsRemoveDeadConfigRuleOverrides.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, _underscore/Model/Core/SurfaceElement.php, _underscore/Model/Core/Action.php, _underscore/Model/Core/Vocabulary.php, _underscore/Model/Core/VocabularyTerm.php, _underscore/Model/Core/Message.php, _underscore/Model/Client/SurfaceOverride.php, _underscore/Model/Client/MessageTranslation.php, _underscore/Model/Client/ThemeToken.php, _underscore/Model/Core/Page.php |
25
25
  | [Tracking-Number Bridge Migration (ASN / Item Fulfillment / Item Receipt)](features/tracking-number-bridges.md) | Shipment tracking numbers used to live as **scalar FK columns** (`trackingNumberId`, `returnTrackingNumberId`) directly on the lowest-level "unit"/"item" tables | api2/Component/Api/V2/V2.php, _underscore/Model/Client/AdvanceShippingNoticeItemUnit.php, _underscore/Model/Client/AdvanceShippingNoticeItemUnits/TrackingNumber.php, _underscore/Model/Client/ItemFulfillmentItemUnits/TrackingNumber.php, _underscore/Model/Client/ItemFulfillment.php, _underscore/Model/Prudential/AdvanceShippingNotice.php, _underscore/Model/Compass/AdvanceShippingNotice.php, _underscore/Trait/Netsuite/ItemFulfillment.php, api2/Component/Api/Cxml/Cxml.php, dbchanges2/Client/2026-06-10 - TrackingNumberBridges.sql, dbchanges2/Core/2026-06-10 - TrackingNumberBridges.sql, dbchanges2/Client_Prudential/2026-06-15 - ItemFulfillmentTrackingNumberAclLogicGroups.sql, dbchanges2/Client_Quad/2026-06-18a - ItemFulfillmentItemReceiptTrackingNumberAclLogicGroups.sql, dbchanges2/Client_Nychh/2026-06-19b - ItemFulfillmentItemReceiptTrackingNumberAclLogicGroups.sql, dbchanges2/Client_Growrk/2026-07-13a - ItemFulfillmentItemReceiptTrackingNumberAclLogicGroups.sql, dbchanges2/Client_Nychh/2026-06-19a - FixItemFulfillmentTableViewTrackingAndRoot.sql, dbchanges2/Client_Quad/2026-06-19a - FixItemFulfillmentTableViewTrackingAndRoot.sql |
26
26
  | [Units for Items for Purchase Orders — Data Structure](features/units-for-items-for-purchase-orders.md) | Describes how unit (serialized inventory) data is linked to sales-order and purchase-order line items behind the `units-for-items-for-purchase-orders` TableView | |
27
27
  | [Refreshing a Local Dev Database from Beta (dev-sandbox)](workflows/local-db-refresh-from-beta.md) | How to reset a local 2.0 dev database from the **beta / dev-sandbox** environment: dump each schema (`Core`, `Client_<Id>`, `Logs_<Id>`, …) from the beta host, | api2/Config/, _underscore/Loader.php, _underscore/Model/Client/BundleTranslation.php, api2/Component/Api/V2/V2.php, toga25-supply/sync_compasscanada_schema.sql |
@@ -6,7 +6,7 @@ project: _Underscore
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-07-16
9
+ updated: 2026-07-17
10
10
  owners: [jcardinal, apeterson]
11
11
  files:
12
12
  - _underscore/Model/Core/Surface.php
@@ -20,6 +20,13 @@ files:
20
20
  - dbchanges2/Client/2026-06-29c - SurfaceRecordScriptAcl.sql
21
21
  - dbchanges2/Core/2026-06-29c - SurfaceDebugPhpMethodFix.sql
22
22
  - dbchanges2/Client_Compass/2026-07-15f - SalesOrderRecordActionsRemoveDeadConfigRuleOverrides.sql
23
+ - dbchanges2/Core/2026-07-17h - Update - ClearApprovalsFilterButtonConfig.sql
24
+ - dbchanges2/Client_Compass/2026-07-17a - SalesOrderApprovalActionsOverride.sql
25
+ - dbchanges2/Client_Compass/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql
26
+ - dbchanges2/Client_CompassCanada/2026-07-17a - SalesOrderApprovalActionsOverride.sql
27
+ - dbchanges2/Client_CompassCanada/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql
28
+ - dbchanges2/Client_Quad/2026-07-17a - SalesOrderApprovalActionsOverride.sql
29
+ - dbchanges2/Client_Quad/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql
23
30
  - _underscore/Model/Core/SurfaceElement.php
24
31
  - _underscore/Model/Core/Action.php
25
32
  - _underscore/Model/Core/Vocabulary.php
@@ -186,16 +193,35 @@ Compass's shape. Core was re-baselined as a true shared default so clients store
186
193
  4. Edit-in-Commerce only for Compass / CompassCanada.
187
194
  5. Columns button hidden by default.
188
195
 
189
- Per-client diffs layered on top:
190
- - **Quad** — Approve + Deny only; filter narrowed to `pendingApproval`; filter button visible.
191
- - **Compass USA / Compass Canada** — two-stage approvals: record-action `visibilityRule`/`enabledRule`
192
- = `in [pendingApproval, pendingInitialApproval]`. **Compass Canada** additionally gets a `CONFIG`
193
- override on the approvals filter button (surface `sales-order-listing-actions`) to add
194
- `pendingInitialApproval`.
195
-
196
- > ⚠ **Regression left open:** the Compass / CompassCanada **non-rule** overrides (Edit-in-Commerce
197
- > flags, role-8 Manager hides) were **wiped during the rebuilds and not re-added**. The two-stage rule
198
- > overrides are also LOCAL only (see above).
196
+ ### Per-client sales-order button diffs — materialized 2026-07-17
197
+ The Core neutral default now covers the **approvals filter button too**: `Core/2026-07-17h` cleared
198
+ element 22's `config` to `{}`, so Core carries no `_status` default and **every** client (even Quad,
199
+ whose value matches the old default) supplies the whole filter `CONFIG` via its own override (REPLACE
200
+ semantics). Concrete per-client diffs, all via `SurfaceOverrides` (rule JSON is
201
+ `{"all":[{"field":"order._status","op":"in","value":[…]}]}`; seed authoring/element-id map in the
202
+ [surface-layer-schema](../../dbchanges2/features/surface-layer-schema.md) doc):
203
+
204
+ - **Compass USA / Compass Canada** (mirror each other) — two-stage approval:
205
+ - **ADMIN**: opts into all four gated record-action buttons (approve/deny/approvalWorkflow/editOrder)
206
+ `IS_VISIBLE=1`, and widens **both** `VISIBILITY_RULE` **and** `ENABLED_RULE` to
207
+ `_status in [pendingApproval, pendingInitialApproval]`. (For approve, the Tier-2 `stepTwoAssigned`
208
+ predicate still further gates *enabled* in PHP.) On the approvals filter button: `IS_VISIBLE=1` +
209
+ `CONFIG` `additionalData._status = [pendingApproval, pendingInitialApproval]`.
210
+ - **MANAGER**: opts into **approve + deny only** (`IS_VISIBLE=1`); rules left at the Core base
211
+ (`pendingApproval` only, single-stage). No approvals-filter override → inherits Core `isVisible=0`
212
+ (hidden).
213
+ - **Quad** — Approve + Deny only, visible for **role ids 7/8/9** (`IS_VISIBLE=1`), with **no** rule
214
+ override (status stays at the Core base `pendingApproval`). This is deliberately **per-role**, unlike
215
+ Quad's usual client-wide (`roleId NULL`) pattern — per request. Approvals filter button is
216
+ client-wide with `CONFIG` `_status=[pendingApproval]`; the "Enter PO Details" button (element 32) is
217
+ made client-wide visible (⚠ dual-gate — see the schema doc; the FE may also read `config.isVisible`).
218
+
219
+ > ✅ **Regression (mostly) closed:** the two-stage rule overrides and the record-action/filter opt-ins
220
+ > for Compass / Compass Canada that were wiped in the earlier rebuild were **re-added 2026-07-17**
221
+ > (`Client_Compass`/`Client_CompassCanada/2026-07-17a`+`b`). These surface DB changes remain **local/
222
+ > beta only** pending promotion; the `_underscore` rule-override code + the ENUM widening still ship
223
+ > together on promotion, and the php-reviewer pass + PHPUnit regression for the rule-override path are
224
+ > still outstanding.
199
225
 
200
226
  ### Operational gotcha — raw SQL bypasses the cache-bust
201
227
  Raw SQL against the surface tables bypasses the model-layer cache-bust, so the on-disk bundle cache
@@ -312,6 +338,14 @@ Core record grants + their logic-group expressions all evaluate `all`/`"1"`. The
312
338
  match Compass, a follow-up migration aligning both `meta` and `meta-group` to roles 1,3,4 is needed.
313
339
 
314
340
  ## Change history
341
+ - 2026-07-17 — Materialized the per-client sales-order button diffs (re-adding the overrides wiped in
342
+ the earlier rebuild): Compass/CompassCanada ADMIN = all four record-action buttons visible + both
343
+ `VISIBILITY_RULE`/`ENABLED_RULE` widened to `[pendingApproval, pendingInitialApproval]`, MANAGER =
344
+ approve+deny visible with Core-base rules; Quad = approve+deny visible per-role (ids 7/8/9), no rule
345
+ override. Extended the Core neutral default to the **approvals filter button** — `Core/2026-07-17h`
346
+ cleared element 22's config so every client (including Quad) now supplies the full filter `CONFIG`
347
+ (REPLACE semantics): Compass/CC admin = two statuses, Quad client-wide = `pendingApproval`. Overrides
348
+ remain local/beta only pending promotion. (apeterson)
315
349
  - 2026-07-16 — Recorded a resolver gotcha: a `SurfaceOverrides` row with `attribute='CONFIG'` carrying
316
350
  a rule value is silently dead — `_castOverride` routes CONFIG→`$config`, not
317
351
  `$visibilityRule`/`$enabledRule` (logs + returns null), and `overridesByElementAndAttr` keyed by
@@ -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 |
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 |
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-16
9
+ updated: 2026-07-17
10
10
  owners: [jcardinal, apeterson]
11
11
  files:
12
12
  - dbchanges2/Client/2026-06-25a - SurfaceClientTables.sql
@@ -31,6 +31,13 @@ files:
31
31
  - dbchanges2/Client/2026-06-25b - SurfaceClientSeed.sql
32
32
  - dbchanges2/Client/2026-06-25c - SurfaceClientAcl.sql
33
33
  - dbchanges2/Client/2026-06-03- BLANK_CLIENT_DATABASE.sql
34
+ - dbchanges2/Core/2026-07-17h - Update - ClearApprovalsFilterButtonConfig.sql
35
+ - dbchanges2/Client_Compass/2026-07-17a - SalesOrderApprovalActionsOverride.sql
36
+ - dbchanges2/Client_Compass/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql
37
+ - dbchanges2/Client_CompassCanada/2026-07-17a - SalesOrderApprovalActionsOverride.sql
38
+ - dbchanges2/Client_CompassCanada/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql
39
+ - dbchanges2/Client_Quad/2026-07-17a - SalesOrderApprovalActionsOverride.sql
40
+ - dbchanges2/Client_Quad/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql
34
41
  related:
35
42
  - ../../_underscore/features/surface-resolver.md
36
43
  ---
@@ -114,6 +121,52 @@ it `isVisible: true`. Both `Core/2026-06-29a` (Item) and `Core/2026-06-29d` (Ven
114
121
  off." A client opts a role in via a `SurfaceOverride` (`IS_VISIBLE=1`), scoped by role/persona. This is
115
122
  the seed-authoring corollary of the Core neutral-default re-baseline recorded in the resolver doc.
116
123
 
124
+ ## Sales-order button overrides — element identities & the id-agnostic authoring house style
125
+
126
+ When a client opts its roles into the sales-order action/filter buttons (the resolved per-client
127
+ *behavior* lives in the [surface-resolver](../../_underscore/features/surface-resolver.md)
128
+ per-client-diffs section), the override seeds follow a strict **id-agnostic house style** so one file
129
+ runs unchanged across local/beta/prod:
130
+
131
+ - **Resolve `roleId` by `Roles.name`** (`'Admin'`/`'Manager'`) — client role ids are environment-specific.
132
+ - **Resolve the Core element by surface slug + one discriminator**, never a hardcoded Core id:
133
+ `Core.Actions.slug` for action buttons; the **label `messageKey`** (`salesOrder.filter.approvals`)
134
+ for the approvals filter button — it has no `actionId` and, after the Core config wipe (below), no
135
+ `config` left to match on; or `config.valueKey` (`poNumber`) for the "Enter PO Details" button.
136
+ - **`personaId`/`languageId` NULL** for role/client scope (language-agnostic).
137
+ - **Every INSERT guarded by `NOT EXISTS`** on `(surfaceElementId, roleId, attribute, personaId NULL,
138
+ languageId NULL)` so the file is re-runnable. A per-role Quad seed does this with a
139
+ `CROSS JOIN (SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9)` + a `Roles` existence join, so a
140
+ missing role id is skipped rather than erroring.
141
+ - Cross-DB read of `Core.*` from the client seed mirrors the established Surface override pattern
142
+ (safe where Core+client are co-located; the prod cross-cluster caveat in the gotchas applies).
143
+
144
+ **Which attribute for which change:** `IS_VISIBLE`/`CONFIG` are in the base attribute ENUM;
145
+ `VISIBILITY_RULE`/`ENABLED_RULE` require the widened ENUM
146
+ (`Client/2026-07-15 - SurfaceOverridesAttributeRuleValues.sql`) applied per-tenant first (see the
147
+ resolver doc — an unknown ENUM value silently coerces to `''` in non-strict mode). A `CONFIG` override
148
+ **replaces the whole object**, so a filter override must carry the full config
149
+ (`role`+`filterKey`+`additionalData`), never just the changed key.
150
+
151
+ **Sales-order surface element identities** (Core seed `2026-07-17c` assigns EXPLICIT, stable ids — but
152
+ author overrides by slug/messageKey/valueKey, not by these numbers):
153
+
154
+ | Surface (id) | Element | id | Discriminator |
155
+ |---|---|---|---|
156
+ | `sales-order-record-actions` (8) | approve | 17 | action `salesOrder.approve` |
157
+ | | deny | 18 | action `salesOrder.deny` |
158
+ | | approvalWorkflow | 19 | action `salesOrder.approvalWorkflow` |
159
+ | | viewLog | 20 | always-visible / ungated (excluded from overrides) |
160
+ | | editOrder | 21 | action `salesOrder.editOrder` |
161
+ | | Enter PO Details | 32 | no `actionId`; `config.valueKey='poNumber'` |
162
+ | `sales-order-listing-actions` (9) | approvals filter | 22 | label messageKey `salesOrder.filter.approvals` |
163
+ | | columns | 23 | — |
164
+
165
+ **Core approvals-filter default removed (`Core/2026-07-17h`).** Core element 22's `config` was cleared
166
+ to `{}` so Core carries **no** `_status` default. Every client — even Quad, whose config matches the
167
+ old default — now declares the full filter config via its own `CONFIG` override. This makes the Core
168
+ seed a true neutral default for the filter button, matching the action-button rule above.
169
+
117
170
  ## ThemeTokens — per-tenant, physically isolated in each client DB
118
171
 
119
172
  `ThemeTokens` lives **inside each tenant's own database** (`Client_Compass.ThemeTokens`,
@@ -251,8 +304,32 @@ rule resumes.
251
304
  flip a section per role/persona. Also discovered: `elementType` in `orderViewFields.json` is **dead
252
305
  config** (no renderer reads it); and MANAGER/Quad summary tooltips can't be removed via the cascade
253
306
  because `TOOLTIP_MESSAGE` is numeric-only (cosmetic, deferred).
307
+ - **`Client_CompassCanada` may be missing the `SurfaceOverrides` table entirely** (its beta reset
308
+ predates the surface rollout). Prereqs — in order — **before any CompassCanada surface override
309
+ runs:** `Client/2026-06-25a - SurfaceClientTables.sql` (creates `ThemeTokens`/`MessageTranslations`/
310
+ `SurfaceOverrides`), then `Client/2026-07-15 - SurfaceOverridesAttributeRuleValues.sql` (ENUM
311
+ widening for the rule attributes); and for the `/surfaces/meta` endpoint to resolve at all, the ACL
312
+ dispatch grants (`Client/2026-06-25c`, `2026-06-29c`, `2026-06-30a`). Skipping the table/ENUM
313
+ bring-up makes the `2026-07-17a/b` override inserts fail or silently coerce.
314
+ - **"Enter PO Details" (element 32) has a DUAL visibility gate.** Its rendering is gated by BOTH the
315
+ element-level `isVisible` flag AND a `config`-embedded `"isVisible":false` (migrated from Quad's
316
+ legacy field JSON, alongside `isEnabled`/`isComplete`). Flipping the element-level `IS_VISIBLE=1`
317
+ (as `Client_Quad/2026-07-17b` block 3 does) may **not** render the button if the FE
318
+ (`SalesOrderTopBar`) reads `config.isVisible` — in which case a `CONFIG` override is also needed.
319
+ Element 32 is likewise `isEnabled=0` (appears but disabled until an `IS_ENABLED`/`ENABLED_RULE`
320
+ override is added). **Open follow-up.**
254
321
 
255
322
  ## Change history
323
+ - 2026-07-17 — Applied the Core-neutral-default → client-opt-in pattern to the sales-order action &
324
+ filter buttons across Compass, CompassCanada, and Quad (`Client_*/2026-07-17a`+`b`). Cleared the
325
+ Core approvals-filter `_status` default (`Core/2026-07-17h`) so every client declares its own filter
326
+ `CONFIG`. Documented the sales-order surface **element-identity map** (surface 8 elements 17-21/32;
327
+ surface 9 elements 22-23) and the **id-agnostic override authoring house style** (resolve `roleId`
328
+ by name; resolve Core elements by surface slug + `Actions.slug`/label messageKey/`config.valueKey`;
329
+ `personaId`/`languageId` NULL; `NOT EXISTS`-guarded). Added gotchas: `Client_CompassCanada` may lack
330
+ the `SurfaceOverrides` table (beta reset predates rollout — table/ENUM/ACL prereqs must run first),
331
+ and "Enter PO Details" (element 32) has a dual visibility gate (element-level `isVisible` AND a
332
+ `config.isVisible` the FE may also read). (apeterson)
256
333
  - 2026-07-16 — Documented `SurfaceElements`' two orthogonal axes (`valueType` display vs `inputType`
257
334
  edit widget — neither derived from the other) and the edit-mode columns added in `Core/2026-06-25a`
258
335
  (`inputType`, `validationType` [renamed from `hasTypeCheck`], `showRequiredIndicator`, `isSearchable`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.370",
3
+ "version": "1.0.371",
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",