toga-ai 1.0.848 → 1.0.849

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.
@@ -249,40 +249,3 @@ names, reads `Core.ClientEmailDomains` / `Core.Clients`, and inserts into `Logs_
249
249
  added in worker2 on 2026-09-16, or the block silently under-covers the protected set.
250
250
  - **ops** — rotate every secret in `tools/config.production.ini`; consider a least-privilege
251
251
  Compass account.
252
-
253
- ## Change history
254
-
255
- - 2026-09-16 — Recorded that worker2's cross-region protected list **grew from four addresses to
256
- six** (`ALWAYS_ACTIVE_EMAILS_BOTH` + `ALWAYS_ACTIVE_EMAILS_CA`), so this tool's
257
- `isCrossRegionProtectedEmail()` block now under-covers it: the two new `@compassdigital.io`
258
- Canada-protected addresses can still be email-edited here and would silently drop out of the
259
- protected set, because the worker2 match is on email. No `tools` code changed. Detail:
260
- [PEOPLE-File User Lifecycle](../../../clients/compass-usa/features/people-file-user-lifecycle.md).
261
- (bala)
262
-
263
- - 2026-09-04 — Added **email, phone and cost-center editing** (PR tools#14,
264
- `feature/compass-user-field-edits`, **open / not merged / not deployed**): new `App_Compass`
265
- setters plus the `normaliseEmail` / `normalisePhone` / `emailDomainIsRegistered` /
266
- `usersWithEmail` / `isCrossRegionProtectedEmail` validators, a cost-center picker with a mandatory
267
- before/after persona diff, and a `Users` + primary `Contacts` write in one transaction. No schema
268
- change. Recorded the decision to ship **all three** fields against independent
269
- architecture/security advice to defer email, and that the six safety rails (typed twice,
270
- `Core.ClientEmailDomains` domain check, cross-row duplicate refusal, duplicate-twin confirmation,
271
- cross-region address block, audit-before-write) are the conditions of that decision. Recorded that
272
- **cost-center edits are deliberately temporary** because `c_erpSystemEntityId` is not overwritten.
273
- **Resolved the "no staff-actor audit trail" open item** — `Logs_<Tenant>.Record.userId` is
274
- nullable, so `recordId = 2` (`Users`) + `primaryKeyId` + staff identity in `note` works with no
275
- schema change (`note` is 255 **characters** — truncate with `mb_substr`); hence the new
276
- `[database_compasslogs]` / `[database_compasscanadalogs]` ini sections, still on the existing
277
- `[database_true]` account. Prod-verified that **neither tenant has a `UNIQUE KEY` on
278
- `Users.email`**, so the duplicate check must live in code, and that `compass-canada.com` is
279
- registered to Compass **USA** (client 2), so an email-domain allowlist must span both Compass
280
- clients. Marked PR tools#13 **merged** and the doc `active`. (ajean)
281
- - 2026-09-04 — Initial: built the two-page Compass user/persona admin (PR tools#13, unmerged) — the
282
- first `tools` pages that write to a client tenant DB, gated to `Development Team` only, with a
283
- US/Canada switcher and new `[database_compass]` / `[database_compasscanada]` ini sections reusing
284
- the existing `[database_true]` account. Recorded Jeff Cardinal's scope reset (no schema changes;
285
- `dbchanges2#478` and `worker2#160` closed unmerged) and its consequence — **activation is temporary
286
- because the `c_isKeepActive` flag was dropped**, while deactivation is durable. Logged the accepted
287
- credential-reuse risk, the 4-day session persona staleness, the missing staff-actor audit trail, and
288
- that every user search is a full scan. (ajean)
@@ -6,7 +6,7 @@
6
6
  | [Canon received-PO → NetSuite sales order sync](features/canon-received-po-netsuite-order-sync.md) | Canon-only worker cron that reads Vision customer POs and creates the matching NetSuite sales order (bundles exploded, prefixes stripped); open before touching |
7
7
  | [Compass MA Sales Order Exception Report](features/compass-ma-sales-order-exception-report.md) | Worker cron emailing ops the "Compass Refresh Exception Report" of `MA%` Compass sales orders whose ODP NetSuite order isn't created yet; open for the two-hop b |
