toga-ai 1.0.741 → 1.0.742

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.
@@ -204,7 +204,11 @@ children" rule:
204
204
  re-catalogs it.** The `toga2-commerce` storefront relays whatever item `GET /v2/bundles/{uuid}`
205
205
  returns; its `catalogId = 1` filter guards standalone item search only, never bundles. So a kit
206
206
  whose `BundleItems.itemId` points at the wrong-catalog twin makes **every checkout POST the wrong
207
- item** (434 rows / 110 bundles after the 2026-08-31 fold). Fix in data, not the frontend. See
207
+ item** (434 rows / 110 bundles after the 2026-08-31 fold). **The fix surface is the DB bundle rows
208
+ PLUS the serving cache, never the frontend code** — after the DB rows were restored, a **shared**
209
+ bundle cache (api2/`_underscore` response cache and/or a CDN in front of `/v2/bundles`) kept
210
+ serving the stale Agilant uuid to new checkouts (two different users still POSTed the Agilant 2427
211
+ uuid) until it was invalidated. See
208
212
  [catalog-fold reversal](../workflows/catalog-fold-reversal.md) and
209
213
  [bundle item visibility & selectability](../../../2.0/apps/toga2-commerce/features/bundle-item-visibility-and-selectability.md).
210
214
  - **⚠ `isFulfillable` is born on the catalog-2 (Agilant) item** and propagates to the client-facing
@@ -223,6 +227,11 @@ children" rule:
223
227
  [catalog-fold reversal](../workflows/catalog-fold-reversal.md).
224
228
 
225
229
  ## Change history
230
+ - 2026-09-02 — Corrected the `BundleItems` fix surface: restoring the DB bundle rows is **not**
231
+ sufficient — a **shared** server-side bundle cache (api2/`_underscore` response cache and/or a CDN
232
+ in front of `/v2/bundles`) kept serving the stale Agilant uuid to new checkouts until it was
233
+ invalidated (proven by two different users still POSTing the Agilant 2427 uuid after the DB fix).
234
+ Fix surface = DB bundle rows **plus** the serving cache, never the frontend code. (jcardinal)
226
235
  - 2026-09-02 — **Resolved the flagged "distinct vs shared partNumber" tension**: the Agilant twins
227
236
  carry **distinct** part-number variants (the `#ABA` form ≠ the plain part number, e.g.
228
237
  `C40QYUC#ABA` vs `C40QYUC`), so table-wide `partNumber` uniqueness holds and the catalog-fold
@@ -120,13 +120,28 @@ qualifiers):
120
120
  **Rehearse on a same-day full prod clone, then apply with a pre-run backup. CTO review gated the
121
121
  approach** (rehearse-on-clone, fail-loud, customer-scoped, tenant-locked).
122
122
 
123
- ### Stragglers: `#ABA`-variant PO lines need a manual VendorItem re-map
124
- Because the `#ABA` twins share no part number, neither the merge's part-number map nor a
125
- partNumber-twin re-point catches PurchaseOrder lines sitting on them. These were fixed by an
126
- **explicit VendorItem mapping**, scoped to **pending `customerId = 2` PO lines**, then clearing
127
- `PurchaseOrders.dtSubmitted` so the PO re-transmits: VendorItem **3845 → 3597** @ `945.17`,
128
- VendorItem **3884 → 3600** @ `1627.38`. Why a mis-mapped PO line transmits the wrong SKU + cost
129
- and drops to EMAIL rather than cXML:
123
+ ### Stragglers: broken-window orders need a manual, by-id re-map (SO item + PO VendorItem)
124
+ Orders created **before** the data fix + cache flush stay on the Agilant twin and must be
125
+ re-pointed by hand — the `#ABA` twins share no part number, so neither the merge's part-number map
126
+ nor a partNumber-twin re-point catches them. The pattern per straggler, scoped to **pending
127
+ `customerId = 2` lines**:
128
+ 1. **`SalesOrderItems.itemId`** — re-point the Agilant twin → the Compass twin.
129
+ 2. **`PurchaseOrderItems.vendorItemId` + `cost`** (if a PO was already built) — re-point to the
130
+ Compass `VendorItem` (correct SKU + cost).
131
+ 3. **`PurchaseOrders.dtSubmitted = NULL`** — so cron 2 re-transmits the PO correctly (cXML, right
132
+ SKU/cost).
133
+
134
+ Verified twin / VendorItem mappings this session:
135
+
136
+ | Agilant item | Compass item | Compass VendorItem | Vendor SKU | Cost |
137
+ |---|---|---|---|---|
138
+ | 2427 (`C40QYUC`) | 2157 | 3597 | 5775600 | 945.17 |
139
+ | 2431 (`C40QYUC-1`) | 2158 | 3598 | 7761063 | 945.17 |
140
+
141
+ PO `VendorItem` re-maps: **3845 → 3597** @ `945.17`, **3884 → 3600** @ `1627.38` (`B7HJ2UC#ABA`).
142
+ Orders fixed: `50312344-1`, `50312409-1`, `SA136868`, `SA136874`, plus the earlier 5 pending
143
+ (`SA136819`, `SA136820`, `SA136845`, `SA136852`, `SA136862`). Why a mis-mapped PO line transmits the
144
+ wrong SKU + cost and drops to EMAIL rather than cXML:
130
145
  [MITS PO transmission to vendors](../features/mits-po-transmission-to-vendors.md).
