toga-ai 1.0.64 → 1.0.65

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.
@@ -4,3 +4,4 @@
4
4
  |-----|---------|-------|
5
5
  | [Worker (1.0 Framework) Architecture](architecture.md) | `worker` is the legacy (**1.0** `App_` framework) **background-job tier**. | worker/index.php, worker/_/app/framework.php, worker/crons/, worker/schedules/, worker/ebs/cron.worker.php, worker/.ebextensions/035_cron.worker.config |
6
6
  | [Forecast2 ↔ NetSuite Reconciliation & Trueup Tooling](features/forecast2-netsuite-reconciliation.md) | CLI tools to **audit** and **repair** drift between the production `Forecast` DB (core2) and NetSuite. | test/@dave/reconcile_netsuite_totals.php, test/@dave/analyze_netsuite_forecast_diff.php, test/@dave/trueup_sales.php, test/@dave/trueup_open_orders.php, test/@dave/trueup_opportunities.php, test/@dave/probe_sales_gap_direct.php, worker/crons/toga2/forecast2/common_import_sales_from_netsuite.php |
7
+ | [Prudential: Send Shipments for the Day report (daily cron)](features/send-shipments-for-the-day.md) | Daily cron (9:00 PM) that emails Prudential and Dell stakeholders an Excel report of all devices shipped that day, including tracking number, serial number, emp | worker/crons/notifications/reports/send_shipments_for_the_day.php |
@@ -0,0 +1,65 @@
1
+ ---
2
+ title: "Prudential: Send Shipments for the Day report (daily cron)"
3
+ framework: "1.0"
4
+ repo: worker
5
+ project: Worker
6
+ client: prudential
7
+ type: feature
8
+ status: active
9
+ updated: 2026-06-12
10
+ owners: ["rgirish"]
11
+ files:
12
+ - worker/crons/notifications/reports/send_shipments_for_the_day.php
13
+ related:
14
+ - ../../../clients/prudential/features/dell-asn-units-interceptor.md
15
+ ---
16
+
17
+ ## Summary
18
+
19
+ Daily cron (9:00 PM) that emails Prudential and Dell stakeholders an Excel report of all
20
+ devices shipped that day, including tracking number, serial number, employee name/XID, item
21
+ description, FedEx status, and vendor.
22
+
23
+ ## Key files / entry points
24
+
25
+ - `crons/notifications/reports/send_shipments_for_the_day.php` — self-contained cron script.
26
+ Scheduled via `schedules/cron.worker.notification.json`.
27
+
28
+ ## How it works
29
+
30
+ 1. Queries `Client_Prudential` DB joining `AdvanceShippingNotices` → items → units → tracking
31
+ bridge → `TrackingNumbers` → `Units` → `Items` → `Contacts`, filtered to `dateShipped = CURDATE()`.
32
+ 2. For each unit, calls `App_Api_Carrier_FedExApi::getStatus()` to get live carrier status.
33
+ 3. Builds an `.xlsx` workbook (PhpSpreadsheet) with 8 columns: Name, Employee XID, Device Serial
34
+ Number, Description, Tracking Number, Tracking Number Status, Shipping Carrier Updates, Vendor Name.
35
+ 4. Emails the file to Prudential/Dell contacts + BCC to internal ops.
36
+ 5. If no shipments found, sends a "No Shipments for the Day" notification instead.
37
+
38
+ ## Data model (join chain)
39
+
40
+ ```
41
+ AdvanceShippingNotices
42
+ → AdvanceShippingNoticeItems (advanceShippingNoticeId)
43
+ → PurchaseOrders (AdvanceShippingNotices.purchaseOrderId)
44
+ → SalesOrders_PurchaseOrders (purchaseOrderId)
45
+ → SalesOrders (salesOrderId)
46
+ → Vendors (PurchaseOrders.vendorId)
47
+ → AdvanceShippingNoticeItemUnits (advanceShippingNoticeItemId)
48
+ → AdvanceShippingNoticeItemUnits_TrackingNumbers (advanceShippingNoticeItemUnitId)
49
+ → TrackingNumbers (trackingNumberId)
50
+ → Units (AdvanceShippingNoticeItemUnits.unitId)
51
+ → Items (Units.itemId)
52
+ LEFT JOIN Contacts (SalesOrders.contactId)
53
+ ```
54
+
55
+ ## Gotchas
56
+ - The join chain changed in Jun 2026 when `AdvanceShippingNoticeUnits` was renamed to
57
+ `AdvanceShippingNoticeItemUnits` and tracking was moved to the bridge table
58
+ `AdvanceShippingNoticeItemUnits_TrackingNumbers`. If the query returns no rows unexpectedly,
59
+ verify these two tables exist and have data — they are the migration point.
60
+ - `GROUP BY AdvanceShippingNotices.id` is intentional — one row per ASN even if multi-unit.
61
+ The report shows one tracking number per ASN row (the first joined); this is by design.
62
+
63
+ ## Change history
64
+ - 2026-06-12 — Updated join chain: `AdvanceShippingNoticeUnits` → `AdvanceShippingNoticeItemUnits`
65
+ + added `AdvanceShippingNoticeItemUnits_TrackingNumbers` bridge join after DB migration. (rgirish)
@@ -5,7 +5,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
5
5
  ## 1.0 framework
