toga-ai 1.0.606 → 1.0.607

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.
@@ -5,6 +5,7 @@
5
5
  | [Test (test) Architecture](architecture.md) | `test` (project **Test**) is a **repository of ad-hoc developer scripts** — not a deployed application. | test/team/ |
6
6
  | [2.0 Deployment — Per-Client SQL Generator](features/2-0-deployment-client-sql.md) | `team/2.0 deployment/generate_client_sql.php` fans a single SQL change-set out across **all 2.0 client databases**. | test/team/2.0 deployment/generate_client_sql.php, test/team/2.0 deployment/Clients_Db.txt, test/team/2.0 deployment/Client.sql |
7
7
  | [Active Directory Authentication Test](features/active-directory-auth-test.md) | `team/active_directory_authentication_test.php` is an interactive CLI tool to test **Active Directory authentication**. | test/team/active_directory_authentication_test.php |
8
+ | [Compass retrofix2 — Retroactive Data-Fix SQL Generator](features/compass-retrofix2-sql-generator.md) | `@jeff/compass/retrofix2.php` is a standalone **1.0 `App_`** script that retroactively repairs historical Compass USA (`Client_Compass`, 2.0) order data left in | test/@jeff/compass/retrofix2.php |
8
9
  | [Create Elastic Beanstalk Environment (script)](features/create-elastic-beanstalk.md) | `team/aws/create_elastic_beanstalk.php` is a **standalone** (no `App_` framework) constants-driven PHP generator. | test/team/aws/create_elastic_beanstalk.php |
9
10
  | [Developer Generators (password, UUID)](features/dev-generators.md) | Two tiny **1.0 `App_` framework** convenience scripts for everyday developer needs. | test/team/generate_password.php, test/team/uuid.php |
