toga-ai 1.0.325 → 1.0.326

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.
@@ -9,6 +9,7 @@
9
9
  | [Assortment Name Translation (AssortmentTranslations sidecar)](features/assortment-name-translation.md) | Serves Assortment (product-grouping) **names** in multiple languages by adding a per-language **sidecar** table `AssortmentTranslations`, reusing the platform's | _underscore/Model/Client/AssortmentTranslation.php, dbchanges2/Client/2026-06-26a - AssortmentTranslations.sql, dbchanges2/Core/2026-06-26a - AssortmentTranslationsRecord.sql, dbchanges2/Client/2026-06-26b - AssortmentTranslationsAcl.sql |
10
10
  | [Asynchronous Query Execution (writes-only, via Worker)](features/async-query-execution.md) | `_Query` can run a **write** query asynchronously so a long/slow write does not hold a request-scoped DB connection open long enough to hit **"MySQL server has | _underscore/Query.php, worker2/Worker/Infrastructure/Database.php, worker2/Worker/Team/Transcripts.php |
11
11
  | [Carrier Shipping Labels (UPS/FedEx) & NetSuite Item Fulfillment](features/carrier-shipping-labels.md) | Backend mechanics behind TOGa Supply's Fulfill & Ship: buying a carrier label (UPS/FedEx), persisting it, and creating the NetSuite Item Fulfillment with tracki | _underscore/Model/Client/ItemFulfillment.php, _underscore/Model/Client/TrackingNumber.php, _underscore/Model/Client/ItemFulfillments/TrackingNumber.php, _underscore/Component/Library/LabelPdf/LabelPdf.php, _underscore/Component/Library/Carriers/ShipmentRequest/ShipmentRequest.php, _underscore/Component/Library/Carriers/Ups/Ups.php, _underscore/Component/Library/Carriers/Fedex/Fedex.php, _underscore/Trait/Netsuite/ItemFulfillment.php, _underscore/Trait/Netsuite/SalesOrder.php, _underscore/Component/Library/NetSuite/NetSuite.php, _underscore/Model/Client/TrackingNumber.php, _underscore/Model/Client/ShippingMethod.php, _underscore/Model.php, _underscore/Cloud.php |
