toga-ai 1.0.73 → 1.0.75
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/elite-freshservice-sync.md +3 -0
- package/knowledge/2.0/apps/_underscore/features/carrier-shipping-labels.md +3 -0
- package/knowledge/2.0/apps/_underscore/features/recursive-item-fulfillments.md +3 -0
- package/knowledge/2.0/apps/_underscore/features/tracking-number-bridges.md +3 -0
- package/knowledge/2.0/apps/toga2-supply/features/fulfill-and-ship.md +3 -0
- package/knowledge/2.0/apps/worker2/features/clickup-project-routing.md +3 -0
- package/knowledge/2.0/apps/worker2/features/creating-worker-actions.md +3 -0
- package/knowledge/2.0/apps/worker2/features/elite-freshservice-sync.md +4 -0
- package/knowledge/2.0/apps/worker2/features/monitoring-framework.md +3 -0
- package/knowledge/CONVENTIONS.md +16 -0
- package/knowledge/clients/compass-usa/INDEX.md +1 -1
- package/knowledge/clients/compass-usa/features/asn-to-item-fulfillment.md +56 -11
- package/knowledge/clients/nycdoe/features/servicenow-integration.md +3 -0
- package/knowledge.js +8 -0
- package/package.json +1 -1
|
@@ -164,3 +164,6 @@ Pass `true` for the dedup GET — errors must not silently empty the dedup array
|
|
|
164
164
|
|
|
165
165
|
Each ticket sync is wrapped in `try/catch` — exceptions are sent to Sentry and the run
|
|
166
166
|
continues with the next ticket. A single bad ticket does not abort the whole sync.
|
|
167
|
+
|
|
168
|
+
## Change history
|
|
169
|
+
- 2026-06-10 — Documented `App_Api_Toga2::syncWithTogadesk` orchestration (bidirectional TOGA 2 ↔ TOGaDesk ticket/note/file sync, watermarks, `ticketNoteFiles` gotcha).
|
|
@@ -105,6 +105,9 @@ attempted.
|
|
|
105
105
|
- `createNetsuiteItemFulfillment` doesn't set carrier/method on the NS IF — it defaults
|
|
106
106
|
(can show FedEx for a UPS shipment). Open item.
|
|
107
107
|
|
|
108
|
+
## Change history
|
|
109
|
+
- 2026-06-10 — Documented carrier shipping label mechanics (UPS/FedEx) + the authoritative GIF label-storage decision and NetSuite IF attachment. (mhammontree)
|
|
110
|
+
|
|
108
111
|
## Related docs
|
|
109
112
|
|
|
110
113
|
- [Fulfill & Ship (toga2-supply)](../../toga2-supply/features/fulfill-and-ship.md) —
|
|
@@ -106,6 +106,9 @@ inheritance. Verified against prod `Client_Compass` chains (≥3 levels deep).
|
|
|
106
106
|
- **Performance:** every child write re-runs a full upstream walk (read-heavy, but each
|
|
107
107
|
upstream record is written at most once — idempotent). Fine for normal fulfillment sizes.
|
|
108
108
|
|
|
109
|
+
## Change history
|
|
110
|
+
- 2026-06-08 — Documented the Recursive Item Fulfillments engine (interceptor-driven upstream fulfillment mirroring, bundle scaling, reconcile loop). (jcardinal)
|
|
111
|
+
|
|
109
112
|
## Related docs
|
|
110
113
|
- `_underscore` architecture (interceptors, `internalApiRequest`, `_Model` layer).
|
|
111
114
|
- `api2` architecture (V2 metadata engine that fires these interceptors; the
|
|
@@ -117,6 +117,9 @@ returnTrackingNumber: {...} }]`, and an IFIU's as `itemFulfillmentItemUnitTracki
|
|
|
117
117
|
`_underscore` + `api2` + `worker` + `library` together. Run the additions/migrations DB file first;
|
|
118
118
|
run the companion `..._DROPS.sql` (and the Core deletes) only after the bridges + app are confirmed.
|
|
119
119
|
|
|
120
|
+
## Change history
|
|
121
|
+
- 2026-06-10 — Documented the tracking-number bridge migration: scalar FK columns → `*_TrackingNumbers` bridge tables across ASN/IF/IR, ASN unit table rename, packages-table consolidation. (jcardinal)
|
|
122
|
+
|
|
120
123
|
## Related docs
|
|
121
124
|
- Recursive Item Fulfillment feature (the upstream-sync engine this migration reworked).
|
|
122
125
|
- compass-usa: ASN→Item Fulfillment, and the Item Fulfillment tracking TableView.
|
|
@@ -110,3 +110,6 @@ None in the flow itself — but the NetSuite trait is composed into **client-spe
|
|
|
110
110
|
model subclasses (e.g. `_Model_Growrk_ItemFulfillment uses _Trait_Netsuite_ItemFulfillment`),
|
|
111
111
|
not the base `_Model_Client_ItemFulfillment`. Tested with GroWrk; UPS support was built
|
|
112
112
|
for Compass and is not yet in prod.
|
|
113
|
+
|
|
114
|
+
## Change history
|
|
115
|
+
- 2026-06-10 — Documented the Fulfill & Ship flow (SO sync, label purchase, NetSuite IF creation, success gating, reprint). Driven green on beta for UPS/GroWrk; FedEx + prod verification pending. (mhammontree)
|
|
@@ -117,6 +117,9 @@ Read-only actions (no writes), invoked via `curl -X POST https://worker.togahub.
|
|
|
117
117
|
`DiagnoseOpportunity`, `DiagnoseAmTask` (routing verdicts), `DiscoverIds`, `DiscoverAmIds`
|
|
118
118
|
(print constant declarations), `RegisterOpportunityWebhook` (one-time setup).
|
|
119
119
|
|
|
120
|
+
## Change history
|
|
121
|
+
- 2026-06-09 — Documented ClickUp secondary multi-list routing (hybrid native-automation + worker design, three space handlers, self-trigger guard). (jcardinal)
|
|
122
|
+
|
|
120
123
|
## Related docs
|
|
121
124
|
|
|
122
125
|
- [Worker (worker2) Architecture](../architecture.md) — always-HTTP-200, commit-before-SQS.
|
|
@@ -133,3 +133,6 @@ Use realistic placeholder values, not empty strings/nulls.
|
|
|
133
133
|
- If the action needs a client DB, register it in `initialize()` — it runs before the method.
|
|
134
134
|
- See [architecture.md](../architecture.md) for the always-HTTP-200 rule and the
|
|
135
135
|
commit-before-SQS transaction pattern that the worker relies on.
|
|
136
|
+
|
|
137
|
+
## Change history
|
|
138
|
+
- 2026-06-08 — Documented the worker-action contract (path→class/method convention, parameter typing, webhook/cron templates); replaces the former `/worker2-action` skill. (jcardinal)
|
|
@@ -141,3 +141,7 @@ To test worker2 Elite code locally against production TOGA 2 and Freshservice:
|
|
|
141
141
|
|
|
142
142
|
4. **PHP version** — worker2 vendor targets PHP >= 8.5. Local PHP 8.1 requires a
|
|
143
143
|
temporary bypass in `vendor/composer/platform_check.php` — revert before committing.
|
|
144
|
+
|
|
145
|
+
## Change history
|
|
146
|
+
- 2026-06-11 — Redacted Elite credential constants from the doc; secret scanner added to `validate`.
|
|
147
|
+
- 2026-06-10 — Documented `_Worker_Elite` Freshservice → TOGA 2 webhook sync (conversation/attachment handling, TOGA 2 API gotchas, local dev setup).
|
|
@@ -176,6 +176,9 @@ clients' data flows (Compass, Prudential, AIG, …) but live as separate child c
|
|
|
176
176
|
- Slack / SMS / PagerDuty (email-only today) · `MonitorRuns` history table ·
|
|
177
177
|
HTML email + dashboard deep-links · anti-flap on the alarm side.
|
|
178
178
|
|
|
179
|
+
## Change history
|
|
180
|
+
- 2026-06-10 — Documented the v1.0 monitoring framework (orchestrator, `Core.Monitors` table, recovery-side anti-flap state machine, child contract). First child monitor + staging/prod migration still pending. (mhammontree)
|
|
181
|
+
|
|
179
182
|
## Related docs
|
|
180
183
|
|
|
181
184
|
- [worker2 architecture](../architecture.md) — cron/WorkerJobs pipeline the orchestrator rides on
|
package/knowledge/CONVENTIONS.md
CHANGED
|
@@ -113,6 +113,22 @@ standalone doc. Only a recurring/systemic failure class warrants its own record,
|
|
|
113
113
|
_Elevated_ docs (architecture, standard) are senior-owned; `capture` flags any change
|
|
114
114
|
to them with ⚠ so the developer knows what they're approving.
|
|
115
115
|
|
|
116
|
+
## Required sections
|
|
117
|
+
|
|
118
|
+
Every **feature**, **client-feature**, and **workflow** doc must include a
|
|
119
|
+
**`## Change history`** section: newest-first, dated one-line entries recording notable
|
|
120
|
+
behavior changes only (not a git log). Format:
|
|
121
|
+
|
|
122
|
+
```markdown
|
|
123
|
+
## Change history
|
|
124
|
+
- YYYY-MM-DD — <what changed and why> (<author>)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
`node knowledge.js validate` enforces this — a missing `## Change history` section in any of
|
|
128
|
+
those three doc types fails the build (and therefore blocks `capture`'s publish). `profile`,
|
|
129
|
+
`architecture`, and `standard` docs are exempt. Keep the list terse and cap it at ~10 entries,
|
|
130
|
+
folding older ones away.
|
|
131
|
+
|
|
116
132
|
## INDEX.md files
|
|
117
133
|
|
|
118
134
|
Never hand-edited. `node knowledge.js index` regenerates the master `INDEX.md`, each
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
| Doc | Framework | Summary | Files |
|
|
4
4
|
|-----|-----------|---------|-------|
|
|
5
|
-
| [Compass ASN → ItemFulfillment Auto-Creation](features/asn-to-item-fulfillment.md) | 2.0 | For Compass USA, posting an AdvanceShippingNotice (ASN) auto-creates the ItemFulfillment (IF) on the upstream SalesOrder. | _underscore/Model/Compass/AdvanceShippingNotice.php, api2/Component/Api/Cxml/Cxml.php, dbchanges2/Client_Compass/2026-06-11 - AsnItemTrackingNumberAcl.sql |
|
|
5
|
+
| [Compass ASN → ItemFulfillment Auto-Creation](features/asn-to-item-fulfillment.md) | 2.0 | For Compass USA, posting an AdvanceShippingNotice (ASN) auto-creates the ItemFulfillment (IF) on the upstream SalesOrder. | _underscore/Model/Compass/AdvanceShippingNotice.php, api2/Component/Api/Cxml/Cxml.php, dbchanges2/Client_Compass/2026-06-11 - AsnItemTrackingNumberAcl.sql, dbchanges2/Client_Compass/2026-06-15b - BackfillSA132781ItemFulfillmentTracking.sql |
|
|
6
6
|
| [Compass: Item-Fulfillment TableViews (for-sales-order-items & for-sales-orders, tracking via bridge)](features/item-fulfillment-tracking-tableview.md) | 2.0 | Two sibling Compass TableViews in `Client_Compass` display fulfilled items in toga2-supply, both driven by `TableViews` / `TableViewJoins` / `TableViewFields` c | dbchanges2/Client_Compass/2026-06-10 - ItemFulfillmentsForSalesOrderItemsTableView.sql, dbchanges2/Client_Compass/2026-06-11 - ItemFulfillmentsForSalesOrdersTableView.sql, dbchanges2/Client_Compass/2026-06-15a - FixItemFulfillmentTrackingNumberJoins.sql |
|
|
7
7
|
| [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 |
|
|
8
8
|
| [Compass USA](profile.md) | 2.0 | Compass USA is a TOGA client running a multi-tier supply-chain commerce operation. | |
|
|
@@ -5,12 +5,13 @@ project: _Underscore
|
|
|
5
5
|
client: compass-usa
|
|
6
6
|
type: client-feature
|
|
7
7
|
status: active
|
|
8
|
-
updated: 2026-06-
|
|
8
|
+
updated: 2026-06-15
|
|
9
9
|
owners: [jcardinal]
|
|
10
10
|
files:
|
|
11
11
|
- _underscore/Model/Compass/AdvanceShippingNotice.php
|
|
12
12
|
- api2/Component/Api/Cxml/Cxml.php
|
|
13
13
|
- dbchanges2/Client_Compass/2026-06-11 - AsnItemTrackingNumberAcl.sql
|
|
14
|
+
- dbchanges2/Client_Compass/2026-06-15b - BackfillSA132781ItemFulfillmentTracking.sql
|
|
14
15
|
related:
|
|
15
16
|
- ../../../2.0/apps/_underscore/features/recursive-item-fulfillments.md
|
|
16
17
|
---
|
|
@@ -36,16 +37,28 @@ unit level on both sides — not just on one unit.
|
|
|
36
37
|
inherit `postPost` from `_Model_Compass_AdvanceShippingNotice` — edit the parent.
|
|
37
38
|
|
|
38
39
|
## How it works
|
|
40
|
+
As of **2026-06-15** the handler **reconciles tracking onto whatever fulfillment exists** —
|
|
41
|
+
it no longer only attaches tracking when it creates new fulfillment (see *Change history* and
|
|
42
|
+
the gotcha about already-fulfilled orders). Flow:
|
|
43
|
+
|
|
39
44
|
1. Read ASN → resolve PO → SO via `SalesOrders_PurchaseOrders`; skip if no SO.
|
|
40
|
-
2. Select ASN items
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
2. Select **all** ASN items mapped to a SalesOrderItem (NO "unfulfilled only" filter), carrying
|
|
46
|
+
each SOI's `quantity` and already-`SUM`med fulfilled qty.
|
|
47
|
+
3. Per ASN item, compute `remaining = SOI.quantity − fulfilled` (rounded to kill float dust):
|
|
48
|
+
- **`remaining > 0`** (create path, unchanged): reuse the SO-numbered IF or POST a new one,
|
|
49
|
+
POST an IFI; that new IFI is the tracking target. Additional SO-numbered IFs are acceptable.
|
|
50
|
+
- **`remaining <= 0`** (reconcile path, new): the tracking targets are the **existing IFIs**
|
|
51
|
+
for that SOI (resolved via `ItemFulfillmentItems.salesOrderItemId` → their `itemFulfillmentId`),
|
|
52
|
+
**not** an SO-number lookup — NetSuite/toga2-supply IFs are `F`-numbered, not SO-numbered.
|
|
53
|
+
4. Copy the ASN item's tracking (`AdvanceShippingNoticeItems_TrackingNumbers`) onto each target
|
|
54
|
+
IFI via `POST /item-fulfillment-item-tracking-numbers` → `ItemFulfillmentItems_TrackingNumbers`
|
|
55
|
+
— **idempotent** (skipped if the bridge row already exists; ASNs get re-POSTed).
|
|
56
|
+
5. Per ASN unit: serialized (has a Unit) → attach unit tracking to the matching IFIU
|
|
57
|
+
(`POST /item-fulfillment-item-unit-tracking-numbers`; create the IFIU only on the create path);
|
|
58
|
+
tracking-only (`unitId IS NULL`) → collect its tracking for an IF package.
|
|
59
|
+
6. Create one IF package per unique tracking number (header-level merged with tracking-only
|
|
60
|
+
ASN-unit tracking, deduped by tracking-number **id**) on **each involved IF** — i.e. only the
|
|
61
|
+
IF(s) that received this ASN's tracking — all idempotent.
|
|
49
62
|
|
|
50
63
|
## Tracking number propagation
|
|
51
64
|
The cXML translator maps each `ShipControl` block's tracking number to a line via its
|
|
@@ -62,7 +75,10 @@ The cXML translator maps each `ShipControl` block's tracking number to a line vi
|
|
|
62
75
|
| `ItemFulfillmentItemUnits_TrackingNumbers` | `postPost` — **only when serialized units exist** |
|
|
63
76
|
|
|
64
77
|
Fix-forward only (decided 2026-06-11): applies to new ShipNotices; existing records are not
|
|
65
|
-
backfilled.
|
|
78
|
+
backfilled (one-off backfills repair specific orders — e.g. `2026-06-15b` for SA132781).
|
|
79
|
+
|
|
80
|
+
As of 2026-06-15 propagation also fires when the IF **already exists** (reconcile path), so the
|
|
81
|
+
table above is populated even for SOs fulfilled out-of-band before the ASN arrived.
|
|
66
82
|
|
|
67
83
|
## Data model
|
|
68
84
|
- `AdvanceShippingNoticeUnits.unitId` is nullable (tracking-only units have NULL).
|
|
@@ -80,6 +96,24 @@ Compass Canada (`Model/Compass/Canada/`) is a separate sub-client. The Compass c
|
|
|
80
96
|
(Core `ClientApiIdentities` identity `153531108`, clientId 2) holds roles 1 and 3.
|
|
81
97
|
|
|
82
98
|
## Gotchas / known issues
|
|
99
|
+
- **ASN arriving AFTER the SO is already fulfilled (fixed 2026-06-15):** when an SO is fulfilled
|
|
100
|
+
out-of-band (NetSuite/toga2-supply creates `F`-numbered IFs) **before** its ASN arrives,
|
|
101
|
+
`postPost` previously found zero unfulfilled ASN items and skipped the **entire** propagation
|
|
102
|
+
block (the old `if ($asnItemsQuery->getRowCount())` gate wrapped even the header-package
|
|
103
|
+
creation) — so the ASN's tracking was lost at every level. Symptom: SO **SA132781** (id 105943)
|
|
104
|
+
had tracking on the ASN (header/item/unit) but none on its IFs (68063/68154). Fix: reconcile
|
|
105
|
+
onto existing fulfillment (see *How it works*). Forward-only; SA132781 repaired by the backfill
|
|
106
|
+
migration `2026-06-15b`.
|
|
107
|
+
- **A NULL `AdvanceShippingNoticeItemUnits.unitId` is CORRECT — do NOT add a NOT NULL
|
|
108
|
+
constraint.** Office Depot (vendorId 1) ships via cXML and **never sends serial numbers**;
|
|
109
|
+
the cXML→JSON translator deliberately creates a tracking-only ASN unit (no `unit`, NULL
|
|
110
|
+
`unitId`) purely to carry the unit-level tracking number. Verified against the raw cXML
|
|
111
|
+
(`Logs_Compass.Api`) for SA132781. A NOT NULL constraint would reject the majority of Compass
|
|
112
|
+
ASN volume (~56k of ~101k units are tracking-only) and break tracking ingestion. A serialized
|
|
113
|
+
`Unit` seen on the IF side (e.g. created by NetSuite) is unrelated to the tracking-only ASN unit.
|
|
114
|
+
- **Idempotency:** every tracking attach is guarded by a SELECT-before-POST on the bridge table,
|
|
115
|
+
so re-POSTing the same ASN does not duplicate `ItemFulfillment(s|Items|ItemUnits)_TrackingNumbers`
|
|
116
|
+
rows. New attach helpers depend on this — keep the guard if extending.
|
|
83
117
|
- **Record 217 ACL gap (fixed 2026-06-11):** `AdvanceShippingNoticeItems_TrackingNumbers`
|
|
84
118
|
(Record 217) had **zero** `AclRecordPermissions` and its `advanceShippingNoticeItemId`
|
|
85
119
|
(RecordField 1440) / `trackingNumberId` (1441) fields had **zero** `AclFieldPermissions`,
|
|
@@ -101,5 +135,16 @@ Compass Canada (`Model/Compass/Canada/`) is a separate sub-client. The Compass c
|
|
|
101
135
|
- Separate latent bug in the 1.0 worker: the Strategic Systems cron's no-serials branch
|
|
102
136
|
builds `$itemLevelTrackingNumbers` but never attaches it to the ASN payload.
|
|
103
137
|
|
|
138
|
+
## Change history
|
|
139
|
+
Dated one-liners, newest first.
|
|
140
|
+
- 2026-06-15 — `postPost` rewritten to reconcile ASN tracking onto **existing** fulfillment
|
|
141
|
+
(not just newly-created IFs), idempotently; fixes lost tracking when the SO was fulfilled
|
|
142
|
+
out-of-band before the ASN (e.g. SA132781). Confirmed NULL `unitId` is by-design for Office
|
|
143
|
+
Depot tracking-only units (no NOT NULL constraint). Backfill `2026-06-15b` repairs SA132781. (jcardinal)
|
|
144
|
+
- 2026-06-11 — Record 217 ACL grant so ASN-item-level tracking POSTs succeed; cXML SQL-injection
|
|
145
|
+
hardening; tracking propagated across all ASN/IF granularities. (jcardinal)
|
|
146
|
+
- 2026-06-08 — IFIU query switched to `LEFT OUTER JOIN Units`; tracking-only units routed to IF
|
|
147
|
+
packages (previously dropped by an INNER JOIN). (jcardinal)
|
|
148
|
+
|
|
104
149
|
## Related docs
|
|
105
150
|
- Recursive Item Fulfillments (upstream mirroring) — the engine these IFs/packages feed.
|
|
@@ -186,6 +186,9 @@ Vendor SFTP ───(legacy_import_asn.php, ser+non-ser)─┘ [UNIQUE ded
|
|
|
186
186
|
5. With no staging environment, verify with a standalone arithmetic simulation plus a read
|
|
187
187
|
of the consumer query; `php -l` every touched file.
|
|
188
188
|
|
|
189
|
+
## Change history
|
|
190
|
+
- 2026-06-10 — Documented the NYC DOE ServiceNow/ASN integration (ticket mirror, dual ASN ingestion, NetSuite freeze pipeline, EDI surface, dedupeKey gotchas). (mhammontree)
|
|
191
|
+
|
|
189
192
|
## Related docs
|
|
190
193
|
|
|
191
194
|
- [NYC DOE client profile](../profile.md)
|
package/knowledge.js
CHANGED
|
@@ -612,6 +612,14 @@ function cmdValidate() {
|
|
|
612
612
|
if (!d.data[f]) { fail(`${d.rel}: missing frontmatter "${f}"`); ok = false; }
|
|
613
613
|
}
|
|
614
614
|
if (d.data.type && !DOC_TYPES.includes(d.data.type)) { fail(`${d.rel}: invalid type "${d.data.type}"`); ok = false; }
|
|
615
|
+
// feature/client-feature/workflow docs must carry a "## Change history" section so the
|
|
616
|
+
// doc records its own notable behavior changes over time (newest-first dated one-liners).
|
|
617
|
+
if (['feature', 'client-feature', 'workflow'].includes(d.data.type)) {
|
|
618
|
+
if (!/^##\s+Change history\s*$/m.test(fs.readFileSync(d.file, 'utf8'))) {
|
|
619
|
+
fail(`${d.rel}: missing required "## Change history" section`);
|
|
620
|
+
ok = false;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
615
623
|
const isClientDoc = d.rel.startsWith('clients/');
|
|
616
624
|
if (isClientDoc) {
|
|
617
625
|
if (!d.data.client || d.data.client === 'shared') { fail(`${d.rel}: client doc must set a real "client"`); ok = false; }
|
package/package.json
CHANGED