10
11
  | [Forecast vs NetSuite Discrepancy Analysis](features/forecast-netsuite-discrepancy-analysis.md) | `team/forecast-netsuite/discrepancy_analysis.php` detects discrepancies between our **Forecast database** and **NetSuite** (the source of truth for all sales da | test/team/forecast-netsuite/discrepancy_analysis.php |
@@ -0,0 +1,102 @@
1
+ ---
2
+ title: Compass retrofix2 — Retroactive Data-Fix SQL Generator
3
+ framework: "1.0"
4
+ repo: test
5
+ project: Test
6
+ client: shared
7
+ type: feature
8
+ status: active
9
+ updated: 2026-08-18
10
+ owners: [jcardinal]
11
+ files:
12
+ - test/@jeff/compass/retrofix2.php
13
+ related:
14
+ - ../architecture.md
15
+ - ../../../clients/compass-usa/workflows/order-lifecycle-and-data-integrity.md
16
+ - ../../../clients/compass-usa/features/mits-po-to-so-item-linking.md
17
+ ---
18
+
19
+ ## Summary
20
+
21
+ `@jeff/compass/retrofix2.php` is a standalone **1.0 `App_`** script that retroactively repairs
22
+ historical Compass USA (`Client_Compass`, 2.0) order data left in the wrong shape by 50+ past bugs.
23
+ It **emits review-first `.sql`** — it never writes the DB directly. It supersedes the older sibling
24
+ `retrofix.php` in the same folder (that one is superseded/kept only for reference). The domain facts
25
+ it repairs against (the supply chain, item-link bridges, both fulfillment flows, over-fulfill cap)
26
+ live in the Compass
27
+ [order-lifecycle & data-integrity workflow](../../../clients/compass-usa/workflows/order-lifecycle-and-data-integrity.md);
28
+ this doc covers the **script's structure**.
29
+
30
+ ## How it works
31
+
32
+ `processOrder()` runs three phases per Compass SO, newest-first. **Phase ordering is load-bearing:
33
+ Phase 0 must run before Phase 1/2** because units are **shared up the chain** (the same `Units.id`
34
+ at every level), so unit corrections must land before Phase 2 mirrors fulfillments upward.
35
+
36
+ ### Phase 0 — CG-unit asset-tag merge (new)
37
+ Reproduces retroactively what the forward fix does at `library/app/api/toga2.php` (~lines 3688–3965):
38
+ NetSuite delivers asset tags on **separate service-item lines** whose part number contains
39
+ `ASSETTAG` (e.g. `ODP-COMPASS-ASSETTAG1`); older Compass imports landed each asset tag as its **own
40
+ `Units` row** whose `serialNumber` holds the CG value (e.g. `CG2000027730`), attached via
41
+ `ItemFulfillmentItemUnits` alongside the real serialized unit on the same fulfillment. Phase 0 folds
42
+ each duplicate CG unit into its real device.
43
+
44
+ Per fulfillment, order the IFIU-attached units by `ItemFulfillmentItemUnits.id` and split into CG
45
+ (serial starts `CG`) vs real (non-CG serialized), then:
46
+ - **1:1** → merge (≈17,500 fulfillments).
47
+ - **equal N:N** → order-pair and emit a `REVIEW` comment (≈7).
48
+ - **unequal, or zero real units** → logged and skipped (≈184).
49
+
50
+ Each merge emits, in order:
51
+ 1. `UPDATE Units SET assetTag = <CG serial>` on the real unit — **only if empty; never clobbers a
52
+ different existing tag**.
53
+ 2. Repoint `InventoryAdjustmentItemUnits.unitId` CG→real (decided: **repoint, not delete**, to
54
+ preserve stock history — 14,249 CG units have inventory-adjustment rows).
55
+ 3. Delete the CG unit's `ItemFulfillmentItemUnits` rows (and their `..._TrackingNumbers` bridges).
56
+ 4. `DELETE` the CG unit.
57
+
58
+ Scope: **IFIU-attached CG units only** (per developer). DB facts at time of build: 22,288 total
59
+ CG-serial units, none with `assetTag` set; 19,214 attached to an IFIU.
60
+
61
+ ### Phase 1 — header/link/bridge repairs (levels L1–L4)
62
+ Repairs the supply-chain header chain and the item-link bridges. Levels:
63
+ - **L1** `repairOdpPoToAgilantSoLinks` — **always calls NetSuite** (`buildNetsuiteGroupMap`), even
64
+ when the L1 links already exist.
65
+ - **L2/L3/L4** — NetSuite-free bridge repairs. **L3** repairs the
66
+ `PurchaseOrderItems_SalesOrderItems` rung (MITS PO item → ODP SO item) that the Flow-B recursive
67
+ IF mirror depends on.
68
+
69
+ ### Phase 2 — fulfillment mirror climb
70
+ Walks each source ItemFulfillment up the chain (Agilant → ODP → Compass), creating the mirror IFs.
71
+
72
+ ## Level isolation — `runLevel()`
73
+
74
+ Originally Phase 1 ran L1→L4 with **no isolation**. Because L1 unconditionally calls NetSuite, a
75
+ NetSuite SSL/SOAP failure there threw, `main()`'s catch marked the **whole order FAILED**, and the
76
+ independent NetSuite-free L2/L3/L4 repairs (including the L3 rung Phase 2 needs) were skipped — even
77
+ though L1 usually had nothing to insert (the affected orders' Agilant SOIs were already fully linked,
78
+ so the NetSuite call was pure overhead/risk).
79
+
80
+ `runLevel()` wraps each Phase-1 level (and each Phase-2 source-IF climb) so **a level's exception is
81
+ logged as a skip and swallowed**, letting the remaining independent levels still emit. This is the
82
+ core reliability fix: independent repairs no longer share a failure fate with L1's external call.
83
+
84
+ ## Write guards — `emit()` vs `emitUnit()`
85
+
86
+ - `emit()` — the default SQL sink; **hard-blocks any write to the `Units` and `TrackingNumbers`
87
+ tables**.
88
+ - `emitUnit()` — a narrow helper for the Phase-0 units track that **permits `Units` UPDATE/DELETE
89
+ but still blocks `TrackingNumbers`**. This is a deliberate, scoped exemption to the
90
+ never-write-`Units` guard, used only by Phase 0.
91
+
92
+ Never emit writes to `TrackingNumbers`; existing tracking rows are only ever linked, never created
93
+ (consistent with the Compass workflow invariants).
94
+
95
+ ## Change history
96
+ - 2026-08-18 — Initial doc. Recorded retrofix2.php's Phase 0/1/2 structure, the new **Phase 0
97
+ CG-unit asset-tag merge** (merge/order-pair/skip cases, the 4 emitted statements, repoint-not-delete
98
+ for inventory history), the **`runLevel()` level isolation** fix (L1's unconditional NetSuite call
99
+ no longer fails the whole order and skips the L2/L3/L4 bridge repairs), and the scoped **`emitUnit()`**
100
+ exemption to the never-write-Units guard. (jcardinal)
101
+ </content>
102
+ </invoke>
@@ -12,7 +12,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
12
12
  - **togaview** (TOGa View) — 7 doc(s) → [1.0/apps/togaview/INDEX.md](1.0/apps/togaview/INDEX.md)
13
13
  - **webhook** (Webhook) — 1 doc(s) → [1.0/apps/webhook/INDEX.md](1.0/apps/webhook/INDEX.md)
14
14
  - **walmarttechservices** (Walmart Tech Services) — 1 doc(s) → [1.0/apps/walmarttechservices/INDEX.md](1.0/apps/walmarttechservices/INDEX.md)
15
- - **test** (Test) — 14 doc(s) → [1.0/apps/test/INDEX.md](1.0/apps/test/INDEX.md)
15
+ - **test** (Test) — 15 doc(s) → [1.0/apps/test/INDEX.md](1.0/apps/test/INDEX.md)
16
16
  - **toga** (TOGa) — 3 doc(s) → [1.0/apps/toga/INDEX.md](1.0/apps/toga/INDEX.md)
17
17
  - **tools** (Tools) — 15 doc(s) → [1.0/apps/tools/INDEX.md](1.0/apps/tools/INDEX.md)
18
18
 
@@ -5,10 +5,11 @@ project: _Underscore
5
5
  client: compass-usa
6
6
  type: workflow
7
7
  status: active
8
- updated: 2026-08-04
8
+ updated: 2026-08-18
9
9
  owners: ["jcardinal", "bala", "dfranks"]
10
10
  files: []
11
11
  related:
12
+ - 1.0/apps/test/features/compass-retrofix2-sql-generator.md
12
13
  - clients/compass-usa/profile.md
13
14
  - clients/compass-usa/features/asn-to-item-fulfillment.md
14
15
  - clients/compass-usa/features/mits-po-to-so-item-linking.md
@@ -71,6 +72,27 @@ back-link chain climbs **Agilant → ODP → Compass**. Item back-links use
71
72
  `ItemFulfillmentItems.upstreamItemFulfillmentItemId` the same direction and may be many-downstream →
72
73
  one-upstream for bundles.
73
74
 
75
+ > **Mirror-gap root cause — a missing item bridge stalls the climb (verified 2026-08-18).** The
76
+ > recursive IF mirror climbs Agilant → ODP → Compass through **BOTH** bridge tables. If the
77
+ > `PurchaseOrderItems_SalesOrderItems` rung linking the Compass/MITS PO item → the ODP SO item is
78
+ > **missing**, the mirror **cannot map past the ODP SO** and never creates the ODP/Compass mirror IFs
79
+ > — the Compass SO shows "nothing fulfilled" even though the Agilant SO has an ItemFulfillment
80
+ > (`c_netsuiteInternalItemFulfillmentId` set, created by NetSuite sync). Orders SA130530, SA130334,
81
+ > SA130430 all had an intact header chain and every other item bridge, but were missing **only** that
82
+ > one rung (confirmed against a healthy order that had it). When diagnosing a Flow-B order that
83
+ > fulfilled upstream but shows empty on Compass, check that specific bridge first.
84
+
85
+ ### Asset tags arrive as separate CG "units" (Flow B)
86
+ NetSuite delivers asset tags on **separate service-item lines** whose part number contains
87
+ `ASSETTAG` (e.g. `ODP-COMPASS-ASSETTAG1`). Older Compass imports landed each asset tag as its **own
88
+ `Units` row** whose `serialNumber` holds the CG value (e.g. `CG2000027730`), attached via
89
+ `ItemFulfillmentItemUnits` alongside the real serialized unit on the **same** fulfillment. The
90
+ forward fix (`library/app/api/toga2.php` ~lines 3688–3965) applies those asset tags to the serialized
91
+ items **in order** and sets `Units.assetTag` on the real device. Retroactively this is Phase 0 of the
92
+ [retrofix2 tool](../../../1.0/apps/test/features/compass-retrofix2-sql-generator.md); because units
93
+ are **shared up the chain** (same `Units.id` at every level), the correction must land before the
94
+ fulfillment mirror climbs.
95
+
74
96
  ## Expected raw-data invariants (for detect-and-repair)
75
97
 
76
98
  1. **Links:** every SOI that should be procured has exactly one PURE bridge to the matching POI on the
@@ -141,12 +163,18 @@ column is `ON UPDATE CURRENT_TIMESTAMP`), which can look like a fresh modificati
141
163
  `api2` cXML ShipNotice handler; the `_underscore` recursive item-fulfillment engine.
