toga-ai 1.0.724 → 1.0.725

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.
@@ -111,13 +111,27 @@ duplicates** and must be deployed first — see
111
111
  - **`UPDATE IGNORE ...; DELETE ... WHERE fk=dupe` permanently DELETES collision rows** and drops its
112
112
  helper maps, so prod cannot self-reverse. A reversal needs a **pre-merge snapshot** restored as a
113
113
  scratch DB — plan the backup before running any variant of this.
114
- - **Blast radius of the 2026-08-31 `duplicate_items_merge_ALL_CLIENTS.sql`:** it ran on 17 clients
115
- (Masonite, Ncci, Erau, Shrss, Wmchealth, Trividiahealth, Prudential, Miamidade, Browardsheriff,
116
- Nychh, Canon, Quad, Compass, Elite, Growrk, Spglobal, Endeavorhealth). At-risk = two-catalog +
117
- TOGa Commerce clients like Compass; a **per-client assessment is outstanding**.
114
+ - **Blast radius of the 2026-08-31 `duplicate_items_merge_ALL_CLIENTS.sql` (assessment complete
115
+ 2026-09-01):** it ran on 17 clients (Masonite, Ncci, Erau, Shrss, Wmchealth, Trividiahealth,
116
+ Prudential, Miamidade, Browardsheriff, Nychh, Canon, Quad, Compass, Elite, Growrk, Spglobal,
117
+ Endeavorhealth). **Only 2 were damaged — Compass and Quad, both two-catalog TOGa Commerce
118
+ clients.** The other 15 needed no reversal: 13 single-catalog "Agilant"-only clients were a
119
+ legitimate within-catalog dedup, NYCHH mixed Etilize + NetSuite in one catalog (no fold
120
+ possible), and Prudential was cleared (single populated catalog; NULL `assetType` is its normal
121
+ state). Triage per client with `Catalogs` LEFT JOIN `Items` (empty catalogs still show) + the
122
+ pipeline signal (`c_etilizeProductId` = store vs `c_netsuiteInternalItemId` = Agilant); a client
123
+ is damaged only if it has a two-catalog store/procurement design AND catalog-1 was folded into
124
+ catalog-2 AND storefront/transmit depends on catalog-1. See the Compass
125
+ [catalog-fold reversal](../../../clients/compass-usa/workflows/catalog-fold-reversal.md) and
126
+ [Quad catalog-fold reversal](../../../clients/quad/workflows/catalog-fold-reversal.md).
118
127
 
119
128
  ## Change history
120
129
 
130
+ - 2026-09-01 — **Blast-radius assessment complete.** Of the 17 clients the merge ran on, only 2
131
+ were damaged — Compass and Quad (both two-catalog TOGa Commerce). The other 15 needed no
132
+ reversal (13 single-catalog "Agilant"-only = legitimate within-catalog dedup; NYCHH mixed
133
+ Etilize + NetSuite in one catalog; Prudential cleared — single populated catalog, NULL
134
+ assetType is normal). Added the durable triage method and linked the Quad reversal. (jcardinal)
121
135
  - 2026-09-01 — **⚠ Corrected the success claim.** "0 duplicate part numbers" is NOT a clean-run proof
122
136
  for a multi-catalog client. This merge is catalog-blind (groups on `UPPER(partNumber)` only), so for
123
137
  Compass it folded 199 intentional catalog-1 store items into their Agilant canonical, broke MITS
@@ -18,7 +18,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
18
18
 
19
19
  ## 2.0 framework
20
20
 
21
- - **_underscore** (_Underscore) _(framework core)_ — 73 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
21
+ - **_underscore** (_Underscore) _(framework core)_ — 75 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
22
22
  - **worker2** (Worker) — 58 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
23
23
  - **api2** (API) — 25 doc(s) → [2.0/apps/api2/INDEX.md](2.0/apps/api2/INDEX.md)
24
24
  - **dbchanges2** (Database Changes) _(framework core)_ — 15 doc(s) → [2.0/apps/dbchanges2/INDEX.md](2.0/apps/dbchanges2/INDEX.md)
@@ -95,19 +95,46 @@ damage.**
95
95
  - **Never `UPDATE IGNORE` + delete-leftover for a catalog operation** — it permanently deletes
