toga-ai 1.0.704 → 1.0.706

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.
@@ -16,7 +16,7 @@ project: _Underscore
16
16
  client: compass-canada
17
17
  type: profile
18
18
  status: active
19
- updated: 2026-08-28
19
+ updated: 2026-08-31
20
20
  owners: [jcardinal, bala, tcox, apeterson]
21
21
  files: []
22
22
  related:
@@ -28,6 +28,7 @@ related:
28
28
  - ../compass-usa/features/stranded-approval-reassignment.md
29
29
  - ../compass-usa/features/people-file-user-lifecycle.md
30
30
  - ../compass-usa/features/isfulfillable-data-quality-and-type-rule.md
31
+ - ../compass-usa/features/mits-sales-order-transmission-alerting.md
31
32
  - features/french-order-email-localization.md
32
33
  - features/order-fulfillment-status-per-line.md
33
34
  - features/item-fulfillment-tableviews.md
@@ -72,6 +73,14 @@ to but distinct from Compass USA. Like Compass USA it spans the **2.0** commerce
72
73
  - Worker crons for the G&T flow live under `worker/crons/toga2/compasscanada/workflow/`
73
74
  (`1_…` transmit SOs to MITS, `2_…` transmit POs to vendors, `3_…` status from G&T cXML,
74
75
  `4_…` import G&T ASNs).
76
+ - **⚠ MITS transmit alerting has diverged from Compass USA.** Canada's `1_…transmit…to_mits`
77
+ cron still raises all **three** of its failure alerts as in-cron `App_Email_Agilant` emails
78
+ (No Items Found / more than 15 items / Invalid response from MITS API), so changing who is
79
+ notified here **is** a code edit — whereas USA's rejection path now routes through the Logs
80
+ Issue/Event pipeline and is configured against the issue instead. Canada's "Invalid response"
81
+ email also `print_r`s the full payload (ship-to PII) into the body and has no dedupe. Recipients
82
+ are currently `devteam@togatech.com` + `vburks@togatech.com`. See
83
+ [MITS Sales-Order Transmit Alerting](../compass-usa/features/mits-sales-order-transmission-alerting.md).
75
84
 
76
85
  ## Storefront notes (toga2-commerce)
77
86
  - Runs the same `toga2-commerce` storefront (2.0, consumes api2), with English + French cart
@@ -10,7 +10,7 @@
10
10
  | [Compass MITS PO → SO Item Linking](features/mits-po-to-so-item-linking.md) | 2.0 | MITS sends Compass inbound Purchase Orders (`POST /v2/purchase-orders`) against a Sales Order (`mitsSalesOrder`). | _underscore/Model/Compass/PurchaseOrder.php, worker/crons/toga2/compass/workflow/3a_import_office_depot_purchase_orders.php |