8
8
  | [Compass Manager Approval Reminder Emails (1.0 worker crons)](features/compass-manager-approval-reminder-emails.md) | Two per-tenant Compass worker crons that email approvers about sales orders awaiting a decision; open before touching the approval `orderUrl` (both still send a |
9
- | [Compass Partial In-Transit & Delivered Emails (per package)](features/compass-partial-in-transit-delivered-emails.md) | Compass USA and Compass Canada send a **per-package** in-transit email (and a matching delivered email) instead of one email listing the whole order. |
9
+ | [Compass Partial In-Transit & Delivered Emails (per package)](features/compass-partial-in-transit-delivered-emails.md) | Compass USA + Canada per-package in-transit and delivered emails; open for the two-pass drain, the ASN-vs-TrackingNumbers window clock, the recipient fallback, |
10
10
  | [Elite TOGA 2.0 → TOGaDeskSupport Standalone Attachment Sync](features/elite-togadesk-attachment-sync.md) | Standalone 5-min Elite cron that downloads Freshservice-origin file attachments from TOGA 2.0 (`sourceUrl` S3) into TOGaDeskSupport; open for the uuid-resolutio |
11
11
  | [Forecast2 ↔ NetSuite Reconciliation & Trueup Tooling](features/forecast2-netsuite-reconciliation.md) | CLI tools (`test/@dave/`, `tools/bin/forecast/`) that audit and repair drift between the prod `Forecast` DB and NetSuite; open when reconciling Sales / OpenOrde |
12
12
  | [Forecast2 Supporting-Records Nightly Import (1.0 cron) — Customers & ConsolidatedCustomers](features/forecast2-supporting-records-import.md) | Nightly 1.0 cron that pulls Forecast2 lookup/dimension tables (Accounts, Classifications, Customers, ConsolidatedCustomers, Employees) from NetSuite; open when |
@@ -30,6 +30,8 @@ related:
30
30
  - ../../../2.0/apps/_underscore/features/item-fulfillment-stage-lifecycle-and-order-status.md
31
31
  ---
32
32
 
33
+ Compass USA + Canada per-package in-transit and delivered emails; open for the two-pass drain, the ASN-vs-TrackingNumbers window clock, the recipient fallback, and the many freeze/backlog gotchas.
34
+
33
35
  ## Summary
34
36
 
35
37
  Compass USA and Compass Canada send a **per-package** in-transit email (and a matching
@@ -39,7 +41,9 @@ cron builds three zones: **Items in this shipment** (just that package), **Alrea
39
41
  and earlier packages). The dynamic HTML is injected into a stored `EmailTemplates` body via the
40
42
  `sendEmail` scripted API. Canada renders EN or FR per the user's language setting.
41
43
 
42
- ## Key files / entry points
44
+ ## How it works
45
+
46
+ ### Key files / entry points
43
47
 
44
48
  - `worker/crons/toga2/compass/update_salesorder_status_from_odp.php` — Compass USA prod cron,
45
49
  registered in `worker/schedules/cron.worker.sync.json` as **"Update Compass SalesOrder Status
@@ -55,7 +59,7 @@ and earlier packages). The dynamic HTML is injected into a stored `EmailTemplate
55
59
  - Shared helper set in each cron: `getOrderFulfillmentData`, `buildItemRowsHtml`,
56
60
  `buildSectionHeaderHtml`, `buildPackageBlockHtml`, `buildTrackingUrl`, `buildOrderItemsHtml`.
57
61
 
58
- ## How it works
62
+ ### Mechanics
59
63
 
60
64
  1. **Driving query** finds shipped sales orders and their tracking numbers (`computedStatusSlug
61
65
  = 'shipped'`, `c_dtInTransitEmailSent IS NULL`, rolling date window on
@@ -214,7 +218,7 @@ the tracking number as emailed (it retries next run).
214
218
  `#111928`; P/N `#666666`; Qty regular dark `#111928`.
215
219
  - **20px** gap between consecutive "Already shipped" packages (16px spacer + 4px heading top).
216
220
 
217
- ## Data model
221
+ ### Data model
218
222
 
219
223
  - `TrackingNumbers`: `number`, `trackingUrl`, `shippingCarrierId`, `dtCreated`, `status`,
220
224
  `c_dtInTransitEmailSent` (the idempotency flag the cron sets).
@@ -223,7 +227,7 @@ the tracking number as emailed (it retries next run).
223
227
  bridge). `ItemFulfillments.salesOrderId` ties a package to the buyer SO.