96
96
  collision rows and cannot be reversed. Use FK-checks-ON, fail-loud, single transaction.
97
97
 
98
- ## Blast radius — other clients (OUTSTANDING)
98
+ ## Blast radius — other clients (ASSESSMENT COMPLETE)
99
99
 
100
100
  The `duplicate_items_merge_ALL_CLIENTS.sql` ran `USE Client_<X>` on **17 clients**: Masonite,
101
101
  Ncci, Erau, Shrss, Wmchealth, Trividiahealth, Prudential, Miamidade, Browardsheriff, Nychh,
102
102
  Canon, Quad, **Compass**, Elite, Growrk, Spglobal, Endeavorhealth.
103
103
 
104
- - **Not all are damaged.** The NYCHH run was a legitimate dedup.
105
- - **At-risk = clients with the two-catalog + TOGa Commerce setup like Compass.** A per-client
106
- assessment (customer-scoped, rehearsed) is **outstanding for a future session**.
104
+ **Verdict (assessment complete 2026-09-01): only 2 of 17 were damaged — Compass (reversed prior
105
+ session) and Quad. The other 15 needed no reversal.**
106
+
107
+ - **13 single-catalog "Agilant"-only clients** (Masonite, Ncci, Erau, Shrss, Wmchealth,
108
+ Trividiahealth, Miamidade, Browardsheriff, Canon, Elite, Growrk, Spglobal, Endeavorhealth):
109
+ the merge was a **legitimate within-catalog dedup** — no reversal needed.
110
+ - **NYCHH:** confirmed the legit-dedup pilot — one catalog "Agilant" mixing 221 Etilize +
111
+ NetSuite items in the **same** catalog, so no cross-catalog fold was possible.
112
+ - **Prudential: CLEARED** — all 50k+ order lines were always on its single populated "Agilant"
113
+ catalog; its "USA"/"India"/"Ireland" catalogs are empty placeholders; uniform NULL-`assetType`
114
+ is its **normal** state, not damage.
115
+ - **Quad: DAMAGED** — a two-catalog TOGa Commerce client like Compass, but the damage was
116
+ **storefront-only** (not an order-transmission outage). Reversed with a self-contained
117
+ sandbox-sourced patch. See the
118
+ [Quad catalog-fold reversal](../../quad/workflows/catalog-fold-reversal.md).
107
119
  - **Compass Canada was NOT damaged and is structurally immune** — it was not in the merge's
108
120
  client list, has a single catalog, and does not use NetSuite (so no dupe-item bug).
109
121
 
122
+ **Triage method (durable).** Per `Client_<X>`, compare `Catalogs` LEFT JOIN `Items` (so EMPTY
123
+ catalogs still show) with item counts per catalog plus the pipeline signal
124
+ (`c_etilizeProductId` = Etilize/store vs `c_netsuiteInternalItemId` = NetSuite/Agilant). A
125
+ client is **DAMAGED only if** it has an intentional two-catalog store/procurement design **AND**
126
+ catalog-1 items were folded into catalog-2 **AND** storefront/transmit depends on catalog-1.
127
+ NULL-`assetType` order lines alone are **not** damage (Prudential and Quad show that as normal).
128
+
110
129
  ## Change history
130
+ - 2026-09-01 — **Blast-radius assessment complete.** Resolved the outstanding per-client
131
+ assessment: only **2 of 17** clients were damaged — Compass (reversed prior session) and Quad
132
+ (storefront-only, reversed this session). The other 15 needed no reversal: 13 single-catalog
133
+ "Agilant"-only clients were a legitimate within-catalog dedup, NYCHH mixed Etilize + NetSuite
134
+ in one catalog (no fold possible), and Prudential was cleared (single populated catalog; NULL
135
+ assetType is its normal state). Added the durable triage method (Catalogs LEFT JOIN Items +
136
+ per-catalog pipeline signal) and the damaged-only test. See the
137
+ [Quad catalog-fold reversal](../../quad/workflows/catalog-fold-reversal.md). (jcardinal)
111
138
  - 2026-09-01 — Recorded the root cause of the Compass MITS outage: the ad-hoc cross-client
112
139
  `duplicate_items_merge_ALL_CLIENTS.sql` (2026-08-31 ~12:43) folded 199 Compass catalog-1
