toga-ai 1.0.799 → 1.0.801
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.
- package/knowledge/1.0/apps/library/features/netsuite-suiteql-rest-shim.md +51 -1
- package/knowledge/1.0/apps/library/features/toga2-api-client-and-bridge.md +16 -2
- package/knowledge/1.0/apps/worker/features/netsuite-togasupply-per-client-sync.md +72 -1
- package/knowledge/clients/nychh/features/netsuite-transfer-order-import.md +16 -1
- package/knowledge/clients/nychh/profile.md +20 -1
- package/package.json +1 -1
- package/rules/common/communication.md +38 -0
- package/scripts/hooks/plain-talk.js +3 -0
|
@@ -6,7 +6,7 @@ project: Library
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-09-
|
|
9
|
+
updated: 2026-09-13
|
|
10
10
|
owners: [dfranks, jcardinal, kyalamarthi, rgirish]
|
|
11
11
|
files:
|
|
12
12
|
- library/app/api/netsuite/rest.php
|
|
@@ -153,6 +153,42 @@ Forecast2 tables already store.
|
|
|
153
153
|
skew — the field just reads as its default — so verify the exact scriptId string on both the write and
|
|
154
154
|
the read side. See [NYCHH TransferOrders import](../../../clients/nychh/features/netsuite-transfer-order-import.md).
|
|
155
155
|
|
|
156
|
+
- **The item-fulfillment shim now carries `orderLineUniqueKey` — the STABLE key for matching a
|
|
157
|
+
fulfillment line to its source order line (2026-09-13).** The fulfillment's `orderLine` (source
|
|
158
|
+
`linesequencenumber`) does **not** always equal the sales-order shim's displayed line, so
|
|
159
|
+
number-based matching in `syncItemFulfillmentFromNetsuite` silently missed. The shim derives
|
|
160
|
+
`orderLineUniqueKey` = the source order line's `transactionline.uniquekey`, via
|
|
161
|
+
`previoustransactionlinelink` joined to the source line with **`previousline IS NOT NULL`** (which
|
|
162
|
+
drops wash/inventory link rows). The importer matches it against TOGa
|
|
163
|
+
`SalesOrderItems.c_netsuiteLineUniqueKey`, falling back to the line-number path. Engine-side matcher
|
|
164
|
+
chain: [per-client sync](../../worker/features/netsuite-togasupply-per-client-sync.md).
|
|
165
|
+
|
|
166
|
+
- **⚠ Package TRACKING NUMBERS need `?expandSubResources=true` — a bare package sub-resource GET
|
|
167
|
+
returns rows WITHOUT the fields, so tracking numbers never import (fixed 2026-09-13).**
|
|
168
|
+
`fetchItemFulfillmentById` fetched packages via a **bare** `GET /record/v1/itemFulfillment/{id}/package`,
|
|
169
|
+
which returns package rows **without** `packageTrackingNumber` inlined (proven: items come back as
|
|
170
|
+
`{links:[]}`) — so NYCHH bridges 317/318/319 stayed empty. **Fix:** fetch
|
|
171
|
+
`/record/v1/itemFulfillment/{id}/package?expandSubResources=true` (inlines the fields, scoped to
|
|
172
|
+
`/package` so the huge serial sublists are NOT pulled); only if the generic `package` sublist has no
|
|
173
|
+
tracking number, also check the carrier sublists
|
|
174
|
+
`/packageUps|packageFedex|packageUsps?expandSubResources=true`; dedupe by tracking number; and
|
|
175
|
+
**FAIL LOUD if the fetch fails** — a non-object/error body must not read as zero packages, which
|
|
176
|
+
would drop the number and advance the cursor. Verified end-to-end on a serialized IF: one NetSuite
|
|
177
|
+
tracking number fans to the header (317), the item (318), and all serial units (319). Fan-out
|
|
178
|
+
engine detail: [per-client sync](../../worker/features/netsuite-togasupply-per-client-sync.md).
|
|
179
|
+
|
|
180
|
+
- **⚠ Three REST sub-resource gotchas (framework-level — apply to any `App_Api_Netsuite_Rest`
|
|
181
|
+
sub-resource fetch):**
|
|
182
|
+
1. **A bare sub-resource GET returns rows WITHOUT their fields.** Add `?expandSubResources=true` to
|
|
183
|
+
inline them (this is exactly what hid the package tracking numbers above).
|
|
184
|
+
2. **`fields=` and `expandSubResources` CANNOT be combined** — NetSuite returns **HTTP 400
|
|
185
|
+
`INVALID_PARAMETER` "not allowed in one request"**. Pick one per call.
|
|
186
|
+
3. **api2 truncates a large nested child collection (observed cap 25).** Never trust a single nested
|
|
187
|
+
GET's count — read the collection **flat and fully paginated** (`meta->nextPage`). This is the
|
|
188
|
+
shim-consumer side of the api2 truncation trap on the
|
|
189
|
+
[toga2 client doc](toga2-api-client-and-bridge.md); it drove the two flat-fetch helpers in the
|
|
190
|
+
fulfillment reconcile.
|
|
191
|
+
|
|
156
192
|
- **`fetchPurchaseOrderById()` omitted `entity` from its SELECT and never set `$shim->entity` — so
|
|
157
193
|
every PO shim had a null vendor and the fail-loud guard fired every run (2026-08-29).** Unlike its
|
|
158
194
|
sibling `listPurchaseOrders` (which DOES select `entity` + `BUILTIN.DF(entity)` and populates the
|
|
@@ -323,6 +359,20 @@ None — uniform across clients (NetSuite is a single shared account).
|
|
|
323
359
|
|
|
324
360
|
## Change history
|
|
325
361
|
|
|
362
|
+
- 2026-09-13 — **Item-fulfillment shim gotchas from the NYCHH ITEM_FULFILLMENTS unfreeze (library,
|
|
363
|
+
deployed + verified).** (1) The item-fulfillment REST shim now carries **`orderLineUniqueKey`** (the
|
|
364
|
+
source line's `transactionline.uniquekey`, via `previoustransactionlinelink` joined to the source
|
|
365
|
+
line, `previousline IS NOT NULL` to drop wash/inventory lines) so the importer can match a
|
|
366
|
+
fulfillment line by a stable key instead of the drifting line number. (2) **Package tracking numbers
|
|
367
|
+
never imported** because `fetchItemFulfillmentById` fetched `/package` **bare** (no fields inlined);
|
|
368
|
+
fixed to `?expandSubResources=true` scoped to `/package`, falling back to the carrier sublists
|
|
369
|
+
(`packageUps|packageFedex|packageUsps`), deduped by tracking number, and **fail-loud** if the fetch
|
|
370
|
+
errors so a bad body is not read as zero packages. (3) Recorded three framework-level REST
|
|
371
|
+
sub-resource gotchas: a bare sub-resource GET omits fields (`expandSubResources=true` inlines them);
|
|
372
|
+
`fields=` and `expandSubResources` cannot be combined (HTTP 400 `INVALID_PARAMETER`); and api2
|
|
373
|
+
truncates a large nested child collection (cap ~25) so read it flat + fully paginated. Engine-side
|
|
374
|
+
reconcile detail: [per-client sync](../../worker/features/netsuite-togasupply-per-client-sync.md).
|
|
375
|
+
(jcardinal)
|
|
326
376
|
- 2026-09-03 — Documented that a sales-order shim's **`->holdInvoice` is not a native NetSuite
|
|
327
377
|
field**: it is normalised inside the shim from the custom checkbox **`custbody_asi_hold` (id
|
|
328
378
|
4082)**, which is **shared across all clients** ("asi" = Agilant Solutions Inc, not a client
|
|
@@ -6,7 +6,7 @@ project: Library
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-09-
|
|
9
|
+
updated: 2026-09-13
|
|
10
10
|
owners: [jcardinal, mhammontree, bala]
|
|
11
11
|
files:
|
|
12
12
|
- library/app/api/toga2.php
|
|
@@ -331,7 +331,13 @@ enable flags** and an optional `$monitorTogadeskDepartmentIds[]`:
|
|
|
331
331
|
is silently wrong. **Read the collection flat and fully paginated** (query the child resource
|
|
332
332
|
directly with the universal `meta->nextPage` loop) and take counts from **`meta.totalRecordCount`**,
|
|
333
333
|
not from a single nested response. Surfaced building the NYCHH fulfillment asset-tag verifier
|
|
334
|
-
(`worker/crons/toga2/netsuite/verify_fulfillment_asset_tag_sync_nychh.php`).
|
|
334
|
+
(`worker/crons/toga2/netsuite/verify_fulfillment_asset_tag_sync_nychh.php`). **Confirmed again on
|
|
335
|
+
the fulfillment reconcile (2026-09-13):** the `salesOrderItems` nested collection truncated at
|
|
336
|
+
**25**, and a fulfillment's `itemFulfillmentItemUnits` re-created 25,766 links for 1,192 real units.
|
|
337
|
+
The reconcile now reads both flat + fully paginated via two new private helpers,
|
|
338
|
+
`getItemFulfillmentItemUnitsByItemFulfillmentUuid()` and `getSalesOrderItemsBySalesOrderUuid()`
|
|
339
|
+
(`recordsPerPage` 1000, page-cap 500, `nextPage ?? null`) — detail on the
|
|
340
|
+
[per-client sync doc](../../worker/features/netsuite-togasupply-per-client-sync.md).
|
|
335
341
|
- **🔐 Hardcoded credentials.** Every client's `CLIENT_UUID_*`, `API_UUID_*`, and `API_SECRET_*`
|
|
336
342
|
(plus the "True Workers" master keys) are committed as plaintext class constants at the top of
|
|
337
343
|
`toga2.php`. Treat them as **compromised-if-leaked**; do not reproduce the values in the KB,
|
|
@@ -424,6 +430,14 @@ enable flags** and an optional `$monitorTogadeskDepartmentIds[]`:
|
|
|
424
430
|
|
|
425
431
|
## Change history
|
|
426
432
|
|
|
433
|
+
- 2026-09-13 — Two new private helpers on this class read a nested collection **flat + fully
|
|
434
|
+
paginated** to dodge the api2 nested-GET truncation:
|
|
435
|
+
`getItemFulfillmentItemUnitsByItemFulfillmentUuid()` and `getSalesOrderItemsBySalesOrderUuid()`
|
|
436
|
+
(both feed the fulfillment reconcile). Recorded the fresh evidence — `salesOrderItems` truncated at
|
|
437
|
+
**25**, and one fulfillment re-created 25,766 unit links for 1,192 real units. The methods and the
|
|
438
|
+
full five-bug ITEM_FULFILLMENTS unfreeze live on the
|
|
439
|
+
[per-client sync doc](../../worker/features/netsuite-togasupply-per-client-sync.md) (these are
|
|
440
|
+
`*FromNetsuite` importer internals, scoped there per this doc's Summary). (jcardinal)
|
|
427
441
|
- 2026-09-11 — **Observability: `send()`'s "Invalid API Response" exception now leads with the api2
|
|
428
442
|
message codes.** Added a private `describeApiMessages()` helper (~L726) that renders the
|
|
429
443
|
`->messages[].code: text` list (each text capped at 160 chars, cso point) and prepended it to the
|
|
@@ -6,7 +6,7 @@ project: Worker
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-09-
|
|
9
|
+
updated: 2026-09-13
|
|
10
10
|
owners: ["dfranks", "bala", "jcardinal", "mhammontree", "snaredla", "rgirish"]
|
|
11
11
|
files:
|
|
12
12
|
- worker/crons/toga2/netsuite/common_sync_togasupply.php
|
|
@@ -583,6 +583,57 @@ the [Quad profile](../../../clients/quad/profile.md) and the
|
|
|
583
583
|
Design rationale for putting this at the source writer rather than a 317 interceptor lives on the
|
|
584
584
|
[recursive item fulfillments doc](../../../2.0/apps/_underscore/features/recursive-item-fulfillments.md).
|
|
585
585
|
|
|
586
|
+
### Fulfillment line → sales-order line matching is a 4-step chain (2026-09-13)
|
|
587
|
+
|
|
588
|
+
The fulfillment matcher in `syncItemFulfillmentFromNetsuite` resolves each fulfillment line back
|
|
589
|
+
to its `SalesOrderItems` / `TransferOrderItems` parent. It tries, in order, and stops at the first
|
|
590
|
+
hit:
|
|
591
|
+
|
|
592
|
+
1. **Stable unique key (preferred).** The item-fulfillment REST shim now carries
|
|
593
|
+
`orderLineUniqueKey` — the source order line's `transactionline.uniquekey`, derived via
|
|
594
|
+
`previoustransactionlinelink` joined to the source line (`previousline IS NOT NULL`, which drops
|
|
595
|
+
wash/inventory lines). The matcher compares it to TOGa `SalesOrderItems.c_netsuiteLineUniqueKey`.
|
|
596
|
+
This replaces number-based matching as the primary key because the fulfillment's `orderLine`
|
|
597
|
+
(source `linesequencenumber`) does **not** always equal the sales-order shim's displayed line, so
|
|
598
|
+
number matching silently missed. Shim detail:
|
|
599
|
+
[SuiteQL/REST shim](../../library/features/netsuite-suiteql-rest-shim.md).
|
|
600
|
+
2. **Line number** — the old path, kept as a fallback.
|
|
601
|
+
3. **Reconstruct** — the existing rebuild path.
|
|
602
|
+
4. **Part number (last resort).** Match by part number (UPPER + trim) **only when exactly ONE** SO
|
|
603
|
+
line carries that part number — it never guesses between duplicates, and it **consumes** the
|
|
604
|
+
matched line so a repeat cannot reuse it. This exists because some fulfillment lines'
|
|
605
|
+
`previoustransactionlinelink` points at a **TAX line** (TaxGroup, item −8 "−Not Taxable−") instead
|
|
606
|
+
of the product line, so unique-key + line-number + reconstruct all miss even though the product IS
|
|
607
|
+
on the SO.
|
|
608
|
+
|
|
609
|
+
**An unmatched line FAILS LOUD (throws) — it never creates an orphan.** When no parent resolves the
|
|
610
|
+
code used to still create an item-fulfillment-item with **NULL** `salesOrderItemId` AND
|
|
611
|
+
`transferOrderItemId`. That row can never be matched next run, so a fresh orphan was created every
|
|
612
|
+
run and units split under it (runaway growth the unit-dedup cannot see because it is cross-item).
|
|
613
|
+
Now it throws; the section stays `RUNNING` for a human, matching the fail-loud policy (worker
|
|
614
|
+
stdout/`error_log` is discarded, so a silent skip is invisible). A self-heal deletes existing
|
|
615
|
+
null-parent items on sight: each item's units → each unit's tracking bridge → the unit → the item's
|
|
616
|
+
tracking → the item.
|
|
617
|
+
|
|
618
|
+
### Nested-GET truncation drives two flat + paginated helpers (2026-09-13)
|
|
619
|
+
|
|
620
|
+
api2 **silently truncates a large nested child collection** returned inside one parent GET (see the
|
|
621
|
+
truncation gotcha on the [toga2 client doc](../../library/features/toga2-api-client-and-bridge.md)),
|
|
622
|
+
which corrupted the fulfillment reconcile in two places. Both now read the collection **flat and
|
|
623
|
+
fully paginated** (`recordsPerPage` 1000, page-cap 500, `nextPage ?? null`) instead of trusting the
|
|
624
|
+
nested count:
|
|
625
|
+
|
|
626
|
+
- **Existing units for the dedup map** — `getItemFulfillmentItemUnitsByItemFulfillmentUuid()`. The
|
|
627
|
+
dedup map used to be built from the nested `itemFulfillmentItem->itemFulfillmentItemUnits` in one
|
|
628
|
+
`GET /item-fulfillments`; units it did not see were re-created every run (prod: **25,766** unit
|
|
629
|
+
links for **1,192** real units on one fulfillment, section frozen). A **self-heal** deletes
|
|
630
|
+
duplicate unit links, keeping one per item + `assignmentId` and removing the tracking-bridge
|
|
631
|
+
children first (FK `RESTRICT`).
|
|
632
|
+
- **Sales-order items for the matcher** — `getSalesOrderItemsBySalesOrderUuid()`. The matcher's SO
|
|
633
|
+
fetch returned `salesOrderItems` truncated (observed cap **25**); an order with >25 lines dropped a
|
|
634
|
+
line the fulfillment referenced, the match failed, and the section fail-loud-froze. The flat list
|
|
635
|
+
replaces the truncated nested one before match/reconstruct.
|
|
636
|
+
|
|
586
637
|
### Custom field contract (hardcoded in `common_sync_togasupply.php`)
|
|
587
638
|
|
|
588
639
|
The engine requests these `c_` fields by literal name per route — every synced client must have
|
|
@@ -1482,6 +1533,26 @@ library (or vice versa) crashes GroWrk and Adyen on their next sync run.
|
|
|
1482
1533
|
|
|
1483
1534
|
## Change history
|
|
1484
1535
|
|
|
1536
|
+
- 2026-09-13 — **ITEM_FULFILLMENTS unfrozen for NYCHH: five stacked fulfillment-reconcile bugs fixed
|
|
1537
|
+
(library, deployed + verified in prod).** (1) **Unit duplication from a truncated nested GET** — the
|
|
1538
|
+
existing-units dedup map was built from the nested `itemFulfillmentItemUnits` of one
|
|
1539
|
+
`GET /item-fulfillments`, which api2 silently truncates, so unseen units re-created every run
|
|
1540
|
+
(**25,766** unit links for **1,192** real units on one fulfillment). New
|
|
1541
|
+
`getItemFulfillmentItemUnitsByItemFulfillmentUuid()` reads units flat + fully paginated
|
|
1542
|
+
(`recordsPerPage` 1000, page-cap 500, `nextPage ?? null`) and drives the dedup; a self-heal deletes
|
|
1543
|
+
duplicate unit links (keep one per item + `assignmentId`, tracking-bridge children first for FK
|
|
1544
|
+
RESTRICT). (2) **Orphan item-fulfillment-items** — an unresolved line used to create an item with
|
|
1545
|
+
NULL `salesOrderItemId` AND `transferOrderItemId`, un-matchable so a fresh orphan spawned every run;
|
|
1546
|
+
now **fails loud** (throws) and a self-heal deletes existing null-parent items (units → tracking
|
|
1547
|
+
bridge → unit → item tracking → item). (3) **SO-items nested truncation (cap 25)** — new
|
|
1548
|
+
`getSalesOrderItemsBySalesOrderUuid()` reads all SO items flat + paginated, replacing the truncated
|
|
1549
|
+
nested list before match/reconstruct. (4) **Match on the stable unique key** — the shim now carries
|
|
1550
|
+
`orderLineUniqueKey` and the matcher prefers it over the line number (falls back to number →
|
|
1551
|
+
reconstruct). (5) **Part-number fallback** — last-resort match by part number (UPPER+trim) only when
|
|
1552
|
+
exactly ONE SO line carries it (consumes the line; never guesses between duplicates), for lines whose
|
|
1553
|
+
`previoustransactionlinelink` points at a TAX line. Shim-side detail (`orderLineUniqueKey`, package
|
|
1554
|
+
tracking) on the [SuiteQL/REST shim](../../library/features/netsuite-suiteql-rest-shim.md). An
|
|
1555
|
+
unmatched line fails loud, consistent with the 2026-08-27 policy. (jcardinal)
|
|
1485
1556
|
- 2026-09-11 — **ITEM_RECEIPTS froze at RUNNING on NYCHH: a case-mismatched `Units` serial lookup
|
|
1486
1557
|
(library, fix written not deployed).** `syncItemReceiptFromNetsuite` (`library/app/api/toga2.php`
|
|
1487
1558
|
~L4022) keyed a PHP existing-`Units` array on the DB's stored serial casing (`'na100'`) but read it
|
|
@@ -6,7 +6,7 @@ project: Library
|
|
|
6
6
|
client: nychh
|
|
7
7
|
type: client-feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-09-
|
|
9
|
+
updated: 2026-09-13
|
|
10
10
|
owners: [jcardinal, bala, rgirish]
|
|
11
11
|
files:
|
|
12
12
|
- library/app/api/toga2.php
|
|
@@ -122,6 +122,15 @@ full evidence table (location 75 → warehouse 117, the only `allowSending` sour
|
|
|
122
122
|
locations carry a customer id, 7 carry a location id) is in
|
|
123
123
|
[NYCHH TransferOrder → NetSuite push](./transfer-order-netsuite-push.md).
|
|
124
124
|
|
|
125
|
+
> **⚠ OPEN, not fixed (2026-09-13) — a transfer order's DESTINATION location does not resolve, and
|
|
126
|
+
> it is now collapsing the INVENTORY_ADJUSTMENTS section.** `TransferOrders.destinationLocationId` is
|
|
127
|
+
> also NOT NULL. The INVENTORY_ADJUSTMENTS section (window shrinking, stuck `RUNNING`) runs an
|
|
128
|
+
> on-demand cascade that imports a transfer-order-backed fulfillment, and the
|
|
129
|
+
> `POST /v2/transfer-orders` for **TO 277871** (`c_netsuiteInternalSalesOrderId` **7102750**) fails
|
|
130
|
+
> **EV-10 "Column 'destinationLocationId' cannot be null"** — the **origin** resolved but the
|
|
131
|
+
> **destination** did not. This is a **separate** destination-resolution bug from the origin
|
|
132
|
+
> fallback above (and from the 128829 no-location edge case). Next task; not yet root-caused.
|
|
133
|
+
|
|
125
134
|
## Item-fulfillment transfer-order line link
|
|
126
135
|
|
|
127
136
|
`ItemFulfillmentItems.transferOrderItemId` must populate so the 2.0 stock-out quantity calc can tie
|
|
@@ -315,6 +324,12 @@ item receipts replays about two years unless it is rewound forward first.
|
|
|
315
324
|
|
|
316
325
|
## Change history
|
|
317
326
|
|
|
327
|
+
- 2026-09-13 - **OPEN: INVENTORY_ADJUSTMENTS collapsing on an unresolved transfer-order
|
|
328
|
+
DESTINATION.** The section's on-demand cascade imports a transfer-order-backed fulfillment, and
|
|
329
|
+
`POST /v2/transfer-orders` for **TO 277871** (`c_netsuiteInternalSalesOrderId` **7102750**) fails
|
|
330
|
+
**EV-10 "Column 'destinationLocationId' cannot be null"** — origin resolved, destination did not.
|
|
331
|
+
Separate from the origin fallback and the 128829 no-location case; next task, not yet root-caused.
|
|
332
|
+
Recorded in the origin/destination section. (jcardinal)
|
|
318
333
|
- 2026-09-10 - Recorded that the import concentrates **1,832 of 1,939** transfer orders on catch-all
|
|
319
334
|
destination **location 2**, all with `createdByUserId` NULL (so none came from the Create Transfer
|
|
320
335
|
Order screen), and that whether it should resolve the real hospital instead is still open with the
|
|
@@ -18,7 +18,7 @@ project: _Underscore
|
|
|
18
18
|
client: nychh
|
|
19
19
|
type: profile
|
|
20
20
|
status: active
|
|
21
|
-
updated: 2026-09-
|
|
21
|
+
updated: 2026-09-13
|
|
22
22
|
owners: ["jcardinal", "apeterson", "bala", "akhokhani"]
|
|
23
23
|
files:
|
|
24
24
|
- dbchanges2/Client_Nychh/2026-09-02a - TransferOrderNetsuitePushInterceptor.sql
|
|
@@ -125,6 +125,25 @@ table views. Client-specific DB change-sets live in `dbchanges2/Client_Nychh/`.
|
|
|
125
125
|
(`strtoupper()` on both the key and the reads). This is a **different** duplicate from the open
|
|
126
126
|
sales-order `Items` duplicate below (658-BFZH). Mechanism + the EV-10 → `Logs_Nychh.Api` diagnosis
|
|
127
127
|
traps: [per-client sync doc](../../1.0/apps/worker/features/netsuite-togasupply-per-client-sync.md).
|
|
128
|
+
- **ITEM_FULFILLMENTS freeze RESOLVED — five stacked reconcile bugs fixed, deployed + verified
|
|
129
|
+
(2026-09-13).** The frozen section (prod: 25,766 unit links for 1,192 real units on one fulfillment)
|
|
130
|
+
is cleared: (1) unit dedup now reads existing units **flat + fully paginated** instead of from a
|
|
131
|
+
truncated nested GET; (2) an unmatched fulfillment line **fails loud** instead of creating a
|
|
132
|
+
never-matchable NULL-parent orphan (self-heal deletes existing orphans); (3) the SO-items fetch is
|
|
133
|
+
flat + paginated (api2 truncated the nested list at 25); (4) fulfillment→SO line matching prefers the
|
|
134
|
+
stable `orderLineUniqueKey` over the drifting line number; (5) a part-number last-resort match for
|
|
135
|
+
lines whose NetSuite link points at a TAX line. **Package tracking numbers now import to all three
|
|
136
|
+
bridges (317/318/319)** — the shim fetches `/package?expandSubResources=true` (a bare sub-resource
|
|
137
|
+
GET returned no fields), so one NetSuite tracking number fans to the header, item, and every serial
|
|
138
|
+
unit. Engine + shim detail:
|
|
139
|
+
[per-client sync](../../1.0/apps/worker/features/netsuite-togasupply-per-client-sync.md),
|
|
140
|
+
[SuiteQL/REST shim](../../1.0/apps/library/features/netsuite-suiteql-rest-shim.md).
|
|
141
|
+
- 🚩 **OPEN (2026-09-13): INVENTORY_ADJUSTMENTS collapsing on an unresolved transfer-order
|
|
142
|
+
DESTINATION.** The section's on-demand cascade imports a transfer-order-backed fulfillment and
|
|
143
|
+
`POST /v2/transfer-orders` for **TO 277871** (`c_netsuiteInternalSalesOrderId` 7102750) fails
|
|
144
|
+
**EV-10 "destinationLocationId cannot be null"** — origin resolved, destination did not. Separate
|
|
145
|
+
destination-resolution bug; next task. See
|
|
146
|
+
[NYCHH NetSuite → TransferOrders import](./features/netsuite-transfer-order-import.md).
|
|
128
147
|
- **NYCHH sync scope + data-gap scale + backfill approach (2026-09-09).**
|
|
129
148
|
- **Scope = 22 NetSuite customers:** parent **28908** "NYC Health + Hospitals" + 21 hospital child
|
|
130
149
|
customers (`24145, 29273, 29276, 31584, 31910-31916, 31918-31925, 32229, 33674`).
|
package/package.json
CHANGED
|
@@ -51,6 +51,44 @@ What you need to do:
|
|
|
51
51
|
4. Confirm the WorkerJobs table shows the new column.
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
+
## Cut output tokens — the safe way
|
|
55
|
+
|
|
56
|
+
Shorter answers are clearer AND cheaper to run. Both matter. But **clarity always wins** —
|
|
57
|
+
every rule here stops the moment it would make you harder to understand. This sharpens the
|
|
58
|
+
rules above; it never overrides them.
|
|
59
|
+
|
|
60
|
+
**Drop these words — they add length, not meaning:**
|
|
61
|
+
|
|
62
|
+
- Filler: just, really, basically, actually, simply.
|
|
63
|
+
- Pleasantries: sure, certainly, of course, happy to, great question.
|
|
64
|
+
- Hedging: I think, it seems, perhaps, kind of, sort of.
|
|
65
|
+
|
|
66
|
+
Say it straight. "Basically you just need to..." → "You need to...".
|
|
67
|
+
|
|
68
|
+
**Keep these exact — never shorten:**
|
|
69
|
+
|
|
70
|
+
- Numbers, and negation words: not, never, no, only, except. Flipping one changes the
|
|
71
|
+
meaning — never worth a saved word.
|
|
72
|
+
- Code, commands, file names, and error text — word for word. Do not compress or reword them.
|
|
73
|
+
|
|
74
|
+
**Do not narrate your tool use.** Skip "Now I'll read the file", "Let me check", "I'm going
|
|
75
|
+
to run...". Do the work, then report the result.
|
|
76
|
+
|
|
77
|
+
**Do not dump long output — quote the shortest line that proves the point.** For a long log
|
|
78
|
+
or stack trace, paste the one decisive line and name the file for the rest. A wall of raw log
|
|
79
|
+
buries the finding.
|
|
80
|
+
|
|
81
|
+
**Do not decorate:**
|
|
82
|
+
|
|
83
|
+
- No emoji as decoration.
|
|
84
|
+
- No table when one sentence does the job. Use a table only for real rows and columns.
|
|
85
|
+
- No made-up short forms (cfg, impl, req). The tokenizer splits them the same as the full
|
|
86
|
+
word, so you save nothing and the reader still has to decode.
|
|
87
|
+
|
|
88
|
+
**Write it out in full — normal prose — where being terse causes mistakes:** the numbered
|
|
89
|
+
manual steps above (deploys, SQL, config, restarts), security warnings, and anything hard to
|
|
90
|
+
undo. Clarity wins there, every time.
|
|
91
|
+
|
|
54
92
|
## Check before you send
|
|
55
93
|
|
|
56
94
|
- Can I cut half the words and keep the meaning? Cut them.
|
|
@@ -51,6 +51,9 @@ function reminder() {
|
|
|
51
51
|
' say what it means in plain words instead. Stay exact — keep file names, errors, steps.',
|
|
52
52
|
' 4. Any manual action (deploy, SQL, config, restart) goes in a numbered list under a',
|
|
53
53
|
' "What you need to do:" heading. One action per step, in order.',
|
|
54
|
+
' 5. Trim output: drop filler/pleasantries/hedging, no tool-use narration, quote the',
|
|
55
|
+
' shortest decisive log line (not the whole dump), no decorative tables/emoji. Keep',
|
|
56
|
+
' numbers, negations, code, and errors exact. Clarity always wins over shortness.',
|
|
54
57
|
'',
|
|
55
58
|
'MIRROR THIS PERSON: read how the developer writes to you in this session — the words',
|
|
56
59
|
'and phrases they use, and how long their sentences run — and answer back in that same',
|