6
6
 
7
7
  - **library** (Library) _(framework core)_ — 4 doc(s) → [1.0/apps/library/INDEX.md](1.0/apps/library/INDEX.md)
8
- - **worker** (Worker) — 3 doc(s) → [1.0/apps/worker/INDEX.md](1.0/apps/worker/INDEX.md)
8
+ - **worker** (Worker) — 4 doc(s) → [1.0/apps/worker/INDEX.md](1.0/apps/worker/INDEX.md)
9
9
 
10
10
  ## 2.0 framework
11
11
 
@@ -4,3 +4,4 @@
4
4
  |-----|-----------|---------|-------|
5
5
  | [Prudential: Dell ASN units PRE/POST interceptor (legacy key + flat tracking)](features/dell-asn-units-interceptor.md) | 2.0 | After the tracking-number bridge migration, the ASN unit route was renamed (`advance-shipping-notice-units` → `advance-shipping-notice-item-units`), so the inhe | _underscore/Model/Prudential/AdvanceShippingNotice.php, dbchanges2/Client_Prudential/2026-06-10 - AsnUnitsInterceptor.sql |
6
6
  | [Prudential Financial](profile.md) | 2.0 | Prudential is a TOGA client whose device-fulfillment flow is driven by **Dell** via the Dell API (`Client_Prudential.Apis.id = 2`). | |