142
164
 
143
165
  ## Retrofix tooling
144
- A standalone repair script lives in the worker 1.0 test area (`test/@jeff/compass/retrofix.php`,
145
- machine-local path tracked in dev memory). It sweeps Compass SOs newest-first, detects deviations from
146
- the invariants above, and repairs via direct SQL on `db_prod2_compass`. Safety rules baked in: rehearsal
147
- mode (logs intended writes, rolls back), per-phase gating, a hard block on any write to the
148
- `TrackingNumbers` table, and the never-over-fulfill cap. It is a diagnostic/repair tool, not part of the
149
- runtime workflow.
166
+ The current repair script is **`test/@jeff/compass/retrofix2.php`** (1.0 `App_`), which
167
+ **supersedes** the older `retrofix.php` sibling in the same folder. Unlike the description below of the
168
+ earlier tool, retrofix2 **emits review-first `.sql`** rather than writing the DB directly. It runs
169
+ three phases newest-first per SO — **Phase 0** (CG-unit asset-tag merge; must run first because units
170
+ are shared up the chain), **Phase 1** (header/link/bridge repairs, levels L1–L4, where L3 fixes the
171
+ `PurchaseOrderItems_SalesOrderItems` rung the mirror needs), **Phase 2** (fulfillment mirror climb).
172
+ Each level is wrapped in `runLevel()` so one level's exception (notably L1's unconditional NetSuite
173
+ call failing) is logged as a skip and swallowed, letting the independent NetSuite-free repairs still
174
+ emit. Write guards: `emit()` hard-blocks `Units` and `TrackingNumbers` writes; the Phase-0-only
175
+ `emitUnit()` permits `Units` UPDATE/DELETE but still blocks `TrackingNumbers`. Full structure in the
176
+ [retrofix2 feature doc](../../../1.0/apps/test/features/compass-retrofix2-sql-generator.md). It is a
177
+ diagnostic/repair tool, not part of the runtime workflow.
150
178
 
