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.
@@ -6,7 +6,7 @@ project: Library
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-09-03
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-11
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-11
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-10
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-11
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.799",
3
+ "version": "1.0.801",
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",
@@ -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',