toga-ai 1.0.673 → 1.0.674

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.
@@ -5,6 +5,7 @@
5
5
  | [Worker (worker2) Architecture](architecture.md) | Worker (repo `worker2`) is an AWS Elastic Beanstalk **Worker Tier** application that processes background jobs. | worker2/Controller/Index.php, worker2/Worker/, worker2/LambdaFunctions/, _underscore/Worker.php, worker2/composer.json |
6
6
  | [Deploy-Time Auto-Registration to the Shared ALB Target Group (non-production)](features/alb-target-group-auto-registration.md) | TOGA does **not** pay for EB-managed load-balancer registration, so an EB instance is normally **not** added to its environment's ALB target group — a fresh or | worker2/.platform/hooks/postdeploy/060_register_instance_to_shared_application_load_balancer.sh, worker2/ebs/register_instance_to_shared_application_load_balancer.php, worker2/.platform/hooks/_shared/040-write-instance-id.sh, worker2/.platform/hooks/_shared/041-write-region.sh, worker2/.platform/hooks/_shared/042-write-eb-environment.sh, worker2/.platform/hooks/postdeploy/015_install_composer.sh, saml/.platform/hooks/_shared/040-write-instance-id.sh, saml/.platform/hooks/_shared/041-write-region.sh, saml/.platform/hooks/_shared/042-write-eb-environment.sh, saml/.platform/hooks/prestart/040-write-instance-id.sh, saml/.platform/hooks/prestart/041-write-region.sh, saml/.platform/hooks/postdeploy/040-write-instance-id.sh, saml/.platform/hooks/postdeploy/041-write-region.sh, saml/.platform/hooks/postdeploy/042-write-eb-environment.sh, saml/.platform/hooks/postdeploy/060_register_instance_to_shared_application_load_balancer.sh, saml/ebs/register_instance_to_shared_application_load_balancer.php, saml/composer.json, api2/.platform/hooks/prebuild/_shared/042-write-eb-environment.sh, api2/.platform/hooks/postdeploy/060_register_instance_to_shared_application_load_balancer.sh, api2/ebs/register_instance_to_shared_application_load_balancer.php |
