toga-ai 1.0.606 → 1.0.608

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
@@ -0,0 +1,61 @@
1
+ ---
2
+ type: session
3
+ slug: table-cell-actions-surface
4
+ title: Table cell/row actions — settle surface-layer design
5
+ author: apeterson
6
+ repos: [dbchanges2, api2, toga25-supply]
7
+ framework: "2.0"
8
+ client: elite
9
+ status: active
10
+ created: 2026-08-18
11
+ updated: 2026-08-18
12
+ ---
13
+
14
+ # Session: table-cell-actions-surface
15
+ **Date:** 2026-08-18
16
+ **Project/Repo:** dbchanges2 / api2 / toga25-supply (2.0)
17
+ **Task:** Recover the settled design for moving table cell/row actions (e.g. Elite's "See units" chevron) into the surface layer so per-client visibility (Elite off, NYCHH on) is a surface override — and clean up the stale first-attempt migration.
18
+
19
+ ---
20
+
21
+ ## What WORKED
22
+ - Located the original design conversation: **api2 session `e761c825-6073-40fc-ab0f-a984bca7f770`** (Aug 13, 2026, `surface-layer` branch). Transcript at `~/.claude/projects/-Applications-XAMPP-xamppfiles-htdocs-api2/e761c825-6073-40fc-ab0f-a984bca7f770.jsonl` (1076 lines, 3.2MB).
23
+ - Extracted the full plan/decision text verbatim via a general-purpose subagent (raw dump saved at `scratchpad/dump.txt` in the api2 session scratchpad). The settled design is captured in this session's Decisions section.
24
+ - Confirmed current on-disk SQL state in `dbchanges2`: **no Phase 1/Phase 3 SQL for the final plan exists yet**; grep for `ROW_ACTIONS` only hit unrelated Core seeds (SalesOrder login surface, PO details row-action menu item 2026-08-18a).
25
+ - **Deleted the stale migration** `dbchanges2/Client_Elite/2026-08-14a - InventoryUnitsByItemsRemoveUnitsDrill.sql` (the rejected drop-the-grouping-level approach). Shows as staged deletion (`D`) in git — NOT yet committed.
26
+
27
+ ## What did NOT work — DO NOT RETRY THESE
28
+ These are the mechanisms explicitly rejected in the e761c825 design thread. Do not re-propose them:
29
+ - **Dropping the `inventory_units` grouping level** from Elite's `unitsByItems` CONFIG override (the shipped `2026-08-14a` migration). Reason: destroys the nested-table definition instead of just hiding the button; wrong mechanism. This file was deleted this session.
30
+ - **Per-field `is*` boolean flags** (`isNestedTableEnabled`, `isRowActionEnabled`, `isCellActionEnabled`) on `TableViews`. Reason: wrong grain — a drill/action is not a field capability like isSortable; and it would duplicate the existing `childTableViewId`.
31
+ - **A new dedicated binding table** (`TableViewCellActions` / `TableViewFieldActions`). Reason: label/icon/style/visibility/ACL/per-client overrides is *the surface layer's entire job* — a parallel table duplicates `SurfaceElements` + `SurfaceOverrides`.
32
+ - **Table-meta `actions[]` array with numeric `surfaceElementId` pointers** (the `surfaceElementId: 412` sketch). Reason: superseded once the schema explore found `Surface.type=ROW_ACTIONS` + `Surface.tableViewId` + `SurfaceElement.recordFieldId`/`actionId` already bind everything natively. Also numeric id is wrong key — emitted element key is the `uuid`.
33
+
34
+ ## Not tried yet (candidates for next session)
35
+ - **Phase 1 SQL** — seed a `ROW_ACTIONS` surface for `inventory_units` (`Core.Surfaces` `type=ROW_ACTIONS`, `tableViewId=<inventory_units view>`) + a "See units" BUTTON `SurfaceElement` (labelMessageId, `iconToken=chevronsRight`, an `actionId` for a nested-table action, anchored to its column).
36
+ - **Phase 2 FE** — cell-action renderer in `toga25-supply`/`toga-blox`: fetch the table's `ROW_ACTIONS` surface, render each element as a cell action, wire behavior via `actionRegistry` (add nested-table/route/modal handlers), replace hardcoded `makeSeeUnitsColumns`. Injection point: `useGenericTableViewModel.tsx:36-63` meta memo → `actionColumns`.
37
+ - **Phase 3 Elite** — one `SurfaceOverride` row `isVisible=0` on the "See units" element for Elite.
38
+ - **CTO second opinion** — recommended in the original thread, never run.
39
+ - **Verify whether deleted `2026-08-14a` was already applied to sandbox** — if so, DB state still has the drill dropped; may need the Phase work (or an interim revert) to restore.
40
+
41
+ ## Current file state
42
+ | File | Status | Notes |
43
+ |------|--------|-------|
44
+ | `dbchanges2/Client_Elite/2026-08-14a - InventoryUnitsByItemsRemoveUnitsDrill.sql` | Deleted (staged, uncommitted) | Rejected drop-the-grouping-level approach; removed per final design |
45
+ | `scratchpad/dump.txt` (api2 session scratchpad) | Created | Raw verbatim extraction of the e761c825 design thread |
46
+
47
+ ## Decisions made
48
+ - **Surface layer owns cell/row actions** — not a new table, not FE hardcoding. The button (label, icon, style, visibility, enablement, ACL, per-client/role/persona overrides) is a `SurfaceElement` on a `type=ROW_ACTIONS` Surface linked to the table via `Surface.tableViewId`. Rationale: the surface layer already models all of this; a parallel mechanism duplicates it. Vindicates the original "this is surface-layer" instinct — only earlier mechanisms were wrong.
49
+ - **Grain rule:** table-level toggles → table block; per-cell action presentation → surface element bound to a field (`recordFieldId`/`customRecordFieldId`). Cell action (chevron) and row action (row-click → modal) are conceptually independent (today wrongly coupled at `GenericNestedTables.tsx:37-42`).
50
+ - **Elite vs NYCHH gating** = one `SurfaceOverride` `isVisible=0` on the "See units" element scoped to Elite; element stays visible for NYCHH/others on the same shared table.
51
+ - **Cross-DB binding** (Core surface ↔ Client table view) uses **soft integer FKs** — framework FK traversal can't cross Core↔Client. Stable FE-facing key is the SurfaceElement **uuid**, not numeric id. CONFIG override REPLACES (does not merge).
52
+ - **Two open questions to settle before seeding:** (1) how FE finds a table's ROW_ACTIONS surface — lean **slug convention** `<tableViewSlug>-row-actions` over `tableViewId` query; (2) how element anchors to a column — lean **column-slug in element `config`** over `recordFieldId`.
53
+
54
+ ## Blockers
55
+ - None hard. Soft: the two open questions above should be settled before writing Phase 1 SQL; and confirm whether `2026-08-14a` was already applied to sandbox before assuming Elite DB is clean.
56
+
57
+ ## Exact next step
58
+ > Settle the two open questions (slug-convention lookup + column-slug-in-config anchor), then write **Phase 1 SQL**: a `Core/` migration seeding the `inventory_units` `ROW_ACTIONS` surface + "See units" BUTTON `SurfaceElement`. Check first whether deleted `2026-08-14a` was applied to sandbox.
59
+
60
+ ---
61
+ _Saved by /session-save on 2026-08-18_
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.606",
3
+ "version": "1.0.608",
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",