11
11
  | [Compass MITS PO Transmission to Vendors](features/mits-po-transmission-to-vendors.md) | 2.0 | The 1.0 worker cron `2_transmit_mits_purchase_orders_to_vendors.php` transmits Compass PurchaseOrders to their vendors (Office Depot, Strategic Systems, Compass | worker/crons/toga2/compass/workflow/2_transmit_mits_purchase_orders_to_vendors.php, worker/crons/toga2/compasscanada/workflow/2_transmit_mits_purchase_orders_to_vendors.php, library/app/client/compass.php |
12
12
  | [Compass MITS PO rejection — zero line items (400 + Issue + PM alert email)](features/mits-po-zero-line-item-rejection.md) | 2.0 | MITS transmits Compass purchase orders that carry **`"purchaseOrderItems": []`** (real example: PO `50309196-1`, `mitsSalesOrder` `MR244630`). | _underscore/Model/Compass/PurchaseOrder.php, _underscore/Model/Compass/Usa/PurchaseOrder.php, _underscore/Model/Compass/Canada/PurchaseOrder.php, worker2/Worker/Client/Compass/reports/PurchaseOrderRejectionEmail.php |
13
- | [Compass MITS Sales-Order Transmission — Rejection Alerting (Issue/Event, not email-in-cron)](features/mits-sales-order-transmission-alerting.md) | 2.0 | When MITS **rejects** a Compass sales order transmitted by the 1.0 cron `1_transmit_compass_sales_orders_to_mits.php`, the alert is no longer an email built ins | worker/crons/toga2/compass/workflow/1_transmit_compass_sales_orders_to_mits.php, worker2/Worker/Infrastructure/Errors.php, _underscore/Model/Core/Logs/Issue.php, _underscore/Model/Core/Logs/IssueEmailAddress.php, dbchanges2/Logs/2026-08-04a - MITS rejection business recipients.sql |
13
+ | [Compass MITS Sales-Order Transmit Alerting (US Issue/Event vs Canada in-cron email)](features/mits-sales-order-transmission-alerting.md) | 2.0 | How a failure in the `1_transmit_..._sales_orders_to_mits.php` cron reaches a human — for **both** Compass tenants, because **they no longer work the same way** | worker/crons/toga2/compass/workflow/1_transmit_compass_sales_orders_to_mits.php, worker/crons/toga2/compasscanada/workflow/1_transmit_compassCanada_sales_orders_to_mits.php, worker2/Worker/Infrastructure/Errors.php, tools/mvc/errors/post.php, _underscore/Model/Core/Logs/Issue.php, _underscore/Model/Core/Logs/IssueEmailAddress.php, dbchanges2/Logs/2026-08-04a - MITS rejection business recipients.sql |
14
14
  | [Compass MR/MA Order Auto-Approval & Status Gate](features/mr-ma-order-approval-and-status.md) | 2.0 | Compass **MR** and **MA** sales orders are system-generated from the MITS / Office Depot EDI pipeline (they do not originate as user-entered SA orders) and must | _underscore/Model/Compass/SalesOrder.php, _underscore/Model/Compass/PurchaseOrder.php, worker/crons/toga2/compass/workflow/3a_import_office_depot_purchase_orders.php |
15
15
  | [Compass ODP EDI 850 Line-Item Resolution (VA part number to IN SKU fallback)](features/odp-edi-850-item-resolution.md) | 1.0 | How each **PO1 line** on an inbound Office Depot (ODP) **EDI 850** is resolved to a real `Client_Compass` catalog item before cron `3a_import_office_depot_purch | worker/crons/toga2/compass/workflow/3a_import_office_depot_purchase_orders.php, library/app/Edi.php |
16
16
  | [Compass Office Depot EDI 855 Acknowledgement + Over-Quantity PO Guard](features/odp-edi-855-acknowledgement-and-overquantity-guard.md) | 1.0 | How Compass acknowledges Office Depot (ODP) inbound **EDI 850** purchase orders with an **X12 855**, and the **over-quantity guard** that rejects a duplicate PO | worker/crons/toga2/compass/workflow/3a_import_office_depot_purchase_orders.php, worker/crons/toga2/compass/workflow/4_transmit_office_depot_po_acknowledgements.php, library/app/edi.php |
@@ -1,59 +1,99 @@
1
1
  ---
2
- title: Compass MITS Sales-Order Transmission — Rejection Alerting (Issue/Event, not email-in-cron)
2
+ title: Compass MITS Sales-Order Transmit Alerting (US Issue/Event vs Canada in-cron email)
3
3
  framework: "2.0"
4
4
  project: _Underscore
5
5
  client: compass-usa
6
6
  type: client-feature
7
7
  status: active
8
- updated: 2026-08-04
9
- owners: ["dfranks"]
8
+ updated: 2026-08-31
9
+ owners: ["dfranks", "bala"]
10
10
  files:
11
11
  - worker/crons/toga2/compass/workflow/1_transmit_compass_sales_orders_to_mits.php
12
+ - worker/crons/toga2/compasscanada/workflow/1_transmit_compassCanada_sales_orders_to_mits.php
12
13
  - worker2/Worker/Infrastructure/Errors.php
14
+ - tools/mvc/errors/post.php
13
15
  - _underscore/Model/Core/Logs/Issue.php
14
16
  - _underscore/Model/Core/Logs/IssueEmailAddress.php
15
17
  - dbchanges2/Logs/2026-08-04a - MITS rejection business recipients.sql
16
18
  related:
17
19
  - mits-po-transmission-to-vendors.md
20
+ - ../../compass-canada/profile.md
18
21
  - ../../../2.0/apps/worker2/features/error-escalation-cron.md
19
22
  - ../../../2.0/apps/_underscore/features/error-reporting-issue-event.md
20
23
  - ../../../1.0/apps/library/features/error-capture-1-0.md
24
+ - ../../../1.0/apps/tools/features/errors-curation-console.md
21
25
  ---
22
26
 
23
27
  ## Summary
24
28
 
25
- When MITS **rejects** a Compass sales order transmitted by the 1.0 cron
26
- `1_transmit_compass_sales_orders_to_mits.php`, the alert is no longer an email built inside the
29
+ How a failure in the `1_transmit_..._sales_orders_to_mits.php` cron reaches a human — for
30
+ **both** Compass tenants, because **they no longer work the same way**.
31
+
32
+ When MITS **rejects** a Compass **USA** sales order, the alert is not an email built inside the
27
33
  cron. It is a **business exception** raised into the shared Logs Issue/Event pipeline, and its
28
- recipients are **rows in `Logs.IssueEmailAddress`**.
34
+ recipients are **rows in `Logs.IssueEmailAddress`**. The Compass **Canada** cron still sends a
35
+ direct `App_Email_Agilant` for the same rejection.
36
+
37
+ **Consequence for anyone handed a ticket like "add <person> to the MITS error emails": the
38
+ answer depends on the tenant and on which failure.** Check the table below before opening
39
+ either file — half of these alerts have no PHP to change, and the other half have no
40
+ configuration surface at all.
41
+
42
+ ## Which alert goes where (check this first)
43
+
44
+ | Tenant / failure | Mechanism | To add a recipient |
45
+ |---|---|---|
46
+ | **USA** — MITS rejects the order (`responseCode != 200`) | `App_Exception_Business` → Logs Issue/Event | **Data/UI change.** Add a row to `Logs.IssueEmailAddress` against the issue — no code edit |
47
+ | **USA** — "MITS API Script Error: No Items Found" | in-cron `App_Email_Agilant` | edit `addTo()` in the cron |
48
+ | **Canada** — "No Items Found" | in-cron `App_Email_Agilant` | edit `addTo()` in the cron |
49
+ | **Canada** — "Sales Order Items are more than 15" | in-cron `App_Email_Agilant` | edit `addTo()` in the cron |
50
+ | **Canada** — "Invalid response from MITS API" (the rejection path) | in-cron `App_Email_Agilant` | edit `addTo()` in the cron |
29
51
 
30
- **Consequence for anyone handed a ticket like "add <person> to the MITS error emails": there is
31
- no PHP to change.** It is a one-row data change delivered as a `dbchanges2/Logs/` migration.
52
+ So the USA cron is a **hybrid**: its rejection path is issue-routed, but it still holds one
53
+ hardcoded email for the no-items case. Only the rejection branch was migrated.
32
54
 
33
- ## How it works
55
+ Both crons are live — `worker/schedules/cron.worker.sync.json` schedules
56
+ `toga2/compass/workflow/1_...` and `toga2/compasscanada/workflow/1_...`. (Per the
57
+ [ODP pipeline doc's](../workflows/odp-order-pipeline-to-netsuite.md) rule, a grep hit under
58
+ `crons/toga2/**` is not proof a script runs — these two were verified against the schedule.)
59
+
60
+ **Current recipients on every in-cron email above:** `devteam@togatech.com` +
61
+ `vburks@togatech.com` (business stakeholder, added 2026-08-31).
62
+
63
+ ## How the USA rejection path works
34
64
 
35
65
  - The cron raises
36
66
  `throw new App_Exception_Business('COMPASS_SALES_ORDER_MITS_TRANSMIT_REJECTED', …, URGENCY_HIGH)`
37
67
  on a MITS rejection. (Before 2026-08-03 this block was a hardcoded `new App_Email_Agilant()`
38
- with `addTo('devteam@togatech.com')`.)
39
- - Capture creates/dedupes a `Logs.Issue` keyed on the `issueKey`, and the worker2
40
- `Infrastructure/Errors/Escalate` cron does all outbound notification — business email to the
41
- configured recipients **and**, independently, the dev-team ClickUp task. See
68
+ with `addTo('devteam@togatech.com')` — i.e. exactly what Canada still does.)
69
+ - Capture creates/dedupes a `Logs.Issue` keyed on the `issueKey`, so repeated rejections are
70
+ **one issue with an occurrence count**, not one email per failure. It is visible to internal
71
+ staff in the Tools `/errors` console.
72
+ - The worker2 `Infrastructure/Errors/Escalate` cron does all outbound notification — business
73
+ email to the configured recipients **and**, independently, the dev-team ClickUp task. See
42
74
  [error-escalation-cron](../../../2.0/apps/worker2/features/error-escalation-cron.md).
43
75
  - Recipients live in `Logs.IssueEmailAddress` (FK `issueId` → `Logs.Issue`), scoped by
44
76
  `clientId` (`0` = all clients).
45
77
 
46
- ### Adding a recipient (the correct pattern)
78
+ ### Adding a recipient — two routes
79
+
80
+ **Route 1 (preferred): the Tools `/errors` console.** `tools/mvc/errors/post.php` exposes
81
+ `add-recipient` / `delete-recipient`, which write `IssueEmailAddress`
82
+ (`uuid, issueId, clientId, emailAddress, toCcBcc`) and set `Issue.isManaged = 1`. `clientId = 0`
83
+ requires an explicit second confirmation checkbox, because one mistyped `0` silently sends one
84
+ client's business users every other client's error content. See
85
+ [errors-curation-console](../../../1.0/apps/tools/features/errors-curation-console.md).
47
86
 
48
- Write a `dbchanges2/Logs/YYYY-MM-DD<letter>` migration that:
87
+ **Route 2: a `dbchanges2/Logs/YYYY-MM-DD<letter>` migration** — use this when the change must
88
+ ride a deploy across environments. It must:
49
89
 
50
- 1. **Looks the issue up by `issueKey`**, never by its `id`. The id is assigned on the issue's
90
+ 1. **Look the issue up by `issueKey`**, never by its `id`. The id is assigned on the issue's
51
91
  **first occurrence** and is therefore not stable across environments.
52
- 2. Uses **`clientId = 0`**. This `issueKey` is raised from a Compass-only code path, and an
92
+ 2. Use **`clientId = 0`**. This `issueKey` is raised from a Compass-only code path, and an
53
93
  occurrence recorded without client attribution resolves against scope `0` only — a row scoped
54
94
  to the Compass `clientId` can deliver nothing. (Never use `0` for an `issueKey` raised from
55
95
  shared code — that is a cross-tenant leak.)
56
- 3. Is **idempotent** via `INSERT … WHERE NOT EXISTS`, mirroring the unique key
96
+ 3. Be **idempotent** via `INSERT … WHERE NOT EXISTS`, mirroring the unique key
57
97
  `uq_issue_client_address_type`.
58
98
 
59
99
  Configuration is **never retroactive**: `shouldNotify()` fires on the first occurrence, on
@@ -62,28 +102,49 @@ zero events. The first email lands on the **next live rejection**, not on existi
62
102
 
63
103
  ## Gotchas / known issues
64
104
 
65
- - **Do not "modernize" this alert back into the cron.** Migrating it to
105
+ - **Canada is the pre-2026-08-03 design, and it still carries the two problems that migration
106
+ fixed.** Its "Invalid response from MITS API" email `print_r`s the **whole transmission
107
+ payload** into the body — which includes ship-to addressee, attention line, street address and
108
+ phone number — and there is no issue dedupe, so a bad run emails once per order. Treat
109
+ bringing Canada onto `App_Exception_Business` as known outstanding work, not a new idea; the
110
+ USA block is the reference implementation.
111
+ - **Canada's alerts do not send where outbound email is disabled.** The USA no-items email sets
112
+ `sendEmailEvenIfOutboundEmailIsDisabled = true`; none of Canada's three do. On any environment
113
+ with outbound email off, Canada fails **silently**.
114
+ - **Do not "modernize" the USA rejection alert back into the cron.** Migrating it to
66
115
  `_Model_Client_EmailTemplate::send` (or any in-cron email) reverts the move to the Issue/Event
67
116
  pipeline and removes the recipient configuration surface entirely.
68
- - **Never re-introduce the payload dump into the alert.** The original email included the
69
- transmission payload, which carries ship-to addressee, attention line, street address and phone
70
- number. The Issue message is stored in a table **shared across every client**, displayed to
71
- internal staff in the Tools `/errors` console, pushed to ClickUp, and emailed — so the payload
72
- was deliberately removed. Alerts here name the order, not the person.
73
- - **The MITS cron holds its API credentials inline in the file.** Treat that file as
117
+ - **Never re-introduce the payload dump into the USA alert.** The Issue message is stored in a
118
+ table **shared across every client**, displayed to internal staff in the Tools `/errors`
119
+ console, pushed to ClickUp, and emailed — so the payload was deliberately removed. Alerts here
120
+ name the order, not the person. (This is precisely what Canada still does wrong.)
121
+ - **The MITS crons hold their API credentials inline in the file.** Treat both files as
74
122
  secret-bearing when copying snippets anywhere (tickets, PR bodies, knowledge docs).
75
123
  - **Adding a recipient does not turn ClickUp ticketing off.** Routing is both-and, not
76
- either-or — see the escalation-cron doc for the `elseif` bug this used to be.
124
+ either-or: `_Worker_Infrastructure_Errors` runs `if ($recipients !== null)` and
125
+ `if ((bool) $issue->createsClickupTask)` as **two independent** branches.
126
+ **⚠ The comment above the insert in `tools/mvc/errors/post.php` still claims the opposite**
127
+ ("it stops creating ClickUp tasks for the dev team and starts emailing these people
128
+ instead") — that describes the old `elseif` form and is **stale**. Trust `Errors.php`.
77
129
  - As of 2026-08-04 prod `Logs.IssueEmailAddress` is empty, so this is the **first business-routed
78
130
  issue on the platform**: `processBusinessIssue()` will execute in production for the first time
79
131
  when this issue next fires. Watch that run rather than assuming it works.
80
132
 
81
133
  ## Change history
134
+ - 2026-08-31 — Added `vburks@togatech.com` alongside `devteam@togatech.com` on **every** in-cron
135
+ `App_Email_Agilant` alert in both MITS transmit crons (USA has one, Canada has three), so the
136
+ business stakeholder is alerted on transmission failures. Broadened this doc to cover **both**
137
+ tenants after finding they had diverged: the USA rejection path is Issue/Event-routed
138
+ (recipients configured against the issue, no `addTo()` to edit) while **Canada still uses the
139
+ old direct email** for the same branch — including the PII-bearing payload dump and with no
140
+ dedupe. Also recorded that the USA cron is a hybrid (its no-items alert is still an in-cron
141
+ email), that recipients can be managed from the Tools `/errors` console as well as a
142
+ `dbchanges2/Logs` migration, that Canada's alerts are suppressed wherever outbound email is
143
+ disabled, and that the stale `tools/mvc/errors/post.php` comment misstates ClickUp-vs-email
144
+ routing. (bala)
82
145
  - 2026-08-04 — Documented that MITS rejection alerting moved (worker `5521854b`, 2026-08-03) from a
83
146
  hardcoded in-cron `App_Email_Agilant` to `App_Exception_Business` +
84
147
  `Logs.IssueEmailAddress` recipients, so adding an alert recipient is a data change, not a code
85
148
  change. Recorded the deliberate removal of the PII-bearing payload dump from the alert, the
86
149
  look-up-by-`issueKey` / `clientId = 0` / `NOT EXISTS` migration pattern, and that recipient
87
150
  configuration only takes effect on the next live occurrence. (dfranks)
88
- </content>
89
- </invoke>
@@ -21,6 +21,10 @@ answers. This applies to **all** developers, **both** frameworks, and **every**
21
21
 
22
22
  This is a team directive, not a style tip. Follow it by default.
23
23
 
24
+ > **Now enforced always-on.** The short, hard version lives in `rules/common/communication.md`,
25
+ > which loads in **every** session (not just kickoff). This doc is the fuller reference; the
26
+ > rule file is what binds. Keep the two in sync.
27
+
24
28
  ## The rules
25
29
 
26
30
  1. **Be short.** Say the thing, then stop. Cut every sentence that does not help the reader
@@ -52,6 +56,9 @@ Long, wordy, jargon-heavy answers are hard and tiring to read, especially for no
52
56
  English speakers. The team moves faster when Claude is brief and plain. Clear beats clever.
53
57
 
54
58
  ## Change history
59
+ - 2026-08-31 — Moved the hard, short version to always-on `rules/common/communication.md` so it
60
+ loads every session, not just some kickoffs. Team was still finding output too long and too
61
+ complex; the on-demand-only load was part of why. (jcardinal)
55
62
  - 2026-08-05 — Standard recorded: keep all communication short, clear, and plain; avoid
56
63
  obscure jargon (e.g. "sargability"); lead with the answer; stay technical but brief.
57
64
  Team-wide, both frameworks. (jcardinal)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.704",
3
+ "version": "1.0.706",
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",
@@ -0,0 +1,34 @@
1
+ # Communication Rules
2
+
3
+ You talk to the whole team. Many teammates read English as a second language, and long
4
+ answers tire them out or lose them. So keep every message short, plain, and clear — in your
5
+ thinking, your plans, and your final answers. This is a hard team rule, not a style tip.
6
+
7
+ **Clear with more words beats clever with fewer. But short and clear is the goal.**
8
+
9
+ ## The rules
10
+
11
+ 1. **Cut words.** Say the point, then stop. Delete any sentence that does not help the reader
12
+ do something or decide something. One line is better than three.
13
+ 2. **Use common words.** Pick the everyday word over the fancy one. If a simpler word means
14
+ the same thing, use it.
15
+ 3. **Drop the jargon.** Do not use rare technical words (like "idempotent", "cardinality",
16
+ "sargable", "orthogonal", "canonical"). Say what they mean in plain words instead.
17
+ - Bad: "make the query sargable"
18
+ - Good: "let the query use the index — don't wrap the indexed column in a function"
19
+ 4. **Answer first.** Put the main point in the first line. Reasons come after, only if needed.
20
+ No long wind-up.
21
+ 5. **Use lists.** More than two parts? Use a numbered or bulleted list, not a paragraph.
22
+ 6. **Stay technical, stay exact.** Keep the real detail — file names, error text, exact steps.
23
+ Short does not mean vague. Be brief AND precise.
24
+
25
+ ## Check before you send
26
+
27
+ - Can I cut half the words and keep the meaning? Cut them.
28
+ - Is there a rare word a non-native reader might miss? Swap it.
29
+ - Is my main point in the first line? If not, move it up.
30
+
31
+ ## Why
32
+
33
+ Wordy, jargon-heavy output is hard and slow to read — worse for non-native English readers.
34
+ The team moves faster when you are brief and plain. Clear beats clever.