12
+ | [_Cloud S3 helpers (copy / get / delete / list)](features/cloud-s3-helpers.md) | `_Cloud` centralizes AWS SDK S3 usage for the 2.0 stack so the `S3Client` never leaks into workers or app code. | _underscore/Cloud.php |
12
13
  | [_Component_*/_Model_* project-namespace registration (autoloader) & backslash-qualify traps](features/component-model-namespace-registration.md) | Every **project-local** `_Component_*` and `_Model_*` class in a 2.0 app **must declare the project namespace** at the top of the file: ```php namespace <NAMESP | _underscore/Loader.php, worker2/_.php, api2/_.php, worker2/Component/Forecast/Db/Db.php, worker2/Component/Forecast/SaleImport/SaleImport.php, api2/Component/Api/Netsuite/Netsuite.php |
13
14
  | [Client Email Template Sending](features/email-template-sending.md) | `_Model_Client_EmailTemplate` sends a stored, client-defined email template by UUID. | _underscore/Model/Client/EmailTemplate.php, _underscore/Model/Client/EmailTemplateOutgoingEmailAddress.php, _underscore/Email.php |
14
15
  | [Error Reporting — Issue/Event Aggregation (agreed POST-to-receiver design)](features/error-reporting-issue-event.md) | Platform-wide error-reporting infrastructure for TOGA 2.0, built around a two-table **Issue / Event** aggregation model in the shared **Core Logs DB**. | _underscore/Error.php, _underscore/Model/Core/Logs/Issue.php, _underscore/Model/Core/Logs/Event.php, dbchanges2/Logs/2026-07-06 - Issue and Event tables.sql |
@@ -0,0 +1,54 @@
1
+ ---
2
+ title: _Cloud S3 helpers (copy / get / delete / list)
3
+ framework: "2.0"
4
+ repo: _underscore
5
+ project: _Underscore
6
+ client: shared
7
+ type: feature
8
+ status: active
9
+ updated: 2026-07-13
10
+ owners: ["jcardinal"]
11
+ files:
12
+ - _underscore/Cloud.php
13
+ related:
14
+ - ../../worker2/features/oneuptime-worker2-monitoring.md
15
+ ---
16
+
17
+ ## Summary
18
+
19
+ `_Cloud` centralizes AWS SDK S3 usage for the 2.0 stack so the `S3Client` never leaks into
20
+ workers or app code. Alongside the existing copy / get / delete methods it now has a
21
+ **LIST** method, `_Cloud::getS3Objects()`.
22
+
23
+ ## Key files / entry points
24
+
25
+ - `_underscore/Cloud.php` — `_Cloud::getS3Objects($s3BucketName, $s3BucketPath = '')`.
26
+
27
+ ## How it works
28
+
29
+ `getS3Objects()` uses the AWS SDK `S3Client->listObjectsV2` and **transparently paginates**
30
+ (`listObjectsV2` caps at 1000 keys per page), returning entries shaped:
31
+
32
+ - `Key` — object key
33
+ - `LastModified` — ISO-8601 string
34
+ - `Size`
35
+
36
+ The method is **purely additive** — no existing `_Cloud` method signature changed. Keeping
37
+ S3 listing here (rather than instantiating `S3Client` in a worker) is the reason to prefer
38
+ this helper over ad-hoc SDK calls.
39
+
40
+ First consumer: the worker2 Office Depot EDI backlog monitor — see
41
+ [OneUptime push-metric monitors](../../worker2/features/oneuptime-worker2-monitoring.md).
42
+
43
+ ## Client variations
44
+
45
+ None — shared core helper.
46
+
47
+ ## Gotchas / known issues
48
+
49
+ - Callers get every matching key regardless of count; pagination is handled internally, so
50
+ do not add your own `ContinuationToken` loop on top.
51
+
52
+ ## Change history
53
+ - 2026-07-13 — Added `_Cloud::getS3Objects()` S3 LIST helper (paginated `listObjectsV2`,
54
+ returns `{Key, LastModified, Size}`); additive, no existing signatures changed. (jcardinal)
@@ -20,6 +20,7 @@
20
20
  | [NetSuite Supporting-Record Webhook Importer (the reusable recipe)](features/netsuite-supporting-record-webhook-importer.md) | A single **repeatable recipe** for porting a legacy daily-pull NetSuite *supporting-record* importer (the lookup/dimension tables behind Forecast2 — Employees, | worker2/Worker/Netsuite/Employee.php, worker2/Worker/Netsuite/Account.php, worker2/Worker/Netsuite/Classification.php, worker2/Worker/Netsuite/Customer.php, worker2/Worker/Netsuite/Item.php, worker2/Worker/Netsuite.php, _underscore/Model/Forecast/Employee.php, _underscore/Model/Forecast/Account.php, _underscore/Model/Forecast/Classification.php, _underscore/Component/Forecast/Db/Db.php, test/@dave/test_employee_lifecycle.php, test/@dave/test_account_lifecycle.php, test/@dave/test_classification_lifecycle.php, test/@dave/NetSuite/api-message-queue/ue_api_msg_queue_enqueue.js, worker/crons/toga2/forecast2/import_supporting_records.php |
21
21
  | [Background Email-Template Worker (_Worker_Notification_EmailTemplate)](features/notification-email-template.md) | `_Worker_Notification_EmailTemplate::Send(...)` dispatches a **stored, client-defined `EmailTemplates` row off-thread** as a background WorkerJob. | worker2/Worker/Notification/EmailTemplate.php, worker2/Worker/Client/True.php, _underscore/Model/Client/EmailTemplate.php |
22
22
  | [DB-Driven Notification (Internal) Email](features/notification-email.md) | Internal/notification emails (merge-conflict alerts, ops notices — anything system-generated, not client-facing transactional mail) are sent through one worker | worker2/Worker/Notification/Email.php, _underscore/Model/Client/EmailTemplate.php, dbchanges2/Client/2026-06-23a - EmailTemplateWrapper.sql, dbchanges2/Client_True/2026-06-23a - EmailTemplateWrapper.sql |
23
+ | [OneUptime push-metric monitors for 2.0 workers](features/oneuptime-worker2-monitoring.md) | A second, **OneUptime-reporting** monitoring pattern for the 2.0 worker2 tier, ported from the 1.0 `App_SystemMonitor_Compass` monitors. | worker2/Worker/Monitor/Compass.php, _underscore/Cloud.php |
23
24
  | [Startech Webhook Handler (worker2)](features/startech-webhook-handler.md) | Receives inbound webhook events from Startech (Easeedesk) and creates or updates the corresponding ticket in TOGA 2.0. | worker2/Worker/Startech.php |
24
25
  | [Talos (TOGa IQ) Meeting-Notes Integration & Token Auto-Refresh (consumer)](features/talos-meeting-notes-integration.md) | How a **dev tool / agent consumes Talos (TOGa IQ)** to query the team meeting-notes corpus programmatically. | .claude/skills/plan-ticket/scripts/talos.js |
25
26
  | [Talos Pricing Automation (worker2 Cron — AWS Actuals, Calibration, Monthly Report)](features/talos-pricing-automation.md) | The worker2 half of the **Talos Pricing Platform** (see the talos `pricing-cogs-model` and tools `talos-pricing-ui` docs for the other halves). | worker2/Worker/Talos/Pricing.php, worker2/Database/TalosPricingCrons.sql |
@@ -0,0 +1,128 @@
1
+ ---
2
+ title: OneUptime push-metric monitors for 2.0 workers
3
+ framework: "2.0"
4
+ repo: worker2
5
+ project: Worker
6
+ client: shared
7
+ type: feature
8
+ status: active
9
+ updated: 2026-07-13
10
+ owners: ["jcardinal"]
11
+ files:
12
+ - worker2/Worker/Monitor/Compass.php
13
+ - _underscore/Cloud.php
14
+ related:
15
+ - ./monitoring-framework.md
16
+ - ../../_underscore/features/cloud-s3-helpers.md
17
+ - ../../../1.0/apps/worker/features/oneuptime-worker-uptime-monitoring.md
18
+ ---
19
+
20
+ ## Summary
21
+
22
+ A second, **OneUptime-reporting** monitoring pattern for the 2.0 worker2 tier, ported from
23
+ the 1.0 `App_SystemMonitor_Compass` monitors. A worker2 cron action runs a self-contained
24
+ check, decides pass/fail itself, and POSTs a JSON metric body to a OneUptime "Incoming
25
+ Request" monitor — replacing the 1.0 tier's email alerts. First monitor:
26
+ `_Worker_Monitor_Compass::OfficeDepotEdiImportQueue()`, which watches the Office Depot
27
+ inbound EDI import backlog. Designed to be **client-agnostic** — a reusable template for
28
+ future monitors and clients.
29
+
30
+ This is distinct from the DB-driven email-orchestrator
31
+ [Monitoring Framework](./monitoring-framework.md) (`_Worker_Monitor` orchestrator +
32
+ `_Worker_Monitors_<Name>` children + `Core.Monitors` table, sends email). This pattern has
33
+ **no orchestrator and no `Core.Monitors` table** — each monitor is a plain worker2 action
34
+ that reports straight to OneUptime. Note the folder difference: these live under
35
+ `Worker/Monitor/` (singular) vs. the framework's `Worker/Monitors/` (plural).
36
+
37
+ ## Key files / entry points
38
+
39
+ - `worker2/Worker/Monitor/Compass.php` — `abstract class _Worker_Monitor_Compass`; each
40
+ monitor is a `public static` action method returning a summary string recorded in
41
+ `WorkerJobs` (standard worker2 action conventions). First method:
42
+ `OfficeDepotEdiImportQueue()`.
43
+ - `_underscore/Cloud.php` — `_Cloud::getS3Objects()` list helper this monitor relies on
44
+ (see [Cloud S3 helpers](../../_underscore/features/cloud-s3-helpers.md)).
45
+
46
+ ## How it works
47
+
48
+ Registered as a `Core.CronJobs` entry: schedule `*/5 6-20 * * *`, action
49
+ `Monitor/Compass/OfficeDepotEdiImportQueue`. Each tick, `OfficeDepotEdiImportQueue()`:
50
+
51
+ 1. Lists `s3://agilant-as2/OfficeDepot/` via `_Cloud::getS3Objects()`, then counts files
52
+ older than `AGED_FILE_MINUTES` (10), **excluding** the `OUTBOX/` and `SENT/` sub-prefixes
53
+ and directory-placeholder keys.
54
+ 2. Decides the alarm state itself and POSTs a JSON metric body to the OneUptime "Incoming
55
+ Request" monitor via `_ApiRequest` — with **logging disabled** and
56
+ **`throwExceptionsOnFailure` disabled**, so a failed ping never fails the worker job.
57
+ 3. On S3 failure it still POSTs `{"status":"error"}` so a blind/dead checker is
58
+ distinguishable from a real backlog.
59
+
60
+ Body tokens (see the alarm contract below): `"alarm":"HIGH"` when the aged-file count is
61
+ over threshold, else `"alarm":"OK"`; `"status":"error"` on S3 failure.
62
+
63
+ ### The token-based alarm contract (critical — OneUptime cannot compare numbers)
64
+
65
+ OneUptime **Incoming Request** monitors **cannot** do numeric threshold comparison on a
66
+ pushed body. Verified in OneUptime source (`Common/Server/.../IncomingRequestCriteria.ts`):
67
+ a `checkOn: "Request Body"` filter supports only `Contains` / `NotContains` **string**
68
+ matching — it does **not** JSON-parse the body, does **not** target a nested key, and does
69
+ **not** support Greater Than / Less Than (those filter types apply only to
70
+ outgoing/synthetic checks like Response Time / Status Code / Metric Value).
71
+
72
+ Consequence: the "dumb reporter, smart monitor" ideal (push a raw number, let OneUptime
73
+ compare `> threshold`) is **not achievable for push monitors**. Instead the **worker makes
74
+ the threshold decision** and emits a string token that OneUptime matches with `Contains`.
75
+ OneUptime criteria for this monitor:
76
+
77
+ - Request Body **Contains** `"alarm":"HIGH"` → Offline + incident.
78
+ - Request Body **Contains** `"status":"error"` → Offline + incident.
79
+ - **Online** requires BOTH "received in 1 min" AND Request Body **Contains** `"alarm":"OK"`
80
+ — so status does not flap back to Operational while the alarm is still HIGH.
81
+
82
+ ### Heartbeat / cron cadence timing
83
+
84
+ Heartbeat missed-ping thresholds must match the cron cadence. With a **5-minute** push
85
+ cadence: **Degraded at 10 min / Offline at 15 min**. An initial 3/5-min setting
86
+ false-alarmed on a single missed ping. The Office Depot backlog alarm threshold is
87
+ **10 aged files**.
88
+
89
+ ## Provisioning a monitor (runbook)
90
+
91
+ 1. Write the monitor method on `_Worker_Monitor_Compass` (or a new `_Worker_Monitor_<X>`
92
+ class). Keep it **fully self-contained**: no private helpers, no class constants — all
93
+ per-monitor config lives as `ALL_CAPS` local variables inside the method (PHP disallows
94
+ `const` at function scope), so the class stays clean as monitors accumulate.
95
+ 2. Provision the OneUptime monitor by cloning the reusable import/export template at
96
+ `monitor-import-OfficeDepot-EDI-1.0.json` (a local dev artifact, not a repo file) and
97
+ importing it into OneUptime; wire the Contains criteria above.
98
+ 3. Register the OneUptime push URL as a local/constant in the monitor method — it is a
99
+ **push credential**; never log it and never record its value in a doc.
100
+ 4. Add the `Core.CronJobs` row (`action = 'Monitor/<Class>/<Method>'`) with the schedule,
101
+ and set OneUptime's Degraded/Offline thresholds to match the cadence.
102
+
103
+ ## Client variations
104
+
105
+ None — the pattern is shared infrastructure. The first monitor targets Compass USA's
106
+ Office Depot inbound EDI (vendor ODP), but the class and template are client-agnostic;
107
+ clone the template to provision the same check for another client.
108
+
109
+ ## Gotchas / known issues
110
+
111
+ - OneUptime Incoming Request bodies are matched **as strings only** (Contains/NotContains) —
112
+ no numeric comparison, no JSON key targeting. Always emit a decided token, never a raw
113
+ number, for push monitors.
114
+ - The OneUptime push URL is a credential — keep it as a local/constant in the method; never
115
+ log it or write its value into knowledge docs.
116
+ - Keep the metric POST non-fatal (`throwExceptionsOnFailure` off) so a monitoring outage
117
+ never breaks the worker job it rides in.
118
+
119
+ ## Change history
120
+ - 2026-07-13 — Ported Compass monitoring from the 1.0 worker tier into worker2 reporting to
121
+ OneUptime; built `_Worker_Monitor_Compass::OfficeDepotEdiImportQueue()` (Office Depot EDI
122
+ backlog), the token-based alarm contract (OneUptime Incoming Request can only string-match
123
+ Contains, not compare numbers), and the 5-min cadence → 10/15-min heartbeat timing. (jcardinal)
124
+
125
+ ## Related docs
126
+ - [Monitoring Framework](./monitoring-framework.md) — the parallel DB-driven, email-alert monitoring pattern
127
+ - [Cloud S3 helpers](../../_underscore/features/cloud-s3-helpers.md) — `_Cloud::getS3Objects()` used to list the EDI bucket
128
+ - [OneUptime 1.0 worker uptime monitoring](../../../1.0/apps/worker/features/oneuptime-worker-uptime-monitoring.md) — the 1.0 push-heartbeat predecessor
@@ -17,8 +17,8 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
17
17
 
18
18
  ## 2.0 framework
19
19
 
20
- - **_underscore** (_Underscore) _(framework core)_ — 29 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
21
- - **worker2** (Worker) — 27 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
20
+ - **_underscore** (_Underscore) _(framework core)_ — 31 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
21
+ - **worker2** (Worker) — 28 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
22
22
  - **api2** (API) — 10 doc(s) → [2.0/apps/api2/INDEX.md](2.0/apps/api2/INDEX.md)
23
23
  - **dbchanges2** (Database Changes) _(framework core)_ — 3 doc(s) → [2.0/apps/dbchanges2/INDEX.md](2.0/apps/dbchanges2/INDEX.md)
24
24
  - **toga2-supply** (TOGa Supply) — 3 doc(s) → [2.0/apps/toga2-supply/INDEX.md](2.0/apps/toga2-supply/INDEX.md)
@@ -9,6 +9,7 @@ apps:
9
9
  - toga2-commerce
10
10
  - worker
11
11
  - worker1.5
12
+ - worker2
12
13
  - dbchanges2
13
14
  project: _Underscore
14
15
  client: compass-usa
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.325",
3
+ "version": "1.0.326",
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",