toga-ai 1.0.545 → 1.0.547

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.
@@ -13,7 +13,7 @@
13
13
  | [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 |
14
14
  | [Running 2.0 code from a bare CLI script (bootstrap + transactions)](features/cli-script-bootstrap.md) | A throwaway CLI script (a data check, a backfill dry-run, a render harness) that wants the real 2.0 framework — `_Model`, `_Query`, `_Database` — is **not** the | _underscore/Database.php, _underscore/Environment.php, api2/Initialize.php |
15
15
  | [_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 |
16
- | [_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, _underscore/Component/Api/Paypal/Paypal.php |
16
+ | [_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, worker2/Component/Api/Oneuptime/Oneuptime.php, api2/Component/Api/Netsuite/Netsuite.php, _underscore/Component/Api/Paypal/Paypal.php |
17
17
  | [_Config group access — the two-argument "optional" form does NOT rescue a missing GROUP](features/config-group-access.md) | `_Config::<group>('<property>')` reads a value out of the active `Config/<ENVIRONMENT>.ini`, and **it throws when the requested group is absent from the ini.** | _underscore/Config.php, _underscore/Component/Api/Paypal/Paypal.php |
18
18
  | [Re-pointing a DB alias mid-request (_Database::register park/restore)](features/database-alias-repointing.md) | `_Database` keys **all live per-database runtime state by the connection ALIAS** (`Client` / `_underscore::DB_CLIENT`, `ClientLogs`, `Archive`), **not** by the | _underscore/Database.php, _underscore/Query.php, api2/Component/Api/V2/V2.php, api2/Component/Api/CrossClient/CrossClient.php |
19
19
  | [2.0 Email Send Pipeline (queue + Send worker)](features/email-send-pipeline.md) | In 2.0, `_Email::send()` **does not transmit** — it queues the message. | _underscore/Email.php, _underscore/String.php, worker2/Worker/Infrastructure/Email/Send.php |
@@ -6,14 +6,15 @@ project: _Underscore
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-08-04
10
- owners: [dfranks, mhammontree]
9
+ updated: 2026-08-10
10
+ owners: [dfranks, mhammontree, jcardinal]
11
11
  files:
12
12
  - _underscore/Loader.php
13
13
  - worker2/_.php
14
14
  - api2/_.php
15
15
  - worker2/Component/Forecast/Db/Db.php
16
16
  - worker2/Component/Forecast/SaleImport/SaleImport.php
17
+ - worker2/Component/Api/Oneuptime/Oneuptime.php
17
18
  - api2/Component/Api/Netsuite/Netsuite.php
18
19
  - _underscore/Component/Api/Paypal/Paypal.php
19
20
  related:
@@ -113,8 +114,19 @@ project-local `_Component_*`/`_Model_*` must still declare the project namespace
113
114
  runtime-only failure.
114
115
  - A global-namespace `_Component_*`/`_Model_*` fails **loudly** (the throw above). An
115
116
  unqualified `catch (Exception $e)` fails **silently** — the more insidious of the two.
117
+ - **The namespace rule is APP-repo-only.** `_Component_*` classes that live in the
118
+ `_underscore` **core** repo (e.g. `_Component_Api_Togaiq`, `_Component_Api_Clickup`) are
119
+ declared in the **global** namespace and do **not** `extend \_Component`. Do not copy a core
120
+ `_Component_*` as the template for a new worker2/api2 one — copy a *project-local* precedent
121
+ (e.g. `worker2/Component/Forecast/Db/Db.php`, `api2/Component/Api/Netsuite/Netsuite.php`).
116
122
 
117
123
  ## Change history
124
+ - 2026-08-10 — Confirmed again in worker2 building `_Component_Api_Oneuptime`
125
+ (`Component/Api/Oneuptime/Oneuptime.php`): the component threw the Loader
126
+ "namespace … has not been defined" fatal until `namespace worker;` + `extends \_Component`
127
+ + `\`-prefixed framework refs (`\_ApiRequest`, `\_Config`, `\_Query`, `\Exception`, …) were
128
+ applied. Added the app-repo-only clarification — core-repo `_Component_*` (Togaiq, Clickup)
129
+ are global-namespace and don't extend `\_Component`, so they're the wrong template. (jcardinal)
118
130
  - 2026-08-04 — TRUE-80282: documented the **file-layout** half of `_Component_*` loading, which
119
131
  precedes the namespace rule — `_Loader::autoloader()` (`Loader.php:60-67`) pops the trailing
120
132
  `_`-segment and appends it as **both a directory and the filename**, so
@@ -30,6 +30,7 @@
30
30
  | [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 |
31
31
  | [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 |
32
32
  | [NYCHH Asset-Tag Backfill (worker2)](features/nychh-asset-tag-backfill.md) | Keeps NYC Health & Hospitals (`Client_Nychh`) unit asset tags and MAC addresses synced from NetSuite. | worker2/Worker/Client/Nychh.php, worker2/Worker/Client/Nychh/AssetTagBackfill.php, worker/crons/toga2/netsuite/verify_fulfillment_asset_tag_sync_nychh.php, worker/crons/toga2/netsuite/backfill_all_asset_tags_from_netsuite_nychh.php |
33
+ | [OneUptime Incident → ClickUp Task Sync (Monitor/Oneuptime/SyncIncidents)](features/oneuptime-incident-clickup-sync.md) | An internal/shared TOGA ops feature: worker2 polls the OneUptime API every 15 minutes for **currently-open** incidents and ensures a ClickUp task exists for eac | worker2/Component/Api/Oneuptime/Oneuptime.php, worker2/Worker/Monitor/Oneuptime.php, worker2/Config/production.ini, dbchanges2/Team/2026-08-10a - OneUptime Incident ClickUp Tasks.sql, dbchanges2/Core/2026-08-10b - OneUptime Incident Sync CronJob.sql |
33
34
  | [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, worker2/Worker/Client/Compass.php, worker2/composer.json, _underscore/Cloud.php, worker2/Worker/Monitor/Operations.php |
34
35
  | [Platform Cache Cleanup (_Worker_Platform_Cache — Clean + Truncate)](features/platform-cache-cleanup.md) | `_Worker_Platform_Cache` owns maintenance of the shared **Cache** cluster that backs api2's [multi-client data retrieval](../../api2/features/cross-client-data- | worker2/Worker/Platform/Cache.php, worker2/Controller/Index.php, worker2/_.php, dbchanges2/Core/2026-07-27a - PlatformCacheCleanCron.sql |
35
36
  | [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 |
@@ -0,0 +1,122 @@
1
+ ---
2
+ title: OneUptime Incident → ClickUp Task Sync (Monitor/Oneuptime/SyncIncidents)
3
+ framework: "2.0"
4
+ repo: worker2
5
+ project: Worker
6
+ client: shared
7
+ type: feature
8
+ status: active
9
+ updated: 2026-08-10
10
+ owners: ["jcardinal"]
11
+ files:
12
+ - worker2/Component/Api/Oneuptime/Oneuptime.php
13
+ - worker2/Worker/Monitor/Oneuptime.php
14
+ - worker2/Config/production.ini
15
+ - dbchanges2/Team/2026-08-10a - OneUptime Incident ClickUp Tasks.sql
16
+ - dbchanges2/Core/2026-08-10b - OneUptime Incident Sync CronJob.sql
17
+ related:
18
+ - ./oneuptime-worker2-monitoring.md
19
+ - ./error-escalation-cron.md
20
+ - ./creating-worker-actions.md
21
+ - ./team-sprint-management.md
22
+ - ../../_underscore/features/component-model-namespace-registration.md
23
+ ---
24
+
25
+ ## Summary
26
+
27
+ An internal/shared TOGA ops feature: worker2 polls the OneUptime API every 15 minutes for
28
+ **currently-open** incidents and ensures a ClickUp task exists for each, so operational
29
+ incidents become actionable tickets automatically without duplicates. This is the **first
30
+ *reader* of the OneUptime API** in worker2 — until now OneUptime was **push-only** (workers
31
+ POST metrics/heartbeats to Incoming-Request monitors; see
32
+ [OneUptime push-metric monitors](./oneuptime-worker2-monitoring.md)). The model was "dumb
33
+ reporter, smart monitor"; this feature adds the reader half.
34
+
35
+ ## Key files / entry points
36
+
37
+ - `worker2/Component/Api/Oneuptime/Oneuptime.php` — `_Component_Api_Oneuptime`, the OneUptime
38
+ API read client, modeled on `_Component_Api_Togaiq`. Reads a new `[oneuptime]` config group
39
+ (endpoint, api_key, project_id) via `_Config`; `isConfigured()` guard; `send()` wraps
40
+ `_ApiRequest` with `APIKey` + `ProjectID` headers; `getActiveIncidents()` returns normalized
41
+ open incidents (filters out resolved **in PHP**).
42
+ - `worker2/Worker/Monitor/Oneuptime.php` — `_Worker_Monitor_Oneuptime::SyncIncidents(): string`,
43
+ the cron action. Returns a structured summary string on every path
44
+ (`incidentsPolled` / `created` / `skipped` / `failed`).
45
+
46
+ ## How it works
47
+
48
+ Canonical worker2 scheduled-3rd-party-API-job shape (see
49
+ [Creating Worker Actions](./creating-worker-actions.md)): a `Core.CronJobs` row (cron expr,
50
+ Central tz) → CronScheduler Lambda enqueues → `Controller/Index::worker()` dispatches the
51
+ `action` `Monitor/Oneuptime/SyncIncidents` to `_Worker_Monitor_Oneuptime::SyncIncidents`.
52
+ HTTP goes through `_ApiRequest`; secrets come from `_Config::oneuptime()` reading
53
+ `Config/<env>.ini`; ClickUp uses `_Component_Api_Clickup::send()`.
54
+
55
+ ### Open-only
56
+
57
+ Only currently-open incidents are synced. The list route returns all incidents and resolved
58
+ ones are filtered out in PHP inside `getActiveIncidents()`.
59
+
60
+ ### Claim-first (unique-key) dedup
61
+
62
+ For each open incident, INSERT a ledger row into `OneUptimeIncidentTasks` keyed on the
63
+ OneUptime incident id **before** calling ClickUp. A unique-key violation means a task already
64
+ exists → skip. On success, create the ClickUp task via
65
+ `_Component_Api_Clickup::send('POST','/list/{listId}/task', …)` and attach the returned id to
66
+ the ledger row; on failure, **delete the claim and re-throw**. This is the established
67
+ worker2 way to prevent duplicate ClickUp tasks under overlapping cron runs — pattern copied
68
+ from `_Worker_Infrastructure_Errors::createClickupTask`. `INSERT … WHERE NOT EXISTS` is
69
+ **insufficient** under REPEATABLE READ; the UNIQUE key is the concurrency arbiter.
70
+
71
+ ### Target list = current sprint list
72
+
73
+ The ClickUp task lands in the **current sprint** list, resolved by `GET /folder/{id}` and
74
+ matching the list whose `start_date`/`due_date` window contains now (mirrors
75
+ `_Worker_Team_Sprint::SprintLock` — see [Team Sprint Management](./team-sprint-management.md)
76
+ and the sprint-promotion note in [Error Escalation Cron](./error-escalation-cron.md)). Folder
77
+ id is read from `[clickup] sprint_folder_id` with a constant fallback (`90020432579`).
78
+
79
+ ## Data model
80
+
81
+ `OneUptimeIncidentTasks` (CREATE on the **Team** cluster — chosen over Logs;
82
+ `dbchanges2/Team/2026-08-10a`): `id`, `uuid char(36)`, `dtCreated`,
83
+ `oneuptimeIncidentId varchar(64)`, `clickupIdentifier varchar(64) NULL`. The **UNIQUE KEY on
84
+ `oneuptimeIncidentId`** is the dedup contract, same rationale as `IssueClickupTasks`.
85
+
86
+ ## Provisioning / deploy
87
+
88
+ - `dbchanges2/Core/2026-08-10b` inserts the `Core.CronJobs` row: action
89
+ `Monitor/Oneuptime/SyncIncidents`, schedule `*/15 * * * *`, `maxExecutionTime` 120, seeded
90
+ **`isActive = 0`**. Flip to 1 only after (a) the ledger table exists, (b) the `[oneuptime]`
91
+ config group is populated, and (c) the incident-list route is confirmed.
92
+ - `[oneuptime]` config group (endpoint, api_key, project_id) added to
93
+ `worker2/Config/production.ini` with placeholders — **values are filled by the developer,
94
+ not committed**. Credentials live only in the ini files.
95
+
96
+ ## Configuration / credentials
97
+
98
+ - `[oneuptime]` — `endpoint`, `api_key`, `project_id`. The hosted OneUptime SaaS base is
99
+ `https://oneuptime.com` (confirmed from `worker/.ebextensions/045_oneuptime_agent.config`);
100
+ the REST API path is appended to that base.
101
+ - `[clickup]` — `sprint_folder_id` (fallback constant `90020432579`) plus the ClickUp token.
102
+ ClickUp/OneUptime token **values** live in `worker2/Config/<env>.ini` — location only,
103
+ never the value.
104
+
105
+ ## Gotchas / known issues
106
+
107
+ - **Incident-list route/fields are PLACEHOLDER** (`/api/incident/get-list`) pending
108
+ confirmation against the live OneUptime instance. Do not enable the cron (`isActive = 1`)
109
+ until the route and returned fields are verified.
110
+ - **OneUptime cannot filter open-only server-side here** — resolution filtering happens in
111
+ PHP, so the returned field set must actually carry the resolved/open state.
112
+ - Ship the worker2 code deploy and both dbchanges2 migrations **together**; the cron row is
113
+ inert until the action is deployed and the ledger table exists.
114
+
115
+ ## Change history
116
+ - 2026-08-10 — Built: first OneUptime API *reader* (`_Component_Api_Oneuptime`) + the
117
+ `Monitor/Oneuptime/SyncIncidents` cron that claim-first-dedups an open incident into a
118
+ ClickUp task in the current sprint list; new `OneUptimeIncidentTasks` ledger (Team cluster,
119
+ UNIQUE on incident id) and a seeded-inactive `*/15 * * * *` cron row. Incident-list route
120
+ left PLACEHOLDER pending confirmation. (jcardinal)
121
+ </content>
122
+ </invoke>
@@ -15,6 +15,7 @@ files:
15
15
  - _underscore/Cloud.php
16
16
  - worker2/Worker/Monitor/Operations.php
17
17
  related:
18
+ - ./oneuptime-incident-clickup-sync.md
18
19
  - ./monitoring-framework.md
19
20
  - ./all-client-email-queue-monitor.md
20
21
  - ../../_underscore/features/cloud-s3-helpers.md
@@ -211,6 +212,10 @@ check for another client.
211
212
  monitors must pass the region (see [Cloud S3 helpers](../../_underscore/features/cloud-s3-helpers.md)).
212
213
 
213
214
  ## Change history
215
+ - 2026-08-10 — Noted that worker2 gained its **first OneUptime API *reader*** (this doc covers
216
+ the push-only half; OneUptime was previously push-only, "dumb reporter, smart monitor"). The
217
+ reader polls open incidents and files ClickUp tasks — see
218
+ [OneUptime Incident → ClickUp Task Sync](./oneuptime-incident-clickup-sync.md). (jcardinal)
214
219
  - 2026-08-10 — Documented OneUptime incident/alert `{{requestBody.*}}` templating (missing
215
220
  paths → empty string; `Not Recieved In Minutes` heartbeat spelling), discovered while
216
221
  wiring the second all-client `_Worker_Monitor_Operations` monitor —
@@ -18,8 +18,8 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
18
18
 
19
19
  ## 2.0 framework
20
20
 
21
- - **_underscore** (_Underscore) _(framework core)_ — 48 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
22
- - **worker2** (Worker) — 43 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
21
+ - **_underscore** (_Underscore) _(framework core)_ — 49 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
22
+ - **worker2** (Worker) — 44 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
23
23
  - **api2** (API) — 22 doc(s) → [2.0/apps/api2/INDEX.md](2.0/apps/api2/INDEX.md)
24
24
  - **dbchanges2** (Database Changes) _(framework core)_ — 8 doc(s) → [2.0/apps/dbchanges2/INDEX.md](2.0/apps/dbchanges2/INDEX.md)
25
25
  - **toga2-supply** (TOGa Supply) — 5 doc(s) → [2.0/apps/toga2-supply/INDEX.md](2.0/apps/toga2-supply/INDEX.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.545",
3
+ "version": "1.0.547",
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",