7
+ | [Prudential: Dell ASN failed POST backfill replay](workflows/dell-asn-backfill-replay.md) | 2.0 | When Dell ASN POSTs fail in bulk (e.g. | |
@@ -5,8 +5,8 @@ project: _Underscore
5
5
  client: prudential
6
6
  type: client-feature
7
7
  status: active
8
- updated: 2026-06-10
9
- owners: ["jcardinal"]
8
+ updated: 2026-06-12
9
+ owners: ["jcardinal", "rgirish"]
10
10
  files:
11
11
  - _underscore/Model/Prudential/AdvanceShippingNotice.php
12
12
  - dbchanges2/Client_Prudential/2026-06-10 - AsnUnitsInterceptor.sql
@@ -28,7 +28,9 @@ interceptor translates it on the way in.
28
28
  - **`Model/Prudential/AdvanceShippingNotice.php::prePost(&$api, &$payload)`** — for each
29
29
  `$payload->advanceShippingNoticeItems[]`: renames the legacy `advanceShippingNoticeUnits` key to
30
30
  `advanceShippingNoticeItemUnits`, and lifts each unit's flat `trackingNumber` / `returnTrackingNumber`
31
- into a single `advanceShippingNoticeItemUnitTrackingNumbers` bridge-child row, removing the flat fields.
31
+ into a single `advanceShippingNoticeItemUnitTrackingNumbers` bridge-child row using the FK field names
32
+ `trackingNumberId` / `returnTrackingNumberId` (not the plain field names — the engine resolves FK
33
+ children by field name ending in `Id`).
32
34
  - **Registration** — `Client_Prudential.ApiPayloadInterceptors` row: `recordId = 55`
33
35
  (advance-shipping-notices), `prePostProcessing = 'PRE'`, `httpMethod = 'POST'`, `apiId = 2` (Dell),
34
36
  `isActive = 1`. The engine resolves `_Model_Client_AdvanceShippingNotice` → `_Model_Prudential_AdvanceShippingNotice`
@@ -40,12 +42,41 @@ advanceShippingNoticeItems: [ { quantity, advanceShippingNoticeUnits: [
40
42
  { trackingNumber:{number}, returnTrackingNumber:{number}, unit:{serialNumber} } ] } ]
41
43
  ```
42
44
  The interceptor rewrites each item to `advanceShippingNoticeItemUnits` with the tracking moved into
43
- `advanceShippingNoticeItemUnitTrackingNumbers`.
45
+ `advanceShippingNoticeItemUnitTrackingNumbers` as `{ trackingNumberId: {number:...}, returnTrackingNumberId: {number:...} }`.
46
+
47
+ ## Required DB config (`Core.RecordFields`)
48
+
49
+ The bridge record's FK fields must have `childPolicy = MATCH_CREATE` — otherwise the engine throws
50
+ `EV-12` when the `TrackingNumbers` row doesn't exist yet (Dell always sends new tracking numbers):
51
+
52
+ ```sql
53
+ -- trackingNumberId on advance-shipping-notice-item-unit-tracking-numbers (id=1437)
54
+ UPDATE Core.RecordFields SET childPolicy = 'MATCH_CREATE' WHERE id = 1437;
55
+ -- returnTrackingNumberId on same record (id=2198)
56
+ UPDATE Core.RecordFields SET childPolicy = 'MATCH_CREATE' WHERE id = 2198;
57
+ ```
58
+
59
+ `MATCH_CREATE` = look up existing `TrackingNumbers` row by `number` (isIdentifier=1), create if not
60
+ found. `MATCH` (the default) errors when no row exists — that was the root cause of the Jun 2026
61
+ `EV-12` outage.
44
62
 
45
63
  ## Gotchas
46
64
  - Scoped to `apiId = 2` so other (internal) Prudential callers — which already send the new shape —
47
65
  are not double-transformed.
66
+ - The interceptor must use **`trackingNumberId` / `returnTrackingNumberId`** (FK field names) on the
67
+ bridge child row — NOT `trackingNumber` / `returnTrackingNumber`. Using the plain names causes `EV-12`
68
+ because the engine treats them as unknown field lookups against `TrackingNumbers.number` with `MATCH`
69
+ policy and errors when no row is found.
48
70
  - DB change lives in `dbchanges2/Client_Prudential/`.
71
+ - If Dell ASN POSTs fail in bulk, replay them from `Logs_Prudential.Api` — see the Dell ASN backfill
72
+ replay workflow doc.
73
+
74
+ ## Change history
75
+ - 2026-06-12 — Fixed interceptor bug: bridge row keys were `trackingNumber`/`returnTrackingNumber`
76
+ instead of `trackingNumberId`/`returnTrackingNumberId`, causing EV-12 on all Dell ASN POSTs. Also
77
+ set `Core.RecordFields childPolicy = MATCH_CREATE` on ids 1437 and 2198. Replayed 28 failed payloads
78
+ from `Logs_Prudential.Api`. (rgirish)
49
79
 
50
80
  ## Related docs
51
81
  - 2.0 _underscore: Tracking-Number Bridge Migration.
82
+ - Prudential: Dell ASN backfill replay workflow.
@@ -0,0 +1,70 @@
1
+ ---
2
+ title: "Prudential: Dell ASN failed POST backfill replay"
3
+ framework: "2.0"
4
+ project: API
5
+ client: prudential
6
+ type: workflow
7
+ status: active
8
+ updated: 2026-06-12
9
+ owners: ["rgirish"]
10
+ files: []
11
+ related:
12
+ - ../features/dell-asn-units-interceptor.md
13
+ ---
14
+
15
+ ## Summary
16
+
17
+ When Dell ASN POSTs fail in bulk (e.g. after a DB migration or interceptor bug), this workflow
18
+ replays the failed payloads from the `Logs_Prudential.Api` log table using a fresh auth token.
19
+ Used Jun 2026 after the `EV-12` tracking-number bug to backfill 28 missed shipments.
20
+
21
+ ## Steps
22
+
23
+ 1. **Confirm the root cause is fixed** before replaying — replaying into a broken system just
24
+ adds more failed log rows. Verify the interceptor fix and any `Core.RecordFields` DB changes
25
+ are applied to production.
26
+
27
+ 2. **Pull failed payloads from logs:**
28
+ ```sql
29
+ SELECT id, dtStamp, transactionId, responseCode, requestPayload
30
+ FROM Logs_Prudential.Api
31
+ WHERE route LIKE '%advance-shipping%'
32
+ AND method = 'POST'
33
+ AND responseCode != 200
34
+ ORDER BY id DESC
35
+ LIMIT 28;
36
+ ```
37
+ Adjust `LIMIT` and add a `dtStamp >= '...'` filter to scope to the incident window.
38
+
39
+ 3. **Get a fresh Dell API auth token** (the original `transactionId`s are already consumed —
40
+ each replay needs a new unique `transactionId`). The Dell API credentials (`client`, `api`,
41
+ `secret` UUIDs) are stored in `Client_Prudential.Apis` (id=2) — do not paste values here.
42
+
43
+ 4. **Test with the first payload only** — confirm `isSuccess: true` and `status: 201` before
44
+ continuing with the rest.
45
+
46
+ 5. **Replay all remaining payloads** using a script (Python recommended — shell array handling
47
+ breaks on multi-unit payloads with special characters). Generate a fresh UUID per request.
48
+ Log each result as `[N/total] OK` or `FAIL` with the error.
49
+
50
+ 6. **Verify** by checking `Logs_Prudential.Api` — successful replays appear with `responseCode = 201`
51
+ and new `transactionId`s distinct from the original failed ones.
52
+
53
+ ## Systems involved
54
+
55
+ - `Logs_Prudential.Api` — source of failed payloads
56
+ - `https://api.togahub.com/v2/advance-shipping-notices` — replay target
57
+ - `Core.RecordFields` — `childPolicy` config (must be `MATCH_CREATE` on ids 1437 and 2198)
58
+ - `_underscore/Model/Prudential/AdvanceShippingNotice.php` — PRE interceptor
59
+
60
+ ## Edge cases & escalation
61
+
62
+ - **Token expires mid-run** (access token valid 1 hour): re-auth and resume from the first
63
+ failed item — already-created records are not duplicated.
64
+ - **`EV-5` duplicate transactionId**: payload was already successfully processed. Skip it.
65
+ - **`EV-12` still firing after fix**: `Core.RecordFields childPolicy` change may not have
66
+ cleared the config cache — wait a minute, then retry.
67
+ - **`Box` serial numbers**: valid — some multi-unit shipments use `serialNumber: "Box"`.
68
+
69
+ ## Change history
70
+ - 2026-06-12 — Created after replaying 28 failed Dell ASN POSTs from Jun 11 2026 incident. (rgirish)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.64",
3
+ "version": "1.0.65",
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",