113
140
  store items into their Agilant canonical, producing MITS HTTP 400 (NULL assetType) and SQL
@@ -6,3 +6,4 @@
6
6
  | [Quad multi-currency item prices & vendor item costs](features/multi-currency-item-pricing.md) | 2.0 | Quad prices the **same item in several currencies** and costs the **same vendor item in the vendor's own currency**, so both listings must show a *set* of amoun | _underscore/Model/Quad/Item.php, _underscore/Model/Quad/VendorItem.php, toga2-supply/src/components/ui/CurrencyAmountLines.tsx, toga2-supply/src/pages/Items/api/itemsApi.ts, toga2-supply/src/pages/VendorItems/api/vendorItemsApi.ts, toga2-supply/src/pages/VendorItems/VendorItemsPage.tsx, dbchanges2/Client_Quad/2026-08-24 - Quad Multi Currency Item Pricing.sql, worker/crons/toga2/quad/Imports/import_items.php |
7
7
  | [Quad: PO + ASN email importer (import_po_and_asn.php)](features/po-asn-email-import.md) | 1.0 | Quad Graphics' supplier emails Purchase Order and Advance Shipping Notice CSVs into a monitored Microsoft 365 mailbox. | worker/crons/toga2/quad/import_po_and_asn.php |
8
8
  | [Quad Graphics](profile.md) | 2.0 | Quad Graphics is a TOGA 2.0 client on the `_underscore` platform, prod schema `Client_Quad`. | |
9
+ | [Quad Graphics — reversing the 30-item catalog fold (storefront-assortment recovery)](workflows/catalog-fold-reversal.md) | 2.0 | Quad is the **second and only other** client damaged by the 2026-08-31 catalog-blind `duplicate_items_merge_ALL_CLIENTS.sql`. | test/team/2.0 deployment/quad_catalog_fold_reversal.sql, test/team/2.0 deployment/duplicate_items_merge_ALL_CLIENTS.sql, worker/crons/toga2/quad/workflow/1_transmit_purchase_orders_to_vendors.php |
@@ -16,10 +16,11 @@ project: _Underscore
16
16
  client: quad
17
17
  type: profile
18
18
  status: active
19
- updated: 2026-08-26
19
+ updated: 2026-09-01
20
20
  owners: ["jcardinal", "bala", "apeterson", "ajean"]
21
21
  files: []
22
22
  related:
23
+ - ./workflows/catalog-fold-reversal.md
23
24
  - ./features/po-asn-email-import.md
24
25
  - ./features/enter-po-details-vendor-selection-ev12.md
25
26
  - ../../2.0/apps/_underscore/features/sales-order-po-number-sourcing.md
@@ -134,4 +135,11 @@ Client-specific DB change-sets live in `dbchanges2/Client_Quad/`.
134
135
  `acl['vendor-items']['navigation-edit-on-vendor-items']` (`Core.AclActions` id 7 on record 19);
135
136
  Quad had id 5 only. Granted id 7 to role 7 (Global Admin). UI gate only — record 19 already
136
137
  granted role 1 full CRUD.
138
+ - **Two-catalog TOGa Commerce client (like Compass).** Catalog 1 "Quad" = storefront (Etilize,
139
+ carries `assetType`); catalog 2 "Agilant" = procurement (NetSuite, NULL `assetType`). Unlike
140
+ Compass, the storefront customer `customerId = 8` has its **orders on Agilant by design**, so
141
+ the "Quad" catalog is display-only. This is why the 2026-08-31 catalog-blind merge damaged
142
+ Quad's **storefront only** (not orders/transmit), and Quad was the **only other client besides
143
+ Compass** that needed a reversal. See
144
+ [Quad catalog-fold reversal](./workflows/catalog-fold-reversal.md).
137
145
  - This profile is a starting point; expand as more Quad-specific behavior is captured.
