toga-ai 1.0.604 → 1.0.605

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-08-17
9
+ updated: 2026-08-18
10
10
  owners: [mhammontree, sking]
11
11
  files:
12
12
  - worker/crons/sync/nycdoe/import_asn.php
@@ -326,7 +326,7 @@ Vendor SFTP ───(legacy_import_asn.php, ser+non-ser)─┘ [UNIQUE ded
326
326
  counts SO+customerPO pairs rather than distinct SOs.
327
327
 
328
328
  - **⚠ NAMED PATTERN — "Pre-ASN Manual Receipt Mismatch"** (the umbrella condition covering
329
- this doc's two SO/PO-stamp gotchas below plus a third confirmed instance). Search this
329
+ this doc's two SO/PO-stamp gotchas below plus a third and fourth confirmed instance). Search this
330
330
  title, or its informal name **"Shipment Received Notice"** (Mark's nickname — some vendors,
331
331
  chiefly Lenovo, effectively send the ASN *after* the goods already arrived).
332
332
  - **Common shape:** a manufacturer's physical shipment reaches the warehouse before (or
@@ -343,6 +343,66 @@ Vendor SFTP ───(legacy_import_asn.php, ser+non-ser)─┘ [UNIQUE ded
343
343
  `listItemReceiptsCreateFromPurchaseOrder($actualReceiptPO)`) and both are fixed the same
344
344
  way (a `dbchanges` data repair repointing the ASN item row's SO/PO ids to wherever the
345
345
  receipt actually lives, then letting the `*/5` Stage 5 cron ticket it — no code change).
346
+ - **⚠ FIRST TRIAGE STEP — "is the receipt-bearing PO a `Created From` CHILD of a sales order
347
+ we can stamp?"** (added 2026-08-18). This one question picks the remedy, and the two
348
+ remedies are **not interchangeable**, because Stage 5 resolves receipts **SO-wide only**
349
+ (`listPurchaseOrdersCreatedFromSalesOrder` → receipts per child PO):
350
+ - **PO IS a child of the SO** → a plain data repoint of *both* id columns
351
+ (`netSuiteInternalSalesOrderId` + `netSuiteInternalPurchaseOrderId`) works, and the `*/5`
352
+ Stage 5 cron tickets it itself. (Instances 3 and 4.)
353
+ - **PO is NOT a child** — a manually created PO or a cross-wired stamp, e.g. ASN `26215` —
354
+ → the SO-wide fan-out can **never** reach it, so a repoint is a **silent no-op** and
355
+ recovery needs the one-off **union-receipt backfill** instead.
356
+ Answer it in one look via NetSuite's **"Related Records"** tab on the SO (it lists the child
357
+ POs and their link type, e.g. `Special Order`), confirmed by the PO's own **"Created From"**
358
+ field. Getting this wrong costs a full apply-and-wait cron cycle before you learn the
359
+ repoint did nothing.
360
+ - **Quick discriminators that rule out neighbouring DOE failure classes** (use these before
361
+ committing to this pattern):
362
+ - A unit with `trackingNumberId` **NOT NULL** was created by the **importer**, not added by
363
+ Stage 5 from NetSuite — i.e. a genuine ASN unit (the inverse of the dedupeKey-drift
364
+ fingerprint further below).
365
+ - A well-formed `serialNumber` + populated `assetTag` + a clean OEM SKU in `partNumber`
366
+ rules **out** the open "Lenovo Off-Layout ASN File" parse bug (whose fingerprint is
367
+ `serialNumber = '1'`, the real serial in `assetTag`, and a product *description* in
368
+ `partNumber`).
369
+ - **NetSuite internal ids are creation-ordered**, so a receipt id can never predate its own
370
+ PO id — that ordering alone can disprove a proposed receipt↔PO pairing.
371
+ - **Confirmed instance 4 — NEW STRUCTURAL VARIANT: duplicate SO cut for a POST-FREEZE GROWTH
372
+ row while the ORIGINAL SO already carried that line** (2026-08-18, ASN `26644`, customer PO
373
+ `WR260175404-RPL`, Lenovo, `ldaCode` `M366M263`). Item `54552` (`DOE-62C5GAR1US`, unit
374
+ `604254`, serial `VKVY4802`, asset `DOE-LN1271004`) sat `installTicketStatus=pending` with
375
+ `togadeskRepairOrderId` NULL since 2026-07-02 — the silent-stranding dead end, no error, no
376
+ alert.
377
+ - Warehouse **force-received** the shipment because Lenovo's ASN had not arrived yet.
378
+ - SO `281110` (internal `7219711`) carried **all three** ASN lines including
379
+ `DOE-62C5GAR1US`, with two child POs, both link type **Special Order**: `167882`
380
+ (internal `7219712`, 7/1/2026) and `167917` (internal `7223073`, 7/2/2026). Goods were
381
+ receipted on PO `167917` / internal `7223073`, **item receipt internal `7223075`**.
382
+ - When the ASN growth row for the touch monitor landed (post-freeze growth correctly
383
+ becoming a fresh item row per business rule 4), the automation cut a **second** SO —
384
+ internal `7245587` / PO `7245588` — and Stage 3 stamped item `54552` with it. That
385
+ duplicate chain was never received and **never can be**: serial `VKVY4802` was already
386
+ consumed by receipt `7223075`. Id ordering confirms it: `7223073 < 7223075 < 7245587`.
387
+ - **Fix (data-only, worked 2026-08-18):** repointed `netSuiteInternalSalesOrderId`
388
+ `7245587 → 7219711` and `netSuiteInternalPurchaseOrderId` `7245588 → 7223073`; the `*/5`
389
+ Stage 5 cron then created the repair order itself. Because the correct chain's PO **is** a
390
+ legitimate `Created From` child of the SO, the plain repoint was the right remedy.
391
+ - **How it differs from its neighbours:** instance 3 (ASN `23522`) was a same-ASN **sibling
392
+ PO**; ASN `26215` had a **manually created** PO that was *not* a child of the stamped SO.
393
+ Here the duplicate arose from the **post-freeze growth rule itself** on an SO that already
394
+ held the line — no manual NetSuite edit involved.
395
+ - **⚠ OUTSTANDING (not done):** the orphaned duplicate chain SO internal `7245587` / PO
396
+ internal `7245588` is unreceived and unused and **should be cancelled in NetSuite**, same
397
+ as the duplicate chain on ASN `26215`. Not blocking the install, which is TOGa Desk-side
398
+ only.
399
+ - **Delivering the repair by hand vs. by `dbchanges`.** Instance 4 was run as a **manual
400
+ one-row `UPDATE` directly against legacy `Core`** — deliberately *not* shipped as a
401
+ `dbchanges` file, diverging from the ASN `26280` / `23522` precedents. Consequence worth
402
+ knowing: when run manually the **derived-table preflight guard is unnecessary** — that
403
+ pattern exists only to work around the `dbchanges` runner's inability to express procedural
404
+ guards. Pinning the before-state values in the `WHERE` clause still gives the
405
+ no-op / no-double-apply safety either way.
346
406
  - **Confirmed instance 3 (2026-08-06/07, ASN `23522`, customer PO `S202637409`).** Item
347
407
  `51104` (`DOE-63D8MAR3US`, serial `VTV11634`, asset `DOE-LN1262287`) arrived from Lenovo
348
408
  and the warehouse receipted *a* unit of that part against sibling PO **#157026** (internal
@@ -587,6 +647,22 @@ the client's `apps:` scope solely so this monitor loads, and its presence is **n
587
647
  of the consumer query; `php -l` every touched file.
588
648
 
589
649
  ## Change history
650
+ - 2026-08-18 — Repaired stranded ASN `26644` / customer PO `WR260175404-RPL` (**data-only, no code
651
+ in `worker` or `dbchanges`**): item `54552` (`DOE-62C5GAR1US`, unit `604254`, serial `VKVY4802`)
652
+ had been `pending` with a NULL `togadeskRepairOrderId` since 2026-07-02. Repointed
653
+ `netSuiteInternalSalesOrderId` `7245587 → 7219711` and `netSuiteInternalPurchaseOrderId`
654
+ `7245588 → 7223073` and let the `*/5` Stage 5 cron ticket it (confirmed working). Logged this as
655
+ the **fourth** confirmed instance of "Pre-ASN Manual Receipt Mismatch" and a **new structural
656
+ variant**: the duplicate SO was cut for a **post-freeze growth row** while the original SO already
657
+ carried that line (no manual NetSuite edit) — distinct from instance 3's same-ASN sibling PO and
658
+ from ASN `26215`'s non-child manual PO. Added the pattern's **first triage step** ("is the
659
+ receipt-bearing PO a `Created From` child of a stampable SO?" — child ⇒ repoint works, non-child ⇒
660
+ repoint is a silent no-op and the union-receipt backfill is required), the quick discriminators
661
+ that rule out the off-layout parse bug and importer-vs-Stage-5 units, the id-ordering proof, and
662
+ the note that a **manual** SQL run needs no derived-table preflight guard (unlike a `dbchanges`
663
+ file). **Outstanding:** duplicate chain SO `7245587` / PO `7245588` still needs cancelling in
664
+ NetSuite. The durable detection/alerting fix for this stranding class remains **unbuilt**.
665
+ (mhammontree)
590
666
  - 2026-08-17 — TRUE-80587: added `Monitor/Nycdoe/ServiceNowEndpointHealth` (worker2 → OneUptime), an
591
667
  unauthenticated-GET liveness probe complementing the log-scraping 1.0 `App_SystemMonitor_ServiceNow*`
592
668
  monitors, which cannot see a dead endpoint. Token validity is a deliberately accepted coverage gap
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.604",
3
+ "version": "1.0.605",
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",