7
7
  | [All-Client Email Queue Monitor (Monitor/Operations/EmailQueue)](features/all-client-email-queue-monitor.md) | `_Worker_Monitor_Operations::EmailQueue()` is the cross-client health check for the 2.0 outbound email queue (`Logs_<Client>.Email` — see [2.0 Email Send Pipeli | worker2/Worker/Monitor/Operations.php, _underscore/Database.php, _underscore/Query.php, dbchanges2/Logs_Client/2026-05-21 - Email.sql |
8
+ | [API 2.0 Stability Monitor (Monitor/Operations/ApiStability)](features/api-stability-monitor.md) | `_Worker_Monitor_Operations::ApiStability()` is a cross-client/operational **end-to-end round-trip probe** of the production 2.0 API. | worker2/Worker/Monitor/Operations.php, dbchanges2/Core/2026-08-28a - API 2.0 Stability Monitor Cron.sql |
8
9
  | [Automated PR Merger — Concurrent Force-Push Clobber Race](features/automated-pr-merger-force-push-race.md) | The automated PR merger `_Worker_Team_GitHub::Merge` (`worker2` `Worker/Team/Github.php`) merges approved PRs to `_production` by **force-pushing from a clone t | Worker/Team/Github.php |
9
10
  | [Callback Scheduling ("call me back") — worker2 AI-BDR](features/callback-scheduling.md) | The **AI-BDR callback path**: what happens between a prospect saying *"call me back later"* on a Vapi call and the dialer actually placing that second call. | worker2/Worker/Vapi.php, worker2/Worker/Ai/Bdr/Vapi.php, worker2/Controller/Index.php |
10
11
  | [ClickUp Connectivity Watchdog](features/clickup-connectivity-watchdog.md) | A cron watchdog that emails when the ClickUp integration looks disconnected during business hours. | worker2/Worker/Clickup/Health.php, worker2/Database/ClickupHealthWatchdog.sql |
@@ -0,0 +1,140 @@
1
+ ---
2
+ title: API 2.0 Stability Monitor (Monitor/Operations/ApiStability)
3
+ framework: "2.0"
4
+ repo: worker2
5
+ project: Worker
6
+ client: shared
7
+ type: feature
8
+ status: active
9
+ updated: 2026-08-28
10
+ owners: ["jcardinal"]
11
+ files:
12
+ - worker2/Worker/Monitor/Operations.php
13
+ - dbchanges2/Core/2026-08-28a - API 2.0 Stability Monitor Cron.sql
14
+ related:
15
+ - ./oneuptime-worker2-monitoring.md
16
+ - ./netsuite-integrations-monitor.md
17
+ - ./all-client-email-queue-monitor.md
18
+ - ./elastic-beanstalk-health-monitor.md
19
+ ---
20
+
21
+ ## Summary
22
+
23
+ `_Worker_Monitor_Operations::ApiStability()` is a cross-client/operational **end-to-end
24
+ round-trip probe** of the production 2.0 API. Unlike a log-scraper (blind to a dead
25
+ endpoint) or a cheap health-endpoint liveness probe, it performs a real authenticated
26
+ call chain against `api.togahub.com/v2` and only reports OK when the API round-trips a
27
+ representative read correctly. It follows the established "dumb reporter, smart monitor"
28
+ OneUptime push pattern — same shape as the sibling
29
+ [NetsuiteIntegrations](./netsuite-integrations-monitor.md) and
30
+ [EmailQueue](./all-client-email-queue-monitor.md) monitors on
31
+ `_Worker_Monitor_Operations`. Shared internal operational infrastructure, **not** a client
32
+ feature.
33
+
34
+ **Motivating incident.** A `Core.Records` model failed to deploy to production. Because the
35
+ 2.0 API requires a model for every `Core.Records` entry, any call touching the missing
36
+ model returned HTTP 500 — while the Elastic Beanstalk instances stayed "healthy" and the
37
+ `/v2/health` short-circuit route kept returning 200. A monitor that actually round-trips
38
+ the API would have gone red immediately; a health-endpoint probe and an EB health check
39
+ both stayed green. This probe closes that gap.
40
+
41
+ ## Key files / entry points
42
+
43
+ - `worker2/Worker/Monitor/Operations.php` — `abstract class _Worker_Monitor_Operations`;
44
+ `public static function ApiStability(): string`, route
45
+ `Monitor/Operations/ApiStability`. All config is `ALL_CAPS` in-method locals (no
46
+ arguments): `$ONEUPTIME_URL` (push credential), `$API_BASE`, timeouts, expected statuses,
47
+ `$EXPECTED_CLIENT_AUTH_TYPE = 'SSO'`, `$DOMAINS_QUERY`, and `$ORIGIN`.
48
+ - `dbchanges2/Core/2026-08-28a - API 2.0 Stability Monitor Cron.sql` — the `Core.CronJobs`
49
+ seed row (see below).
50
+
51
+ ## How it works
52
+
53
+ Two sequential sub-checks against **production** `api.togahub.com/v2` (the `$API_BASE` is
54
+ hardcoded — the monitor watches prod regardless of which environment runs it). HTTP goes
55
+ through `_ApiRequest` with `ENCODE__JSON` (so `execute()` returns the decoded object) and a
56
+ fresh `transactionId` per request via `_String::generateUuid()`:
57
+
58
+ 1. **Auth** — `POST /v2/auth/public?transactionId=<uuid>` with an `Origin` header (see the
59
+ gotcha below). Expect **HTTP 201**; extract the bearer token from `data.tokens.access`.
60
+ 2. **Representative read** — `GET /v2/domains?<fields/join/where>&transactionId=<uuid>` with
61
+ `Authorization: Bearer <token>` and the same `Origin`. The query is a representative
62
+ joined read across `Domains` + `Environments` + `ClientAuthentications` + `Apps`, scoped
63
+ to the `compass.togasupply.com` PRODUCTION domain. Expect **HTTP 200 AND**
64
+ `data.domains[0].ClientAuthentications.type === 'SSO'` (`$EXPECTED_CLIENT_AUTH_TYPE`).
65
+ This is the exact call that failed during the missing-model incident.
66
+
67
+ Any failed sub-check sets `alarm = 'DEGRADED'` (else `OK`). The method pushes
68
+ `{status:'reporting', alarm, authStatus, domainsStatus, failureCount, failures,
69
+ checkedAtUtc}` to OneUptime, then returns a structured summary string recorded in
70
+ `WorkerJobs.output`.
71
+
72
+ Compass USA's production supply domain is used only as a **representative** live call — this
73
+ is shared platform/liveness knowledge, not client-specific behavior.
74
+
75
+ ### Never-throw / non-fatal push
76
+
77
+ Logging is off, `throwExceptionsOnFailure` is off, and the push is wrapped so a
78
+ monitoring-side failure never fails the worker job — the standard reporter contract from
79
+ [the OneUptime push-metric pattern](./oneuptime-worker2-monitoring.md).
80
+
81
+ ## Cron seed (dbchanges2)
82
+
83
+ `dbchanges2/Core/2026-08-28a - API 2.0 Stability Monitor Cron.sql` — one `Core.CronJobs`
84
+ row: action `Monitor/Operations/ApiStability`, schedule `*/5 * * * *` (every 5 min, all
85
+ hours), `maxExecutionTime` 120, `parameters` NULL (no arguments), **`isActive = 0`**
86
+ (ships inert per the deploy-inert convention — flip to 1 after the OneUptime monitor exists
87
+ and its push URL is set). Core-database-only references (cluster-isolation satisfied); no
88
+ `Core.Records`/`RecordFields` involved.
89
+
90
+ ## Gotchas / known issues
91
+
92
+ - **`POST /v2/auth/public` returns HTTP 401 without an `Origin` request header.** The
93
+ public-auth endpoint carries **no** client credential; the API resolves which client/app
94
+ the public token is minted for from the request's `Origin` header. A server-side call must
95
+ set it explicitly (`Origin: https://compass.togasupply.com`) — the browser supplies Origin
96
+ automatically, which is why the front end's public-token flow
97
+ (`toga-blox-npm/src/api/auth.ts` POSTs to `/auth/public` with a null body + JSON
98
+ content-type) never sees this. Send the same `Origin` on the `/domains` call too, mirroring
99
+ the browser. This is the non-obvious fact for anyone scripting a server-side call to the
100
+ public-auth endpoint. (Verified 2026-08-28: with Origin, auth → 201 and domains → 200 +
101
+ `SSO`; without it, auth → 401.)
102
+ - **The push URL is a credential** — it lives only as the in-method `$ONEUPTIME_URL` local,
103
+ never logged and never written into a doc or into dbchanges2.
104
+ - **Watches PRODUCTION regardless of runner.** `$API_BASE` is hardcoded to prod, so a
105
+ non-prod worker still probes prod — intended, but do not "fix" it to the running env.
106
+
107
+ ## OneUptime import artifact
108
+
109
+ Provisioned by importing an Incoming-Request monitor export (a local staging artifact,
110
+ `C:\STAGE\monitor-export-api-2.0-stability-2026-08-28.json` — **not** a repo file) with three
111
+ criteria: body Contains `"alarm":"DEGRADED"` → Degraded + incident (templated with
112
+ `{{requestBody.failures}}` etc.); body Contains `"alarm":"OK"` → Operational;
113
+ not-received-25-min → Offline + incident. Per the
114
+ [activation-ordering trap](./oneuptime-worker2-monitoring.md#gotchas--known-issues), the
115
+ absence criterion ships `isEnabled: false` — enable it after the first push lands.
116
+ Project-specific status/severity ObjectIDs were cloned from an existing monitor export.
117
+
118
+ ## Change history
119
+
120
+ - 2026-08-28 — Built `ApiStability()` on `_Worker_Monitor_Operations` — a two-step
121
+ end-to-end round-trip probe (auth/public → 201 → bearer, then a joined `/v2/domains` read
122
+ → 200 + `SSO`) against production `api.togahub.com/v2`, plus the `Core.CronJobs` seed
123
+ (`*/5 * * * *`, `isActive=0`) and an Incoming-Request OneUptime import. Motivated by a
124
+ missing `Core.Records` model that 500'd real calls while EB/health-endpoint stayed green.
125
+ Recorded the durable gotcha that `POST /v2/auth/public` **401s without an `Origin`
126
+ header** (the API resolves the client from Origin). Verified working end-to-end after the
127
+ Origin fix. (jcardinal)
128
+
129
+ ## Related docs
130
+
131
+ - [OneUptime push-metric monitors for 2.0 workers](./oneuptime-worker2-monitoring.md) — the
132
+ push/token pattern, OneUptime criteria, import-JSON schema, deploy-inert and
133
+ activation-ordering conventions, and the liveness-probe-vs-log-scraper distinction.
134
+ - [NetSuite Integrations Monitor](./netsuite-integrations-monitor.md) and
135
+ [All-Client Email Queue Monitor](./all-client-email-queue-monitor.md) — sibling
136
+ `_Worker_Monitor_Operations` monitors modeled on the same reporter contract.
137
+ - [Elastic Beanstalk Health Monitor](./elastic-beanstalk-health-monitor.md) — EB-level
138
+ health this probe deliberately reaches past (EB stayed healthy during the incident).
139
+ </content>
140
+ </invoke>
@@ -6,7 +6,7 @@ project: Worker
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-08-20
9
+ updated: 2026-08-28
10
10
  owners: ["jcardinal", "mhammontree", "bala"]
11
11
  files:
12
12
  - worker2/Worker/Monitor/Compass.php
@@ -195,6 +195,21 @@ touches it. Rules for the probe:
195
195
  duplicate credentials into a second repo and race the shared access token. Accept and record the
196
196
  coverage gap rather than forking the client.
197
197
 
198
+ #### A round-trip probe is stronger than a health-endpoint probe
199
+
200
+ A health endpoint that short-circuits before any real work (`/v2/health` → 200) proves the
201
+ process is up, but **not** that the API can actually serve a request. A missing `Core.Records`
202
+ model once 500'd every real call while `/v2/health` and EB health both stayed green. Where an
203
+ integration matters, add an **end-to-end round-trip probe** that authenticates and reads a
204
+ representative record, asserting on the returned data — not just the HTTP status. First
205
+ instance: [API 2.0 Stability Monitor](./api-stability-monitor.md), which mints a public token
206
+ then reads `/v2/domains` and asserts `ClientAuthentications.type === 'SSO'`.
207
+
208
+ **Gotcha for a server-side public-auth call:** `POST /v2/auth/public` returns **HTTP 401
209
+ without an `Origin` request header** — the endpoint carries no client credential and resolves
210
+ the client/app from `Origin`. The browser supplies it automatically; a scripted call must set
211
+ it explicitly. See the API-stability doc for details.
212
+
198
213
  ### Tunable thresholds live in `Core.CronJobs.parameters`, everything else stays a local
199
214
 
200
215
  The alarm threshold is the **one** setting that goes in the DB, as
@@ -356,6 +371,12 @@ check for another client.
356
371
  monitors must pass the region (see [Cloud S3 helpers](../../_underscore/features/cloud-s3-helpers.md)).
357
372
 
358
373
  ## Change history
374
+ - 2026-08-28 — Added the **round-trip probe** refinement (an authenticated end-to-end read
375
+ that asserts on returned data is stronger than a `/v2/health` short-circuit or EB health
376
+ check — a missing `Core.Records` model 500'd real calls while both stayed green) and the
377
+ durable gotcha that `POST /v2/auth/public` **401s without an `Origin` header** (the API
378
+ resolves the client from Origin). First instance:
379
+ [API 2.0 Stability Monitor](./api-stability-monitor.md). (jcardinal)
359
380
  - 2026-08-24 — Documented the **monitor import-JSON schema** the runbook previously described
360
381
  only conceptually: the `oneuptime-resource-export` envelope, `monitorType` must be the
361
382
  spaced display name `"Incoming Request"`, the `_type`-tagged
@@ -410,6 +431,7 @@ check for another client.
410
431
  5-min cadence → 10/15-min heartbeat timing. (jcardinal)
411
432
 
412
433
  ## Related docs
434
+ - [API 2.0 Stability Monitor](./api-stability-monitor.md) — the first end-to-end round-trip probe instance (auth/public + /domains SSO assertion)
413
435
  - [Monitoring Framework](./monitoring-framework.md) — the parallel DB-driven, email-alert monitoring pattern
414
436
  - [Cloud S3 helpers](../../_underscore/features/cloud-s3-helpers.md) — `_Cloud::getS3Objects()` used to list the EDI bucket
415
437
  - [OneUptime 1.0 worker uptime monitoring](../../../1.0/apps/worker/features/oneuptime-worker-uptime-monitoring.md) — the 1.0 push-heartbeat predecessor
@@ -19,7 +19,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
19
19
  ## 2.0 framework
20
20
 
21
21
  - **_underscore** (_Underscore) _(framework core)_ — 70 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
22
- - **worker2** (Worker) — 57 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
22
+ - **worker2** (Worker) — 58 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
23
23
  - **api2** (API) — 25 doc(s) → [2.0/apps/api2/INDEX.md](2.0/apps/api2/INDEX.md)
24
24
  - **dbchanges2** (Database Changes) _(framework core)_ — 13 doc(s) → [2.0/apps/dbchanges2/INDEX.md](2.0/apps/dbchanges2/INDEX.md)
25
25
  - **toga2-supply** (TOGa Supply) — 9 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.673",
3
+ "version": "1.0.674",
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",