@@ -0,0 +1,130 @@
1
+ ---
2
+ title: Quad Graphics — reversing the 30-item catalog fold (storefront-assortment recovery)
3
+ framework: "2.0"
4
+ project: _Underscore
5
+ client: quad
6
+ type: workflow
7
+ status: active
8
+ updated: 2026-09-01
9
+ owners: ["jcardinal"]
10
+ files:
11
+ - test/team/2.0 deployment/quad_catalog_fold_reversal.sql
12
+ - test/team/2.0 deployment/duplicate_items_merge_ALL_CLIENTS.sql
13
+ - worker/crons/toga2/quad/workflow/1_transmit_purchase_orders_to_vendors.php
14
+ related:
15
+ - ../../compass-usa/workflows/catalog-fold-reversal.md
16
+ - ../../compass-usa/features/item-catalogs-and-duplicate-items.md
17
+ - ../../../1.0/apps/worker/workflows/netsuite-duplicate-items-dedup.md
18
+ - ../profile.md
19
+ ---
20
+
21
+ ## Summary
22
+
23
+ Quad is the **second and only other** client damaged by the 2026-08-31 catalog-blind
24
+ `duplicate_items_merge_ALL_CLIENTS.sql`. Like Compass, Quad is a **two-catalog TOGa Commerce**
25
+ client, so the merge folded catalog-1 store items into their catalog-2 Agilant twins. But
26
+ **Quad's damage shape is different from Compass's** — it was **storefront-only**, not an
27
+ order-transmission outage. This workflow records the damage and the self-contained reversal.
28
+ See the [Compass catalog-fold reversal](../../compass-usa/workflows/catalog-fold-reversal.md)
29
+ for the shared playbook this refines.
30
+
31
+ ## Quad's catalog model (why the merge damaged it)
32
+
33
+ - **Catalog 1 "Quad"** — the storefront catalog. Etilize/store items, carries
34
+ `assetType`/classification.
35
+ - **Catalog 2 "Agilant"** — the procurement catalog. NetSuite items, **NULL `assetType`**.
36
+ - **`customerId = 8` IS the Quad storefront customer, but its ORDER LINES correctly resolve to
37
+ catalog-2 Agilant** (verified identical prod vs client-sandbox: ~8040 Agilant / 8 Quad on
38
+ both sides). So Quad's customer→catalog rule **differs from Compass**: the store customer's
39
+ *orders* live on Agilant; the "Quad" catalog is **storefront display**. This is why orders
40
+ were **not** damaged for Quad, unlike Compass (whose store customer belonged on catalog-1 and
41
+ whose MITS transmit broke).
42
+
43
+ ## What broke — storefront only
44
+
45
+ The merge deleted **30 catalog-1 "Quad" store items** (each had an Agilant `partNumber` twin)
46
+ and re-pointed their references onto **NULL-`assetType` Agilant** items. Corrupted storefront
47
+ references:
48
+
49
+ - **48** `AssortmentItems` tiles
50
+ - **1185** `ItemFeatures`
51
+ - **49** `ItemPrices`
52
+ - **79** `ItemImages`
53
+ - **32** `Personas_Items`
54
+ - **49** `VendorItems`
55
+ - **1** `SalesOrderItem`
56
+
57
+ **What did NOT break:**
58
+
59
+ - **Orders** — `customerId = 8` lines were already on Agilant by design (see catalog model).
60
+ - **PO → vendor transmit** (`worker/crons/toga2/quad/workflow/1_transmit_purchase_orders_to_vendors.php`)
61
+ — multi-vendor items went **DOWN 176 → 154** (the merge reduced them; no VendorItem fusion,
62
+ so no SQL 1242 exposure — contrast Compass).
63
+
64
+ **Source of truth for the correct state = a client-sandbox copy of `Client_Quad`** (id-space
65
+ aligned with prod, verified): 100% of `AssortmentItems` sit on catalog "Quad"; prod had 48
66
+ wrongly on Agilant. No recent prod backup existed.
67
+
68
+ ## The reversal (self-contained, sandbox-sourced)
69
+
70
+ Deliverable: `test/team/2.0 deployment/quad_catalog_fold_reversal.sql` — rehearsed,
71
+ CTO-reviewed (**AGREE**), applied to prod.
72
+
73
+ 1. **Reinsert the 30 deleted catalog-1 `Items` verbatim from the sandbox at their original
74
+ ids.** The patch is **self-contained** — no cross-DB references; the sandbox rows are
75
+ inlined.
76
+ 2. **Move the merge-relocated child rows back off the Agilant canonical** by one of two proven
77
+ mechanisms:
78
+ - **(a) Precise move by row `uuid`** — for tables whose canonical (Agilant) item
79
+ legitimately keeps its **own** native/sibling rows: `ItemImages`, `VendorItems`,
80
+ `SalesOrderItems`, and (after CTO review) `AssortmentItems`, `ItemPrices`,
81
+ `Personas_Items`. Moving by uuid touches only the rows that were actually relocated.
82
+ - **(b) Map-move** (`itemId` canon→dupe via a dupe→canon map) — used **ONLY for
83
+ `ItemFeatures`**, safe by a data-model invariant: **nothing writes `ItemFeatures` onto
84
+ catalog-2 items** (the Etilize feed targets catalog-1; NetSuite creates catalog-2 items
85
+ with no features; the sync is stopped; sandbox canon-native `ItemFeatures` = 0).
86
+ - **`VendorItemCosts` ride along unchanged** (VendorItems are moved, not deleted).
87
+
88
+ ## Safety model (refines the Compass playbook)
89
+
90
+ - **Single transaction, `FOREIGN_KEY_CHECKS = 1`, NO `UPDATE IGNORE`, `COMMIT` left
91
+ commented.**
92
+ - **8 fail-loud CASE-based guards** — abort via a subquery-returns-row → forced error 1242.
93
+ - **Row-count-conservation guards** using pre-run `@vars`.
94
+ - **A preflight PK-absence guard.**
95
+ - **Rehearsed on a LOCAL `Client_Quad` freshly restored from prod** — repeatable because the
96
+ commented `COMMIT` + rollback-on-disconnect leaves the DB unchanged.
97
+ - **Perturbation-tested** — pre-inserted a restore id and confirmed the preflight guard aborts.
98
+ - **CTO review drove the hardening** of the four blind guards from count-equality to
99
+ identity-based uuid moves.
100
+
101
+ ## Critical rules / gotchas
102
+
103
+ - **NULL `assetType` on order lines ALONE is NOT proof of catalog-fold damage.** Quad (and
104
+ Prudential) show 100% NULL-`assetType` Agilant order lines as their **normal** state. Damage
105
+ requires the two-catalog store/procurement split **AND** storefront/transmit dependence on
106
+ catalog-1.
107
+ - **The merge's damage is client-specific in SHAPE.** Compass = order-transmission break (MITS
108
+ HTTP 400 / SQL 1242); Quad = storefront-assortment corruption only. **Assess each client's
109
+ actual dependency; do not assume Compass's failure mode.**
110
+ - **MySQL reversal/rehearsal mechanics:**
111
+ - Temp-table `uuid` columns need `COLLATE utf8mb4_unicode_ci` (or an explicit COLLATE on the
112
+ join) to match the real tables.
113
+ - A `TEMPORARY` table **cannot be referenced twice in one query** — inline id-lists in guards
114
+ instead.
115
+ - A `QUOTE()`-generated multi-row `INSERT` can **silently drop a trailing field** for rows
116
+ with several trailing NULLs — **validate field counts before running.**
117
+
118
+ ## Change history
119
+
120
+ - 2026-09-01 — Recorded Quad as the second (and only other) client damaged by the catalog-blind
121
+ `duplicate_items_merge_ALL_CLIENTS.sql`. Documented Quad's two-catalog model (store customer
122
+ `customerId=8` orders live on Agilant by design, so orders were NOT damaged — unlike Compass),
123
+ the storefront-only damage (30 deleted catalog-1 items; 48 AssortmentItems / 1185 ItemFeatures
124
+ / 49 ItemPrices / 79 ItemImages / 32 Personas_Items / 49 VendorItems / 1 SalesOrderItem
125
+ re-pointed onto NULL-assetType Agilant), and the self-contained sandbox-sourced reversal
126
+ (`quad_catalog_fold_reversal.sql`): reinsert 30 items verbatim at original ids, then move child
127
+ rows back by uuid (precise) or by map (ItemFeatures only, safe by the no-features-on-catalog-2
128
+ invariant). Safety model: single transaction, FK-checks ON, no UPDATE IGNORE, 8 fail-loud CASE
129
+ guards, count-conservation guards, preflight PK guard; rehearsed on a prod-restored local,
130
+ perturbation-tested, CTO-reviewed AGREE. (jcardinal)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.724",
3
+ "version": "1.0.725",
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",