224
228
  - `EmailTemplates` — the stored template body with `{placeholder}` tokens.
225
229
 
226
- ## Client variations
230
+ ### Client variations
227
231
 
228
232
  - **Compass USA** — English only; `update_salesorder_status_from_odp.php`. Has the full
229
233
  2026-09-03 hardening: two-pass drain, 400-row cap, 14-day window, `isTrackingStatusFinal()`,
@@ -350,74 +354,7 @@ the tracking number as emailed (it retries next run).
350
354
  tracking-numbers today; the plan (not built) is to move this email logic into a Compass `postPut`
351
355
  interceptor and retire this 1.0 cron.
352
356
 
353
- ## Change history
354
- - 2026-09-16 — **Re-anchored the in-transit window on `AdvanceShippingNotices.dtCreated`** (was
355
- `TrackingNumbers.dtCreated`, `update_salesorder_status_from_odp.php` line ~432);
356
- `IN_TRANSIT_EMAIL_LOOKBACK_DAYS` stays 7 with a comment explaining why. Cause: commit `81824325`
357
- (2026-09-15 11:35) cut the lookback 14 → 7 while the window still measured the **invoice** date,
358
- so 22 shipments invoiced 2026-09-03 whose ASNs landed 2026-09-15 fell out of the window (only
359
- MR245462 still owed a real email; the other 21 read DELIVERED). Verified on prod: 22 rows in,
360
- 0 rows lost, 1 catch-up email. **Corrected the old "invoice tracking numbers never touch the ASN
361
- chain" gotcha** — the invoice sync is in fact the normal origin of Compass `TrackingNumbers` rows;
362
- new doc
363
- [tracking-number origin and the ASN link](../../../clients/compass-usa/features/tracking-number-origin-and-asn-link.md).
364
- Recorded the **rejected** alternative of making 3b email for pre-existing tracking numbers (it
365
- would downgrade split orders from the partial template to the plain one). Not yet committed or
366
- deployed. (bala)
367
-
368
- - 2026-09-10 — Recorded that a zero-line-item ASN is invisible to this cron (candidates come from
369
- `AdvanceShippingNoticeItemUnits(_TrackingNumbers)`), the failure mode Compass Canada's G&T
370
- importer produced until 2026-09-08. (bala)
371
-
372
- - 2026-09-04 — **Fixed the Compass USA in-transit email outage (2026-08-27 → 2026-09-03, 130–190
373
- emails/day → near zero).** Root cause: already-delivered rows were `continue`d without stamping
374
- `c_dtInTransitEmailSent`, so the candidate set grew to 2,379 and every run burned its
375
- `cronInitialization(3600)` hour inside rows dating back to a hardcoded `'2026-06-15'`, never
376
- reaching new ASNs. Fix: two-pass drain (stamp finished rows, then send), newest-first
377
- `ORDER BY MAX(dtCreated) DESC` with `IN_TRANSIT_EMAIL_BATCH_SIZE = 400`, rolling
378
- `IN_TRANSIT_EMAIL_LOOKBACK_DAYS = 14` replacing the fixed date, and `isTrackingStatusFinal()`
379
- short-circuiting the carrier call on `DELIVERED`/`RETURNED_TO_SENDER` using the status worker2
380
- `Sync/TrackingNumbers` already maintains. Also **widened the recipient**: `LEFT OUTER JOIN Users`
381
- + `Contacts`/`ContactEmailAddresses` with an ownership guard and
382
- `IFNULL(Users.email, ContactEmailAddresses.emailAddress)`, which recovered 12 EDI-created MR
383
- orders that have no `Users` row (regression-checked: 4,416 of 4,419 SA rows selected by both old
384
- and new queries, 0 gained, 0 lost, identical resolved address/name). Backlog cleared by
385
- **stamping** 64,132 out-of-window + 421 final-status rows rather than emailing them. Recorded
386
- that **invoice tracking numbers are not in scope** (bridged via `InvoiceTrackingNumbers`, never
387
- the ASN chain) and that a **`&` in a cron filename stops the cron dead**. Canada got the batching
388
- changes only (renamed to `update_salesorder_status_from_g&t.php`; duplicate
389
- `workflow/3_update_salesorder_status_from_grand_and_toy.php` deleted); its recipient block is
390
- **still `INNER JOIN Users`**. New OneUptime monitor `Monitor/Compass/InTransitEmailQueue` now
391
- watches this queue — see
392
- [OneUptime push-metric monitors](../../../2.0/apps/worker2/features/oneuptime-worker2-monitoring.md). (bala)
393
- - 2026-08-26 — Flagged the **duplicated `_status` CASE** in the three crons as a standing divergence
394
- risk after the 2.0 Compass fulfillment rule was rewritten. Verified the crons are unaffected: their
395
- copies only emit canceled / pendingApprovalUnknown / pendingFulfillment / shipped and filter on
396
- `shipped`, and the pendingFulfillment gate was left byte-identical. No code change here. (bala)
397
-
398
- - 2026-08-24 — Recorded the **conflict with the new 2.0 platform-wide tracking-status refresh**: that
399
- refresh writes `TrackingNumbers.status` via api2 PUT for all clients, and this cron's delivered
400
- UPDATE is guarded by `WHERE status <> 'DELIVERED'` — so if the refresh marks a Compass row
401
- `DELIVERED` first, the delivered email never sends. Noted there is no `postPut` interceptor on
402
- tracking-numbers and the plan to move this email logic into a Compass `postPut` interceptor and
403
- retire this cron. Added `send_delivered_email.php` to the file list. (bala)
404
- - 2026-08-03 — Compass Canada **item rows are now localized**: titles resolved from the
405
- `ItemTranslations` sidecar (two-column select + PHP fallback, never a mixed-collation SQL
406
- `COALESCE`) and translated `N/P` / `Qté` labels; language resolution moved onto the shared 1.0
407
- helper `App_Client_CompassCanada::resolveUserLanguageCode()` with `try/catch` → English at every
408
- call site so a lookup failure can't abort the rest of the run. Item text is entity-escaped for the
409
- iso-8859-1 send. Flagged the **`library` deployment dependency** (uncommitted on `_production`;
410
- all 8 Canada crons fatal without it). TRUE-80543, not yet deployed. Detail lives on
411
- [Compass Canada French order emails](../../../clients/compass-canada/features/french-order-email-localization.md). (bala)
412
- - 2026-06-18 — Switched Canada `getOrderFulfillmentData` from the ASN chain to the
413
- `ItemFulfillmentItems` line bridge (match Compass USA); item info all 14px. (bala)
414
- - 2026-06-18 — Brought both prod crons to parity: per-package partial assembly, `buildTrackingUrl`
415
- carrier-URL precedence, POST body transport + `throwExceptionOnApiError=true`, mark-sent only
416
- on success; restored crons after a git stash/merge had duplicated helper functions. (bala)
417
- - 2026-06-17 — Styling pass: 18px headers, medium dark item titles, regular dark Qty, 20px
418
- between packages. (bala)
419
-
420
- ## Related docs
357
+ ## Related
421
358
 
