toga-ai 1.0.539 → 1.0.541

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.
@@ -6,7 +6,7 @@ project: API
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-08-04
9
+ updated: 2026-08-10
10
10
  owners: ["mhammontree", "dfranks"]
11
11
  files:
12
12
  - api2/Component/Api/V2/V2.php
@@ -106,6 +106,28 @@ fact AIG **does** post live entitlements — the writes were **failing (HTTP 500
106
106
  core `Logs`**, not `Logs_Aig`. See
107
107
  [AIG entitlement intake → Intake is a live API feed](../../../../clients/aig/features/entitlement-intake.md).
108
108
 
109
+ ## Querying prod `Logs.Api` without timing out (narrow first, fetch payloads last)
110
+
111
+ Prod `Logs.Api` is large enough that **any `LIKE` over `requestPayload` / `responsePayload`
112
+ (both `mediumtext`) times out the `toga_query` MCP call at 300 s — even scoped to a single day.**
113
+ There is no usable index on those columns. Do not start from a payload search.
114
+
115
+ The working pattern, in order:
116
+
117
+ 1. **Narrow with indexed / non-text columns only** — a `dtStamp` range plus `route`,
118
+ `method`, `responseCode`, `hostname`. A
119
+ `GROUP BY hostname, route, method, responseCode` over one day is cheap and is the fastest way
120
+ to spot a failing route (this is what surfaced the AIG entitlement 500s).
121
+ 2. **Collect the `id`s** from that narrowed set.
122
+ 3. **Then fetch payloads by `id`**, a few rows at a time, using `LEFT(...)` / `SUBSTRING(...)`
123
+ rather than selecting the whole `mediumtext`.
124
+
125
+ Volume reference for sizing a query: **~8,151 rows in `Logs.Api` for a single day** (2026-05-27).
126
+
127
+ Note this is in tension with the payload-based techniques in the next section — the
128
+ `JSON_EXTRACT` dedupe/vendor-split works because it runs over an **already-narrowed** row set
129
+ (one route, one response code, one date range), not over the raw table.
130
+
109
131
  ## Recovering an intake backlog from logged payloads
110
132
 
111
133
  Because the core/writer `Logs.Api` stores **every** inbound request — including failed writes —
@@ -134,6 +156,11 @@ re-send.
134
156
 
135
157
  ## Change history
136
158
 
159
+ - 2026-08-10 — Added **Querying prod `Logs.Api` without timing out**: any `LIKE` over the
160
+ `mediumtext` `requestPayload`/`responsePayload` times out the `toga_query` MCP call at 300 s even
161
+ for one day. Narrow first on indexed/non-text columns (`dtStamp` + `route` + `responseCode`, or a
162
+ `GROUP BY hostname, route, method, responseCode` to spot the failing route), collect `id`s, then
163
+ fetch payloads by `id` with `LEFT()`/`SUBSTRING()`. Volume reference ~8,151 rows/day. (mhammontree)
137
164
  - 2026-08-04 — Added the limit of the commit-logs contract: an **uncaught PHP fatal** (a
138
165
  `Call to undefined method` from an interceptor dispatch) produced **zero rows in
139
166
  `Logs_Compass.Api`** — no 5xx row for the whole day and no row for the failing request — while
@@ -3,5 +3,5 @@
3
3
  | Doc | Framework | Summary | Files |
4
4
  |-----|-----------|---------|-------|
5
5
  | [AIG Contract Reconciliation & Dealer Programs (STS_001 / SA_001)](features/contract-reconciliation.md) | 2.0 | How to reconcile an **AIG contract sales sheet** against the `Client_Aig` tenant, and the durable finding that the **Staples Advantage.com (`SA_001`) program do | _underscore/Model/Client/Entitlement.php, _underscore/Model/Aig/Entitlement.php, _underscore/Model/Client/Contact.php, _underscore/Model/Aig/Contact.php |
6
- | [AIG Entitlement Intake & SaleItem Code Resolution](features/entitlement-intake.md) | 2.0 | The `_Model_Aig_Entitlement::prePost` interceptor below is the code path for AIG protection-plan entitlements arriving as `api2` V2 JSON POSTs — and that path * | _underscore/Model/Aig/Entitlement.php, dbchanges2/Client_Aig/2026-06-18a - TRUE-79534 AIG SaleItem codes.sql |
6
+ | [AIG Entitlement Intake & SaleItem Code Resolution](features/entitlement-intake.md) | 2.0 | The `_Model_Aig_Entitlement::prePost` interceptor below is the code path for AIG protection-plan entitlements arriving as `api2` V2 JSON POSTs — and that path * | _underscore/Model/Aig/Entitlement.php, api2/Component/Api/V2/V2.php, dbchanges2/Client_Aig/2026-06-18a - TRUE-79534 AIG SaleItem codes.sql |
7
7
  | [AIG (Staples Protection Plan)](profile.md) | 2.0 | AIG is the warranty underwriter behind the **Staples Protection Plan** retail program. | |
@@ -5,7 +5,7 @@ project: API
5
5
  client: aig
6
6
  type: client-feature
7
7
  status: active
8
- updated: 2026-07-29
8
+ updated: 2026-08-10
9
9
  owners: ["mhammontree"]
10
10
  files:
11
11
  - _underscore/Model/Client/Entitlement.php
@@ -27,7 +27,7 @@ durable finding that the **Staples Advantage.com (`SA_001`) program does not rou
27
27
  | DealerId | Program | Status |
28
28
  |---|---|---|
29
29
  | `STS_001` | **Staples Technology Solutions** | live api2 feed; intake gap **RESOLVED 2026-07-29** (self-healed) |
30
- | `SA_001` | **Staples Advantage.com** | **never reaches api2** — separate feed; scope decision is the one open item |
30
+ | `SA_001` | **Staples Advantage.com** | **never reaches api2** — SA.com is not sending them; **AIG owns and is working it**, not a TOGa defect (2026-08-10) |
31
31
 
32
32
  `STS_001` arrives as a **live API feed**; its 156-contract gap from the now-fixed intake bug
33
33
  **self-healed** (the feed re-sent and all 156 succeeded — see below). `SA_001` never reaches our
@@ -106,6 +106,28 @@ because their `SA_001` contract was never ingested.
106
106
  into `Client_Aig`, and if so via what feed/integration? That is a scope/integration decision for
107
107
  AIG / the team — not a back-fill of a dropped load. Until decided, `SA_001` stays out-of-pipeline.
108
108
 
109
+ #### CLOSED (2026-08-10): missing `SA_001` entitlements are AIG's issue, not a TOGa defect
110
+
111
+ **SA.com is not sending the new entitlements to us. AIG owns this and is working it.** Stop
112
+ working "missing SA_001 entitlement" escalations as a TOGa bug — the correct response is to route
113
+ them to AIG.
114
+
115
+ Confirmed on a concrete case from AIG's own Warranty Administration Portal: contract
116
+ **CN 1000046237886 / CCN 7680760752-2** (Staples Advantage.com program, plan *"2YR Printer Onsite
117
+ Next Day: ($500-$999.99)"*, purchased 2026-05-27) exists in AIG's portal and is **completely absent
118
+ on our side**:
119
+
120
+ - zero rows in `Client_Aig.Entitlements` — searched by `number`, `vendorEntitlementNumber`,
121
+ `datePurchase`, **and** contract-holder name;
122
+ - zero rows in `Client_Aig.Contacts`;
123
+ - **zero trace in `Logs_Aig.Api` or the core/writer `Logs.Api`.**
124
+
125
+ No log row anywhere means the contract was **never delivered** — nothing was rejected, nothing was
126
+ partially created, and there is no dropped payload to replay. That is the distinguishing signal:
127
+ a TOGa-side intake defect always leaves a failed-write row in the core `Logs` (see
128
+ [request logging](../../../2.0/apps/api2/features/request-logging.md)); **total absence points
129
+ upstream.**
130
+
109
131
  ## How to load a missing program / sheet (back-fill)
110
132
 
111
133
  If `SA_001` is ever confirmed in-scope for `Client_Aig` and AIG cannot route it through api2, it
@@ -118,6 +140,13 @@ feed re-send over a manual load whenever the contracts do reach api2.
118
140
 
119
141
  ## Change history
120
142
 
143
+ - 2026-08-10 — Read-only prod investigation. **Closed the `SA_001` question as NOT a TOGa defect:**
144
+ SA.com is not sending the entitlements; **AIG owns and is working it.** Evidenced by portal
145
+ contract CN 1000046237886 / CCN 7680760752-2 (purchased 2026-05-27) being absent from
146
+ `Client_Aig.Entitlements` *and* `Contacts` *and* from both `Logs_Aig.Api` and core `Logs.Api` —
147
+ never delivered, so nothing was rejected or partially created. Recorded the general
148
+ discriminator: an intake defect leaves a failed-write row in core `Logs`; **total log absence
149
+ points upstream.** Future "missing SA_001 entitlement" escalations route to AIG. (mhammontree)
121
150
  - 2026-07-29 — TRUE-80179 / TRUE-79534: **156 active `STS_001` RESOLVED (self-healed).** The next
122
151
  scheduled batch re-sent all 156 outstanding contracts and every one succeeded (201 × 156, zero
123
152
  failures; `Client_Aig.Entitlements` +156) — no manual back-fill needed, because the feed re-sends
@@ -5,10 +5,11 @@ project: API
5
5
  client: aig
6
6
  type: client-feature
7
7
  status: active
8
- updated: 2026-08-03
8
+ updated: 2026-08-10
9
9
  owners: ["mhammontree"]
10
10
  files:
11
11
  - _underscore/Model/Aig/Entitlement.php
12
+ - api2/Component/Api/V2/V2.php
12
13
  - dbchanges2/Client_Aig/2026-06-18a - TRUE-79534 AIG SaleItem codes.sql
13
14
  related:
14
15
  - clients/aig/features/contract-reconciliation.md
@@ -122,6 +123,32 @@ Loading the catalog fixed intake, and because the feed re-sends outstanding cont
122
123
  **backlog of dropped contracts self-healed on the next scheduled run** — no manual back-fill was
123
124
  needed (see [contract reconciliation](contract-reconciliation.md)).
124
125
 
126
+ ## Verified prod state (2026-08-10) — the catalog IS loaded; do NOT re-diagnose as "missing item ID"
127
+
128
+ Re-verified read-only against prod. **The TRUE-79534 catalog load did run and is present**, so a
129
+ 1064/500 seen from here on is **not** the missing-catalog problem:
130
+
131
+ - **`Client_Aig.Items` = 2,212 rows** — 1,110 `ASI-*`, 558 `SM-*`, 37 legacy `SP-*`.
132
+ - The exact part number in the historically-failing payloads, **`ASI-2YG2`, IS present.**
133
+ - **`Client_Aig.Entitlements` = 621 rows**, latest `dtCreated` **2026-08-04**, latest
134
+ `datePurchase` **2026-07-31** — entitlements are still being created.
135
+
136
+ So the remaining exposure at `Entitlement.php:48` is the **input-empty** variant (an *empty*
137
+ `itemId` interpolated), not an unknown-code variant. Anyone re-opening this should read the actual
138
+ interpolated value before assuming a missing AIG item ID — the earlier ticket already ruled that
139
+ out.
140
+
141
+ **Open question (not answered this session):** the historical failure window in the core/writer
142
+ `Logs.Api` shows **exactly 1,200 `POST /v2/entitlements` requests per day, all HTTP 500, zero
143
+ successes on that route**, every day from at least **2026-05-20 through 2026-07-28**, with the
144
+ *same* stale batch replayed daily — log id 996641 (05-27) and id 1877726 (07-28) carry
145
+ **byte-identical** payloads (`number: 1000045980287`), as do ids 998804 / 1881349
146
+ (`number: 1000045972141`). No entitlement POSTs are logged in core `Logs` after 07-28. Because
147
+ **successful** writes log to `Logs_Aig`, not core `Logs`, the most likely reading is that the route
148
+ recovered on 07-29 exactly as the resolution above describes. But the creating path for the newest
149
+ rows (through 2026-08-04) was **not positively identified** — confirm it in `Logs_Aig.Api` before
150
+ asserting either "intake is entirely down" or "intake is healthy."
151
+
125
152
  ## Business Unit (`UserDefined2`) — answered and DROPPED (nothing to build)
126
153
 
127
154
  AIG (Alissa, 2026-05-04) confirmed the **Business Unit / Value** field needs **nothing returned to
@@ -294,7 +321,17 @@ this interceptor or use this dual-purpose Items pattern.
294
321
  `Apis_RecordFields` override row that stripped `name` as an identifier — see
295
322
  [api2 nested-relationship writes → Per-API overrides](../../../2.0/apps/api2/features/nested-relationship-writes.md).
296
323
  - **A lookup miss yields an empty `$itemId` that crashes the next query (confirmed in prod,
297
- TRUE-79534).** When `saleItem.partNumber` is **valid but absent** from `Client_Aig.Items`, the
324
+ TRUE-79534).** The unguarded line is **`_underscore/Model/Aig/Entitlement.php:48`** in `prePost`,
325
+ reached from **`api2/Component/Api/V2/V2.php:2601`**. The malformed statement it emits is:
326
+ ```sql
327
+ SELECT EntitlementFulfillmentTypes.name
328
+ FROM Items_EntitlementFulfillmentTypes
329
+ INNER JOIN EntitlementFulfillmentTypes ON ...
330
+ WHERE Items_EntitlementFulfillmentTypes.itemId = -- nothing after the '='
331
+ ```
332
+ → MySQL **ERROR 1064** → HTTP 500. The fix is a **guard clause / early return** on an
333
+ empty-or-failed lookup *before* this query runs. When `saleItem.partNumber` is
334
+ **valid but absent** from `Client_Aig.Items`, the
298
335
  `SELECT id … WHERE partNumber = '{$partNumber}' LIMIT 1` returns nothing → `$itemId` is empty →
299
336
  the **fulfillment query interpolates it unquoted** → `WHERE …itemId = ` → **ERROR 1064** → HTTP
300
337
  500 (the mechanism behind the whole intake outage). A separate **input-empty** variant also
@@ -320,6 +357,16 @@ this interceptor or use this dual-purpose Items pattern.
320
357
 
321
358
  ## Change history
322
359
 
360
+ - 2026-08-10 — Read-only prod investigation (no code/SQL changed). Added **Verified prod state**:
361
+ the TRUE-79534 catalog **is** loaded (`Client_Aig.Items` = 2,212 rows — 1,110 `ASI-*` / 558
362
+ `SM-*` / 37 `SP-*`; `ASI-2YG2` present), so a future 1064 here is the **empty-input** variant,
363
+ **not** a missing AIG item ID — do not re-diagnose it as TRUE-79534. Pinned the unguarded lookup
364
+ to **`_underscore/Model/Aig/Entitlement.php:48`** (from `api2/Component/Api/V2/V2.php:2601`) and
365
+ recorded the exact malformed fulfillment query, so the fix is a plain guard clause. Quantified
366
+ the historical outage from core `Logs.Api` (**1,200 × HTTP 500/day, zero successes on the route,
367
+ 2026-05-20 → 2026-07-28**, the same batch replayed byte-identically — corroborates the
368
+ scheduled-re-send model). Flagged the **open question**: 621 entitlements exist with `dtCreated`
369
+ up to 2026-08-04 and the creating path was not positively identified. (mhammontree)
323
370
  - 2026-08-03 (later pass) — **Two corrections.** (1) The `ERROR 1267` temp-table collation trap is a
324
371
  **per-machine server-config property, not a "prod-only" / version difference**: measured prod Core
325
372
  8.0.39 with the MySQL 8 default `utf8mb4_0900_ai_ci` vs local Core_2 8.0.44 with an explicit
@@ -0,0 +1,82 @@
1
+ ---
2
+ type: session
3
+ slug: elite-supply-fe
4
+ title: Elite Service Requests (Orders) + Inventory FE in toga2-supply — code complete, blocked on backend Page.php context-setting fatal
5
+ author: tcox
6
+ repos: [toga2-supply]
7
+ framework: "2.0"
8
+ client: elite
9
+ status: active
10
+ created: 2026-08-10
11
+ updated: 2026-08-10
12
+ ---
13
+
14
+ # Session: elite-supply-fe
15
+ **Date:** 2026-08-10
16
+ **Project/Repo:** toga2-supply (2.0)
17
+ **Task:** Elite's full supply2 FE surface — Service Requests page (retitled Orders page on the new `service-requests` backend view) + details modal + the previously built Inventory page — code complete and iteratively debugged against beta; currently blocked by a backend Page.php fatal that the new service-requests context-setting triggers on the inventory page.
18
+
19
+ > Supersedes session `elite-inventory-fe` (2026-08-06). All Inventory findings there still stand.
20
+
21
+ ---
22
+
23
+ ## What WORKED
24
+ - **"Service Requests" is NOT a new page.** The mockup source (`TOGa Supply mockup Elite/elite/elite-app.jsx`: `VIEW_META.Orders.title = "Service Requests"`, nav `{label:"Orders", text:"Service Requests"}`) defines it as the Elite Orders view retitled; the "details modal" is a details-only order modal (`elite-modal.jsx`, titles itself "Order INC…"). Implemented as config on the existing OrdersPage — no new route.
25
+ - **Sales Orders / Service Requests FE (all tsc-clean, uncommitted on local `_production`):**
26
+ - `src/pages/Orders/viewModel/FIELDS/ELITE/BASE.json` (new): `pageTitle: "Service Requests"`, `tableSlug: "service-requests"`, `listingSlug: "sales-orders-listing"`, `hasQuoteFilter: false`, `approvalsButton.isEnabled: false`, `exportButton.isEnabled: true`, NO `approvalActionOptions`.
27
+ - `useOrdersPageViewModel.ts`: explicit `ELITE: {base: BASE_ELITE}` + `if (hostName === "ELITE") return hostFields.base;` (PRUDENTIAL precedent). L63 `|| fieldMapping.compass` fallback untouched.
28
+ - `OrdersPage.tsx`: all 8 hardcoded `sales-orders` references now `fields?.tableSlug || "sales-orders"` (listing meta, tableDisplayData, setSlug, ResetFilters, both providers); ACL check optional-chained + slug-keyed with a TS cast; `pageTitle` initialized from `fields?.pageTitle || "Orders"`; `isQuote: false` in additionalData is now conditional — omitted when `fields?.hasQuoteFilter === false` (backend confirmed FE-side fix: ServiceRequests has no isQuote column).
29
+ - `SlideMenu.tsx` ELITE branch: "Service Requests" (link `/`) + Inventory deep-link.
30
+ - `renderModalContent.tsx` untouched — DEFAULT routes ELITE row-clicks to OrderDetailsModal only (verified: no ELITE key, no ApprovalsModal).
31
+ - **Review fixes (CodeRabbit) on Inventory work:** `InventoryPage.tsx` re-seeds `selectedGrouping` when the stored uuid isn't in the resolved host's array (corrupt JSON handled); `InventoryRouter.tsx` redirects `/inventory_items` → `/inventory` for hosts whose default view lacks `subTableParent` (data-driven, no host literal). Both no-ops for NYCHH/Compass/Quad.
32
+ - **`convertConstructorColumnTitles.ts`** null-guarded — a page slug without backend meta degrades to "" labels instead of crashing the table (was the white-screen when `service-requests-listing` didn't exist).
33
+ - **Post-merge diagnostics (2026-08-07 prod→beta refresh rebuilt Client_Elite at 11:55 + beta API redeploy) — root causes found via DB reads:**
34
+ 1. Login failure → re-seeded devteam user had an EMPTY password → fixed by hash copy from `Client_Compass.Users` id 127046 (login verified working after).
35
+ 2. `service-requests` table view wiped by merge → backend recreated it (ServiceRequests-record view joined to Tickets/Customers/ServiceRequestTypes/SalesOrders with Elite-tailored status CASE).
36
+ 3. Service Requests table 500 → OUR `isQuote: false` filter against ServiceRequests → fixed FE-side (above), backend confirmed.
37
+ 4. Inventory `/pages/meta?slug=inventory` 500 "Undefined array key 190" → fully diagnosed (see Blockers).
38
+
39
+ ## What did NOT work — DO NOT RETRY THESE
40
+ - **`listingSlug: "service-requests-listing"`** — no such page exists: `Core.Pages` has only `sales-orders-listing` (id 2) etc. The null pageMeta then crashed `convertConstructorColumnTitles` (`Cannot read properties of null (reading 'settings')`). Reverted to `sales-orders-listing`; if backend ever creates a service-requests page, it's a one-line JSON change.
41
+ - **Assuming the service-requests view is a renamed SalesOrders view** — it's a ServiceRequests-record view (`SalesOrders.serviceRequestId = ServiceRequests.id` 1:1). Consequence: table rows carry ServiceRequests uuids; the details modal fetches by uuid via sales-orders record routes → probable uuid mismatch on row click (untested — see Not tried).
42
+ - **Theory: empty `ClientPageSettings` caused the inventory meta 500** — WRONG: NYCHH's is empty too; that table (and `Pages_DefaultTableViewGroups`/`TableViewGroups`) is unused everywhere. The real cause is the context-setting fatal (Blockers).
43
+ - **Sending `isQuote` unconditionally in OrdersPage additionalData** — 1054 "Unknown column 'ServiceRequests.isQuote'". It's a SalesOrders-only column.
44
+ - (Carried from previous session) `/login` redirect ≠ Domains row exists; devteam lives only in dev-sandbox `Client_Compass` (127046); MCP env `client-beta` exposes no schemas — beta API client DBs are on the **dev-sandbox** cluster.
45
+
46
+ ## Not tried yet (candidates for next session)
47
+ - **Row-click details modal on Service Requests** — expect uuid mismatch (ServiceRequests uuid vs sales-orders fetch routes). Fix is either backend (expose linked `SalesOrders.uuid` as the drill identifier) or FE (ELITE detail `apiFields` pointing at service-requests routes in `useOrderDetailsViewModel` — structure already supports per-host apiFields).
48
+ - Inventory nested-expand re-validation (blocked again post-merge: prod's stale TableViewJoins were re-imported; the 3-statement fix from the drift doc applies but join ROW IDS may have shifted — match by tableViewId + joinRecordId + joinOnRecordFieldId, not row id).
49
+ - Four-client regression pass (NYCHH/ENDEAVORHEALTH/COMPASS/COMPASSCANADA, same browser) before PR.
50
+ - Branch + PR (tcox branches personally; bare ticket-ID name; ask first).
51
+ - gitignore check: `TOGa Supply mockup Elite/` folder sits untracked in the repo root — must not ride into the PR.
52
+
53
+ ## Current file state
54
+ | File | Status | Notes |
55
+ |------|--------|-------|
56
+ | src/pages/Orders/viewModel/FIELDS/ELITE/BASE.json | new, uncommitted | full ELITE page config (see What WORKED) |
57
+ | src/pages/Orders/viewModel/index.ts | modified, uncommitted | BASE_ELITE export |
58
+ | src/pages/Orders/viewModel/useOrdersPageViewModel.ts | modified, uncommitted | ELITE fieldMapping entry + base branch |
59
+ | src/pages/Orders/OrdersPage.tsx | modified, uncommitted | slug threading, pageTitle from fields, conditional isQuote, null-safe ACL |
60
+ | src/components/layout/SlideMenu/SlideMenu.tsx | modified, uncommitted | ELITE: Service Requests + Inventory |
61
+ | src/utils/convertConstructorColumnTitles.ts | modified, uncommitted | null-guarded pageMeta/settings |
62
+ | src/pages/Inventory/** (7 files, from elite-inventory-fe session) | modified/new, uncommitted | host-scoped group options etc. + CodeRabbit fixes (selectedGrouping re-seed, InventoryRouter guard) |
63
+ | src/utils/resolveClientHostName.ts | new, uncommitted | store-first + subdomain fallback |
64
+ | package.json | modified, uncommitted | `npm run elite` script |
65
+ | dev-sandbox Client_Elite.Users | hand-fixed, KEPT | devteam password restored via Compass hash copy |
66
+
67
+ ## Decisions made
68
+ - Service Requests = config on OrdersPage (pageTitle/tableSlug/listingSlug/hasQuoteFilter in FIELDS), NOT a new route — mockup defines it as the Orders view retitled; supply2.0 components render it (2.5 mockup = spec for WHAT, 2.0 = HOW).
69
+ - Slug threading via FIELDS with `|| "sales-orders"` fallbacks — other hosts have no tableSlug key, provably unchanged. Rejected: fixing the broken lowercase-`compass` fallback (cross-client risk).
70
+ - Reuse `sales-orders-listing` page meta for Elite until a service-requests page exists (headers come from the table-view meta, so only ACL/search-labels are affected).
71
+ - Keep devteam seeding + document every hand-fix — the 08-07 merge proved hand-inserted beta rows get eaten; everything must eventually be dbchanges2 migrations.
72
+
73
+ ## Blockers
74
+ - **Backend: `/pages/meta?slug=inventory` fatal "Undefined array key 190"** — `Client_Elite.ClientRecordFieldSettings` row id 1 (field 58 → label "Total" in context of field 190 = ServiceRequests.id, created for the new service-requests view) is fetched for ANY page whose field set includes field 58; `_underscore/Model/Core/Page.php:824` resolves `contextRecordFieldId` against a lookup built only from the current page's fields → key 190 missing on inventory → warning made fatal by the newly deployed strict error handler. Fix: isset()-guard Page.php ~L822-829 (skip context settings whose context field isn't on the page). Deleting the row would un-break inventory but lose the service-requests "Total" label. Reported to backend 2026-08-07.
75
+ - Inventory nested-expand still blocked by the re-imported TableViewJoins drift (see drift doc `clients/elite/features/supply2-tableview-config-drift.md`).
76
+ - Details-modal uuid mismatch (suspected, untested) — see Not tried.
77
+
78
+ ## Exact next step
79
+ > Confirm with backend that the Page.php:824 isset() guard (or equivalent) is deployed, then `npm run elite`, log in as devteam, and verify BOTH pages render: Inventory (columns + chevron) and Service Requests (table loads without isQuote error). Then click a Service Request row and capture the modal's network call — the expected failure is the ServiceRequests-uuid-vs-sales-orders-route mismatch.
80
+
81
+ ---
82
+ _Saved by /session-save on 2026-08-10_
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.539",
3
+ "version": "1.0.541",
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",