131
146
 
132
147
  ## The folded `BundleItems` was the storefront's ongoing bad-order source
@@ -135,10 +150,32 @@ rows across 110 bundles**. The `toga2-commerce` storefront does **not** choose a
135
150
  relays whatever item uuid `GET /v2/bundles/{uuid}` returns (`bundleItems.item.uuid`). The
136
151
  `catalogId = 1` filter runs **only** on standalone item search (`genericApi.ts`, `FilterApi.ts`,
137
152
  `translatedSearchApi.ts`), **never** on bundles. So a folded `BundleItems.itemId` makes **every new
138
- checkout of that kit POST the Agilant item** — a fresh wrong-catalog order each time. **The fix is
139
- data (restore `BundleItems`); the frontend needs no change.** Storefront-side detail:
153
+ checkout of that kit POST the Agilant item** — a fresh wrong-catalog order each time. **The fix
154
+ surface is the DB bundle rows PLUS the serving cache (below) — never the frontend code.**
155
+ Storefront-side detail:
140
156
  [bundle item visibility & selectability](../../../2.0/apps/toga2-commerce/features/bundle-item-visibility-and-selectability.md).
141
157
 
158
+ ## Restoring `BundleItems` is NOT enough — a stale bundle cache kept minting bad orders
159
+ Even **after** `BundleItems.itemId` was restored in the DB (bundle 17 → item 2157, bundle 15 →
160
+ 2158, verified), **new** Compass storefront orders **still** came in on the Agilant twin. Proof:
161
+ order **SA136874** (created 2026-09-02 13:03:16 by user **83091**) — its incoming
162
+ `POST /v2/sales-orders` in `Logs_Compass.Api` carried the **Agilant** item 2427 uuid
163
+ (`88bd4bb2…`), not the Compass 2157 uuid — while the DB bundle already pointed at 2157.
164
+ **SA136868** (11:25) showed the same. Because **multiple distinct users** got the stale item, this
165
+ is a **shared server-side cache** (the api2/`_underscore` response cache and/or a CDN in front of
166
+ `/v2/bundles`), **not** a per-browser one — so the DB fix is invisible to shoppers until the cache
167
+ is flushed. The developer invalidated the **front-end cache**, which stopped the new bad orders.
168
+ **Durable rule: a catalog-fold reversal is not complete until the bundle/item cache is invalidated
169
+ across every layer — front-end, api2/`_underscore` response cache, and any CDN in front of
170
+ `/v2/bundles`.**
171
+
172
+ **Operational sequence (do it in this order):**
173
+ 1. Fix the data (restore `BundleItems`, re-point stragglers — below).
174
+ 2. **Invalidate the bundle/item cache** (front-end + api2/`_underscore` + any CDN on `/v2/bundles`).
175
+ 3. Confirm new incoming `POST /v2/sales-orders` in `Logs_Compass.Api` stop carrying the Agilant uuid.
176
+ 4. **Only then re-enable vendor transmission (cron 2)** — otherwise it transmits the still-bad
177
+ post-fix orders.
178
+
142
179
  ## The NetSuite→TOGa sync is NOT the source of new cust-2 bad orders (suspect ruled out)
