toga-ai 1.0.242 → 1.0.243

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.
@@ -0,0 +1,74 @@
1
+ ---
2
+ type: session
3
+ slug: surface-layer
4
+ title: Surface grouped-meta + SalesOrders section migration (Compass/CompassCanada/Quad)
5
+ author: jcardinal
6
+ repos: [_underscore, dbchanges2, toga25-supply]
7
+ framework: "2.0"
8
+ client: shared
9
+ status: active
10
+ created: 2026-06-30
11
+ updated: 2026-06-30
12
+ ---
13
+
14
+ # Session: surface-layer
15
+ **Date:** 2026-06-30
16
+ **Project/Repo:** _underscore / dbchanges2 / toga25-supply (2.0)
17
+ **Task:** Build a grouped surface-meta resolver and migrate the toga25-supply SalesOrders record-modal sections onto the Surface UI presentation layer for the seeded clients (Compass, CompassCanada, Quad), keeping non-migrated clients on JSON.
18
+
19
+ ---
20
+
21
+ ## What WORKED
22
+ - **`metaGroup` grouped resolver** — `_Model_Core_Surface::metaGroup(&$api, string $slugs): object` at `GET /v2/surfaces/meta-group?slugs=a,b,c`. Splits/dedupes the slug list (cap `META_GROUP_MAX_SLUGS=25`, logs truncation), calls the existing `resolve()` per slug (shares its per-slug file cache), returns `{group, surfaces:{slug=>bundle|null}}`. `php -l` clean. Verified live on dev-sandbox (200 after the ACL grant).
23
+ - **Resolver message-resolution fixes** (`Surface.php` `_buildBundle`/`_resolveElement`): remap element message slots id→messageKey before return (labels previously fell back to the element key); collect `disabledTooltipMessageId` + emit `disabledTooltip`; set `surface.titleMessageKey`; merge the 2nd `_loadMessages` return into `$messageKeyById`; log dangling message ids; `resolve()` now `: object`. These were latent because SECTION/BUTTON_BAR rendering was never shipped.
24
+ - **FE grouped fetch + adapter**: `useFetchSurfaceMetaGroup(slugs[])` (order-insensitive key, staleTime Infinity, `extractGroup` by `{surfaces}` fingerprint) and `surfaceBundleToTenantFields()` adapter → existing `TenantFields` shape, so `SalesOrderSummaryGrid` renderers + `getDetailSections` are untouched.
25
+ - **Migrated-client roster gate**: `SALES_ORDER_SURFACE_MIGRATED_CLIENTS=[COMPASS,COMPASSCANADA,QUAD]` in the view-model; only roster clients fetch+resolve Surface sections (merge = JSON-base + Surface-wins), everyone else stays JSON.
26
+ - **DB seeds (applied on dev-sandbox, working)**: Core `2026-06-30a` (meta-group RecordScript + `order-recurring` surface + 5 display-toggle marker surfaces); Client `2026-06-30a` meta-group AclRecordScripts grant; Compass/CompassCanada/Quad `2026-06-30a` SurfaceOverrides for section deltas.
27
+ - **403 EZ-1 on meta-group fixed** by applying the Client AclRecordScripts dispatch grant per client DB. Verified via toga-db: `meta` script id 25 → roles 1,3,4; `meta-group` id 27 had no grant until applied.
28
+ - **JSON cleanup**: removed the migrated section blocks from COMPASS/COMPASSCANADA/QUAD `orderViewFields.json` (kept salesOrderDetailsConfig/itemFulfillmentClickRule/recordActionFields/recordApprovals). DEFAULT left intact.
29
+ - **/capture PUSHED** — 4 surface feature docs + 3 client profiles updated on team `_main` (commits f732160 + fc8de41).
30
+
31
+ ## What did NOT work — DO NOT RETRY THESE
32
+ - **Client-DB seeds resolving Core ids via cross-DB subselect** (`Core.RecordScripts`/`Core.Surfaces`/`Core.SurfaceElements` from a `Client_*` file). Works on the dev-sandbox all-in-one instance but **WILL FAIL in production** — Core is a separate MySQL cluster there, and cross-DB queries require one instance. This is the current id-agnostic approach in all 4 Client seeds; it is the prod blocker (see Blockers).
33
+ - **Parent `parentSurfaceId` GROUP-row design for grouped meta** — rejected by CTO review: adds Core schema state + a new TYPE, must be seeded per-client per-env for a grouping the FE already knows statically, and reintroduces id drift. The slug-list `metaGroup` is schema-stateless.
34
+ - **Surface-only cutover for all clients** (no roster gate) — would regress non-seeded clients (NYCHH/Prudential/SPGlobal/DEFAULT) because the Core section surfaces are SHARED and seeded from Compass's shape; they'd inherit it.
35
+ - **Overriding a section's visibility via the Surface row's own `isVisible`** — the resolver cascade (`_loadOverrides`) only overrides ELEMENTS, never a surface's `isVisible`. Hence each display-toggle surface carries one `sectionVisibility` marker element that the overrides target.
36
+ - **Removing MANAGER/Quad summary shipping/tax tooltips via override** — `_castOverride` treats `TOOLTIP_MESSAGE` as numeric-only, so it can't null a tooltip. Cosmetic; deferred.
37
+ - **Seeding `elementType` for Quad** — confirmed dead config (no `.ts/.tsx` reads it); needs no migration.
38
+
39
+ ## Not tried yet (candidates for next session)
40
+ - **Prod cross-cluster seed fix** (the on-hold blocker): rewrite the 4 Client seeds to hardcode Core ids as literals + resolve `roleId` by name (per `Client/2026-06-23b - ItemTranslationsAcl.sql`), zero `Core.` refs. User chose "I'll give you the prod ids" — apply the Core seed to prod Core, run the lookup query (in session memory / below) to get literal recordScriptId/surfaceId/surfaceElementId, then bake them in. Also audit the EXISTING `2026-06-25c`/`2026-06-29c`/`2026-06-25d` surface seeds for the same anti-pattern.
41
+ - **Action-bar / approval-modal migration** — still JSON; pulls in the Compass approval state machine + Tier-2 `stepTwoAssigned`. The `sales-order-actions` BUTTON_BAR surface is already seeded but not yet consumed by the FE.
42
+ - **Seed NYCHH / Prudential / SPGlobal** (and add to the roster) once confirmed live on toga25-supply; they need Quad-like client-level overrides to match the DEFAULT shape.
43
+
44
+ ## Current file state
45
+ | File | Status | Notes |
46
+ |------|--------|-------|
47
+ | _underscore/Model/Core/Surface.php | modified | metaGroup() + message-resolution fixes; php -l clean |
48
+ | dbchanges2/Core/2026-06-30a - SurfaceMetaGroupAndSalesOrderSections.sql | created | meta-group script + order-recurring + 5 display surfaces + markers. Prod-safe (Core→Core). |
49
+ | dbchanges2/Client/2026-06-30a - SurfaceMetaGroupAcl.sql | created | meta-group dispatch grant. ⚠ cross-DB Core ref — prod fix pending. |
50
+ | dbchanges2/Client_Compass/2026-06-30a - SalesOrderDisplaySectionManagerOverrides.sql | created | MANAGER hide invoices/admin-notes. ⚠ cross-DB. |
51
+ | dbchanges2/Client_CompassCanada/2026-06-30a - SalesOrderSurfaceManagerOverrides.sql | created | MANAGER deltas (shippingMethod/invoices/admin-notes), role by name. ⚠ cross-DB. |
52
+ | dbchanges2/Client_Quad/2026-06-30a - SalesOrderSurfaceClientOverrides.sql | created | client-level deltas (costCenter/shippingMethod/recurringTotal + 3 display hides). ⚠ cross-DB. |
53
+ | toga25-supply/src/surface/useFetchSurfaceMeta.ts | modified | added useFetchSurfaceMetaGroup + extractGroup |
54
+ | toga25-supply/src/surface/index.ts | modified | re-export group hook |
55
+ | toga25-supply/src/pages/SalesOrders/helpers/surfaceBundleToTenantFields.ts | created | adapter + slug list + migrated-client roster |
56
+ | toga25-supply/.../SalesOrderRecordModalLayout/helpers/index.ts | modified | re-export adapter + roster |
57
+ | toga25-supply/.../viewModel/useSalesOrderRecordModalLayoutModel.tsx | modified | roster-gated Surface merge |
58
+ | toga25-supply/.../FIELDS/{COMPASS,COMPASSCANADA,QUAD}/orderViewFields.json | modified | section blocks deleted; data-wiring kept |
59
+
60
+ ## Decisions made
61
+ - **Grouped meta = slug-list `metaGroup`, not a parent GROUP row** (CTO AGREE-with-alternative): schema-stateless, reuses resolve()/cache, avoids id drift.
62
+ - **Migrated-client roster gate in code, not an env flag**: protects unseeded/unknown clients from the shared Compass-shaped Core base. Remove a client from the roster only after its seeds are verified; then its JSON sections are safe to delete.
63
+ - **Display sections = field-less SECTION surfaces with one `sectionVisibility` marker element**: only way to express per-role section visibility given the resolver overrides elements, not surface.isVisible.
64
+ - **Data-wiring stays JSON** (salesOrderDetailsConfig, itemFulfillmentClickRule): presentation-only migration, config/logic boundary (Inventory precedent).
65
+ - **Prod-safe Client-seed pattern = literal Core ids + Client-local roleId-by-name** (per ItemTranslationsAcl). Deferred to the prod pass.
66
+
67
+ ## Blockers
68
+ - **PROD CROSS-CLUSTER (on hold, user-paused):** the 4 Client-DB seeds use `Core.*` cross-DB subselects that break against prod's separate Core cluster. Fix recorded in memory [[surface-prod-crossdb-fix-pending]]. Lookup query to get prod literal ids is in the session thread. Dev-sandbox is unaffected (all-in-one) and fully working.
69
+
70
+ ## Exact next step
71
+ > When resuming the prod fix: apply `Core/2026-06-30a` to the prod Core cluster, then run the labeled lookup query against prod Core (returns meta-group recordScriptId + surfaceId/surfaceElementId for order-details/c_erpEntityId, ship-to/shippingMethod.name, order-recurring/isTotal, and the invoices/admin-notes/additional-order-details/notes `sectionVisibility` markers). Paste results, then rewrite the 4 Client `2026-06-30a` seeds to hardcode those Core ids as literals and resolve only `roleId` by name — removing every `Core.` reference — following `dbchanges2/Client/2026-06-23b - ItemTranslationsAcl.sql`.
72
+
73
+ ---
74
+ _Saved by /session-save on 2026-06-30_
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.242",
3
+ "version": "1.0.243",
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",