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>
|
package/knowledge/INDEX.md
CHANGED
|
@@ -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) —
|
|
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-
|
|
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
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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