143
180
  The 1.0 NetSuite→TOGa TOGaSupply sync (`worker/crons/toga2/netsuite/`,
144
181
  `App_Api_Toga2::syncSalesOrderFromNetsuite`, `library/app/api/toga2.php` ~L752) writes **only the
@@ -172,6 +209,14 @@ rule still holds: `cust 2` → catalog 1; `cust 1` and `cust 3` → catalog 2.
172
209
  nothing. Restore `BundleItems` to stop new wrong-catalog checkouts. (The sync still *creates
173
210
  items* in catalog 2 — that is the original duplicate-item source, see the
174
211
  [two-catalog item model](../features/item-catalogs-and-duplicate-items.md).)
212
+ - **The reversal is NOT complete until the bundle/item cache is invalidated.** After `BundleItems`
213
+ was restored in the DB, new cust-2 checkouts kept POSTing the Agilant uuid because a **shared
214
+ server-side cache** (api2/`_underscore` response cache and/or a CDN in front of `/v2/bundles`)
215
+ still served the stale bundle — proven by two different users (SA136868, SA136874) getting the same
216
+ stale item after the DB fix. Sequence: fix data → **invalidate cache (front-end + api2/`_underscore`
217
+ + any CDN on `/v2/bundles`)** → confirm incoming `/v2/sales-orders` POSTs stop carrying the Agilant
218
+ uuid → **only then re-enable cron 2**. The fix surface is the DB bundle rows **plus** the serving
219
+ cache — never the frontend code.
175
220
  - **Never `UPDATE IGNORE` + delete-leftover for a catalog operation** — it permanently deletes
176
221
  collision rows and cannot be reversed. Use FK-checks-ON, fail-loud, single transaction.
177
222
 
@@ -207,6 +252,21 @@ catalog-1 items were folded into catalog-2 **AND** storefront/transmit depends o
207
252
  NULL-`assetType` order lines alone are **not** damage (Prudential and Quad show that as normal).
208
253
 
209
254
  ## Change history
255
+ - 2026-09-02 — **CRITICAL: restoring `BundleItems` in the DB was not enough — a stale shared bundle
256
+ cache kept minting bad orders.** After the DB bundle rows were restored (bundle 17 → 2157, 15 →
257
+ 2158), new cust-2 checkouts still POSTed the Agilant uuid: order SA136874 (13:03, user 83091) and
258
+ SA136868 (11:25) each carried the Agilant 2427 uuid on the incoming `/v2/sales-orders` while the DB
259
+ bundle already pointed at 2157. Two different users → a **shared server-side cache** (api2/
260
+ `_underscore` response cache and/or a CDN in front of `/v2/bundles`), not per-browser; the developer
261
+ invalidated the front-end cache to stop it. Added the rule that a fold reversal is incomplete until
262
+ the bundle/item cache is invalidated across every layer, and the operational order (fix data →
263
+ invalidate cache → confirm POSTs clean → only then re-enable cron 2). Extended the straggler cleanup
264
+ into the full by-id pattern for broken-window orders (re-point `SalesOrderItems.itemId`
265
+ Agilant-twin→Compass-twin, `PurchaseOrderItems.vendorItemId`+cost to the Compass VendorItem, clear
266
+ `PurchaseOrders.dtSubmitted` so cron 2 re-transmits): 2427→2157 / VI 3597 / SKU 5775600 / $945.17,
267
+ 2431→2158 / VI 3598 / SKU 7761063 / $945.17; PO VI 3845→3597 @945.17, 3884→3600 @1627.38; orders
268
+ fixed 50312344-1, 50312409-1, SA136868, SA136874 + the earlier 5 pending
269
+ (SA136819/820/845/852/862). (jcardinal)
210
270
  - 2026-09-02 — **Completed the reversal and root-caused the rest of the incident.** Recorded that
211
271
  the first reversal was **incomplete** — it restored `Items`/`VendorItems`/`VendorItemCosts` and
212
272
  re-pointed only `customerId = 2` `SalesOrderItems`, leaving **10 tables** folded (cust-1/cust-3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.741",
3
+ "version": "1.0.742",
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",