422
359
  - `2.0/apps/_underscore/features/email-template-sending.md` — the `sendEmail` scripted API +
423
360
  its silent-failure hardening.
@@ -2,7 +2,7 @@
2
2
 
3
3
  | Doc | Summary |
4
4
  |-----|---------|
5
- | [API (api2 / TOGa API v2) Architecture](architecture.md) | `api2` is the backend powering the public **TOGa 2.0 API**. |
5
+ | [API (api2 / TOGa API v2) Architecture](architecture.md) | Backend for the public TOGa 2.0 API — metadata/ACL-driven REST JSON (`/v2`) + a cXML gateway, both over `_underscore` `_Model`; open for the response-envelope c |
6
6
  | [API-Key Authentication (/v2/auth/api) and what a key can actually reach](features/api-key-authentication-and-scoping.md) | How a machine caller gets a bearer token from `POST /v2/auth/api` and exactly what that key can reach; open when scoping an API consumer or auditing what a key |
7
7
  | [API Payload Interceptors (metadata-registered prePost/postPut model hooks)](features/api-payload-interceptors.md) | How `_Model` prePost/postPost/prePut/postPut hooks are dispatched by the api2 /v2 engine only when a metadata row exists — the missing-row silent no-op, the wro |
8
8
  | [Multi-Client (Cross-Client) Data Retrieval](features/cross-client-data-retrieval.md) | The scatter-gather engine that returns one entitled user's records across many client DBs from a single GET (triggered by a `client` query option); open when wo |