toga-ai 1.0.1193 → 1.0.1194

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.
@@ -6,7 +6,7 @@ project: Worker
6
6
  client: nycdoe
7
7
  type: client-feature
8
8
  status: active
9
- updated: 2026-10-27
9
+ updated: 2026-10-29
10
10
  owners: [mhammontree, sking, bala, jcardinal, rgirish]
11
11
  files:
12
12
  - worker1.5/crons/sync/nycdoe/3_create_installation_ticket.php
@@ -132,7 +132,10 @@ Vendor SFTP ───(legacy_import_asn.php, ser+non-ser)─┘ [UNIQUE ded
132
132
  - **Stage 5:** for units `WHERE togadeskRepairOrderId IS NULL`, reads serials from NetSuite item receipts (so TOGa Desk RO serials are **driven by NetSuite**, not the ASN unit), creates/reuses TOGa Desk manufacturers/models/assets/serial-numbers/MSO and creates **a new repair_orders row unconditionally per loop iteration** — one RO per Unit (a 50-cable line = 1 unit = 1 RO). Existing-serial lookup is scoped **per item row** (`$asnItemId`). Item receipts are resolved **Sales-Order-wide** via `App_NetSuite::listItemReceiptsCreatedFromSalesOrder($soId)` (fans across ALL POs from `listPurchaseOrdersCreatedFromSalesOrder`, dedupes receipts by `internalId`), cached **per sales-order internal id** (`$itemReceiptsBySo`, keyed by `netSuiteInternalSalesOrderId`) — a shared SO is still fetched once — with the `getItemReceipt` detail cache kept per (globally-unique) receipt `internalId`. Both the inner item query **and** the outer ASN-candidate query require `netSuiteInternalSalesOrderId <> 0` (a sentinel guard mirroring the PO guard) so a null/zero-SO row cannot poison the cache or match the wrong SO's receipts. Self-healing: units previously stuck under an unstamped PO clear on subsequent 5-min cron runs.
133
133
  - **Receipt resolution is SO-ONLY — the stamped PO id never finds a receipt** (traced 2026-07-29, `3_create_installation_ticket.php`: candidate query ~L248-278, per-item ~L311-341, receipt resolution ~L354-360, part-number match ~L418-422, per-unit gate ~L511-535). The chain is strictly `AdvanceShippingNoticeItems.netSuiteInternalSalesOrderId` → `listPurchaseOrdersCreatedFromSalesOrder` (all POs created from that SO) → `listItemReceiptsCreateFromPurchaseOrder` for each → dedupe (this is what `listItemReceiptsCreatedFromSalesOrder` wraps, `library/app/netsuite.php` ~L739 / ~L762 / ~L797, details via `getItemReceipt` ~L1697). **`netSuiteInternalPurchaseOrderId` is NEVER used to look up receipts** — it is only a non-null / non-zero **eligibility gate**. The schema is misleading here: the PO column *looks* authoritative and is not.
134
134
  - **Item receipts are never persisted.** They are fetched **live from NetSuite on every run** (no table, no bridge row), and the receipt-line → ASN-line linkage is derived **at runtime by part-number string match** after stripping the `DOE-` prefix and `_` characters. So NetSuite is the only source of truth for what was received, and a part-number formatting drift breaks the match silently.
135
- - **Candidate pick is `ORDER BY RAND() LIMIT 1` ON PURPOSE — do not change it to a fixed order** (rgirish, 2026-10-23). Newest-first was tried and the script stuck for days on one ASN with bad data. Cost: ~1,698 pending candidate ASNs (oldest 2023-10-02, most will never complete) and only a handful finish per run, so a new, fully received ASN can wait hours or days by chance (2026-10-22: 4 ASNs completed in 7.5 h). Symptom "received in NetSuite, no repair order in Desk" with correct SO/PO stamps = this wait, not a stamp mismatch → run the ASN by hand (below).
135
+ - **Candidate pick is `ORDER BY RAND() LIMIT 1` ON PURPOSE — do not change it to a fixed order** (rgirish, 2026-10-23). Newest-first was tried and the script stuck for days on one ASN with bad data. Cost: ~1,700–1,800 pending candidate ASNs (1,698 on 2026-10-23, 1,795 on 2026-10-29; oldest 2023-10-02, most will never complete) and only a handful finish per run, so a new, fully received ASN can wait hours or days by chance (2026-10-22: 4 ASNs completed in 7.5 h). Symptom "received in NetSuite, no repair order in Desk" with correct SO/PO stamps = this wait, not a stamp mismatch. A DOE report that lists POs by repair order will miss the PO until then.
136
+ - **Default response for ONE such ASN: no action** — no manual run, no code change; let the cron pick it (Brian Yard, 2026-10-29). Run by hand (below) only when asked, or for a batch/outage gap.
137
+ - **Fast triage (SuiteQL, 2 queries):** `transaction` + `transactionline` `WHERE id IN (<SO>,<PO>) OR createdfrom IN (<SO>,<PO>)` shows the SO → PO → ItemRcpt chain at once; `inventoryassignment WHERE transaction = <receipt id>` shows the received serial. PO created from SO + receipt holds the ASN serial = clean chain → it is this wait, not [Pre-ASN Manual Receipt Mismatch](#gotchas).
138
+ - Worked case (TRUE-83394): `WR270047873` = ASN 27376 (Apple, 1 unit, serial `CK7W74WQCG`), late from the TRUE-82940 Stage 1b outage; SO 7686363 → PO 7686364 → receipt 7693049 all clean on 10-28; still no RO on 10-29 → left to the cron.
136
139
  - **Manual one-ASN run** (optional argv `<asnId>`, int-cast, non-numeric throws "Invalid ASN id"; pins the candidate query to `AdvanceShippingNoticeItems.advanceShippingNoticeId`; no arg = normal cron): as root on worker15 via SSM, `php /var/app/current/crons/sync/nycdoe/3_create_installation_ticket.php <asnId>` (or `cd` + `./`). Never use the cron's own `/var/www/html/...` path — the overlap guard exits it at once, silently ([path rules](../../../1.0/apps/worker1.5/features/cron-overlap-guard.md)). Run ASNs **one after another**. Verify after: per MSO, `COUNT(repair_orders) = COUNT(DISTINCT serialNumId)`.
137
140
  - **MSO reuse is safe on re-run.** `doeCreateInstallationRepairOrder()` looks the managed service order up by `advanceShippingNoticeId`, so re-running Stage 5 against an ASN that already has an MSO **reuses** it rather than creating a duplicate.
138
141
  - **The per-SO (not per-ASN) receipt cache is load-bearing.** An ASN can carry lines from more than one NetSuite sales order; caching the receipt set once per ASN off the *first* line's SO matches every other line against the wrong SO's receipts (FIXED 2026-07-22 — see the multi-SO gotcha). One level *above* the multi-PO-per-SO fix.
@@ -315,6 +318,7 @@ All **live** DOE business logic is 1.0. The only other 2.0 code is the in-progre
315
318
  - Local deep-dive (full WR260236464 case study with record IDs): `doe_service_now_integration.md` in Mark's WWW workspace root; also the `service-now-integration` skill (`asn-import-flow.md`)
316
319
 
317
320
  ## Change history
321
+ - 2026-10-29 — TRUE-83394: `WR270047873` received in NetSuite but no Desk RO = Stage 5 random-pick wait (1,795 candidates); default = no action for one ASN (Brian Yard); SuiteQL chain triage tip. No code change. (mhammontree)
318
322
  - 2026-10-27 — TRUE-82940: `apple.php:74` PHP 8.5 outage (10-22 → 27) fixed, not deployed; errors land in V2 `Logs.Issue`; Stage 1b cadence is 15 min (worker1.5); gated mode sends one `RunForFiles` per account per run. (mhammontree)
319
323
  - 2026-10-23 — Daily open/closed report row; manual re-run gotcha (duplicate email, 24 h window shift) (TRUE-83159) (bala)
320
324
  - 2026-10-23 — RITM cron still broken in the worker1.5 copy (undefined vars); not fixed on TRUE-83163 (jcardinal)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.1193",
3
+ "version": "1.0.1194",
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",