151
179
  ## Edge cases & escalation
152
180
  - Incomplete orders (no PO/ASN/Agilant leg yet) are normal — repair only the layers that exist.
@@ -155,6 +183,12 @@ runtime workflow.
155
183
  - High-multiplier over-fulfillment (5×–20×) does not fit the split-PO spurious-link pattern — separate cause.
156
184
 
157
185
  ## Change history
186
+ - 2026-08-18 — Recorded the **Flow-B mirror-gap root cause** (a missing `PurchaseOrderItems_SalesOrderItems`
187
+ rung stalls the recursive IF mirror past the ODP SO, so a fulfilled Agilant order shows empty on
188
+ Compass — orders SA130530/SA130334/SA130430), the **CG asset-tag "unit" data shape** (asset tags land
189
+ as their own CG-serial `Units` rows), and repointed the Retrofix tooling section to the new
190
+ **retrofix2.php** (review-first `.sql`; Phase 0/1/2; `runLevel()` level isolation; `emit()`/`emitUnit()`
191
+ write guards). (jcardinal)
158
192
  - 2026-08-04 — Added the **"empty shell" order signature** — the ODP importer writes the SO header
159
193
  and its items in two separate API requests, so a fatal on the second leaves a committed,
160
194
  zero-item order — plus the three orphan sweeps that detect it (zero-item SOs, zero-item POs, ODP
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.606",
3
+ "version": "1.0.607",
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",