toga-ai 1.0.907 → 1.0.909
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/2.0/apps/_underscore/features/error-reporting-issue-event.md +5 -1
- package/knowledge/2.0/apps/_underscore/features/order-for-delegation.md +16 -1
- package/knowledge/2.0/apps/worker2/architecture.md +3 -1
- package/knowledge/2.0/apps/worker2/features/cross-account-aws-access.md +16 -1
- package/knowledge/2.0/apps/worker2/features/tracking-status-refresh.md +4 -2
- package/package.json +1 -1
|
@@ -6,7 +6,7 @@ project: _Underscore
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-09-
|
|
9
|
+
updated: 2026-09-28
|
|
10
10
|
owners: ["dfranks", "jcardinal", "mhammontree", "ajean", "bala", "apeterson"]
|
|
11
11
|
files:
|
|
12
12
|
- _underscore/Error.php
|
|
@@ -687,6 +687,10 @@ read you feed it — `_Error` promotes a *"read property on int"* warning into a
|
|
|
687
687
|
|
|
688
688
|
## Gotchas
|
|
689
689
|
|
|
690
|
+
- **`Logs.Issue` starts 2026-08-03 on prod — there are no rows before it.** The table went live with
|
|
691
|
+
that migration, so **any 500 older than 2026-08-03 has no Issue row at all**: looking its
|
|
692
|
+
`error.id` up returns nothing, and the `Logs.Api` row is the only record you get. An empty result
|
|
693
|
+
for an old error is the expected state, not a capture failure.
|
|
690
694
|
- **⚠ A missing `Logs.Issue` column silently disables ALL error capture on that environment** —
|
|
691
695
|
see the open defect above. Symptom: `identifiers.captureFailure` in the API response and nothing
|
|
692
696
|
anywhere else.
|
|
@@ -6,7 +6,7 @@ project: _Underscore
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-09-
|
|
9
|
+
updated: 2026-09-28
|
|
10
10
|
owners: [bala, tcox]
|
|
11
11
|
files:
|
|
12
12
|
- _underscore/Model/Client/Users/DelegatorUser.php
|
|
@@ -122,6 +122,19 @@ paging. Two hard rules in
|
|
|
122
122
|
- **api2 does log 4xx rows** (59 × 403 on client-sandbox in the last 30 days), so a missing 403 in
|
|
123
123
|
`Logs_<Client>.Api` means the call never happened or hit another environment — check the host
|
|
124
124
|
before blaming the log.
|
|
125
|
+
- **⚠ `POST /v2/auth/delegator` 500s on a PUBLIC (logged-out) token — known, deliberately not
|
|
126
|
+
fixed.** `V2.php` L896 checks `property_exists($this->jwtPayload->id, 'delegator')`; when the
|
|
127
|
+
claim is absent the `else` reads `$this->jwtPayload->id->client->user->uuid` at **L903** with no
|
|
128
|
+
check that `user` exists. A public token's `id.client` is `{uuid, slug, roles, api}` and carries
|
|
129
|
+
**no `user` key**, so PHP raises *"Undefined property: stdClass::$user"* and the caller gets a
|
|
130
|
+
**500 `EO-1`** instead of a clean **401 `EN-3`**. The same file already guards this exact shape
|
|
131
|
+
~50 lines lower (L952, the expired-token `elseif`: `property_exists($this->jwtPayload->id->client,
|
|
132
|
+
'user')`) — L903 is the one place that does not. Reachable **with no login**. Evidence:
|
|
133
|
+
`Logs.Issue` reference **T2**, 6 occurrences in 11 s on 2026-09-04 and none since; the failing
|
|
134
|
+
token decoded out of `Logs.Api.requestHeaders` was slug `Compass_Usa`, roles `[1,3]`, `api`
|
|
135
|
+
present, no `user`. **Decision (2026-09-28, bala): leave it.** Dormant and low impact; add the
|
|
136
|
+
one-line guard returning `DEFINED_MESSAGE_ERROR_INVALID_ACCESS_TOKEN` next time someone is in
|
|
137
|
+
that block — do not open a ticket for it.
|
|
125
138
|
- **Role 3 (API) cannot reach this record.** Its grant for record 362 was written into `Core`, but
|
|
126
139
|
`aclDatabase = CLIENT` means Core rows are never consulted — so no integration can read or write
|
|
127
140
|
`user-delegator-users` through api2 until the grant is mirrored into each `Client_*` DB.
|
|
@@ -154,6 +167,8 @@ paging. Two hard rules in
|
|
|
154
167
|
|
|
155
168
|
## Change history
|
|
156
169
|
|
|
170
|
+
- 2026-09-28 — Recorded the `/auth/delegator` public-token 500 at `V2.php` L903 (no `user` guard,
|
|
171
|
+
`Logs.Issue` T2) and the decision to leave it unfixed. (bala)
|
|
157
172
|
- 2026-09-22 — Front end now switches the token, so the gate is live: recorded that
|
|
158
173
|
`originalUserId` is still NULL on client-sandbox during a real Order For session, that the gate
|
|
159
174
|
also returns 403 EZ-1 for admin View As of anyone off the list, and that api2 does log 4xx rows.
|
|
@@ -6,7 +6,7 @@ project: Worker
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: architecture
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-09-
|
|
9
|
+
updated: 2026-09-28
|
|
10
10
|
owners: [jcardinal, ajean, rgirish]
|
|
11
11
|
files:
|
|
12
12
|
- worker2/Controller/Index.php
|
|
@@ -151,6 +151,8 @@ For **programmatic** enqueue via `_Worker::runTask()`, the MySQL-first rule was
|
|
|
151
151
|
|
|
152
152
|
## Gotchas
|
|
153
153
|
|
|
154
|
+
- **Shrinking `WorkerJobs.output` MEDIUMTEXT → TEXT (planned, not yet done).** TEXT holds 65,535 **bytes** (utf8mb4 = up to 4 bytes/char), not chars. Trim byte-safe before the ALTER, repeating until 0 rows: `UPDATE WorkerJobs SET output = LEFT(output, CHAR_LENGTH(output) - (LENGTH(output) - 65535)) WHERE LENGTH(output) > 65535 LIMIT 1000`. After the change, every producer must truncate first or the result UPDATE fails with 1406 Data too long (strict mode) and the job result is lost: PHP check-out (both paths in `Controller/Index.php`) and the JobScheduler watchdog Lambda UPDATE (repackage + redeploy it). The `MODIFY` must restate the column COMMENT. On MySQL 8 the type change rebuilds the table.
|
|
155
|
+
|
|
154
156
|
- **⚠ OBSERVED `Core.WorkerJobs` retention is ~30 days, not 90 — unexplained.** Measured 2026-09-15 in prod: `MIN(dtCreated)` across the **whole** table is **2026-08-16 02:00:46** (790,597 rows). Either the cleanup cron does not behave as described, or something else prunes the table. **Not investigated** — no cause is asserted.
|
|
155
157
|
- **A missing `WorkerJobs` row is NOT proof the job never ran.** Any "there is no job for this record, so the webhook never fired" conclusion is invalid past the ~30-day floor. That exact wrong call was made and retracted on 2026-09-15. Same failure family as *an empty log table is not proof a code path never ran*.
|
|
156
158
|
- **The watchdog does not stop the PHP process** — an over-budget action keeps running past a false failure row and typically loses its result UPDATE to MySQL 2006 (prod job 1075223). See JobScheduler Part B above.
|
|
@@ -6,7 +6,7 @@ project: Worker
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-09-
|
|
9
|
+
updated: 2026-09-28
|
|
10
10
|
owners: [jcardinal, bala]
|
|
11
11
|
files:
|
|
12
12
|
- worker2/Component/Aws/Workloads/Workloads.php
|
|
@@ -82,6 +82,21 @@ Each `WorkloadsRuntime` role has broad service permissions (`elasticbeanstalk:*`
|
|
|
82
82
|
|
|
83
83
|
The helper adoption was captured earlier: the prior inline STS/credential code and the `HEALTH_ASSUME_ROLE_NAME` / `HEALTH_ASSUME_ROLE_SESSION` constants were removed in favor of `_Component_Aws_Workloads` + the `[cloud]` config keys. The prior `CheckBeanstalks()` action was renamed `ElasticBeanstalkInstances()` (dbchanges2 `Core/2026-08-10c` updates the CronJobs action name; `Core/2026-08-10d` seeds the parameterized `ElasticBeanstalkHealth` cron row, `isActive=0`, and carries the `environments`-map sample parameters).
|
|
84
84
|
|
|
85
|
+
### Second consumer — ElasticBeanstalkInstances (auto-terminate stuck instances)
|
|
86
|
+
|
|
87
|
+
`_Worker_Infrastructure_CloudWatch::ElasticBeanstalkInstances(?regions)` — prod `Core.CronJobs` id 39, every 10 min. Rewritten 2026-09-28 (not yet verified by a real prod run).
|
|
88
|
+
- **Why:** the old version used the aws CLI via `_Cloud::$preCommands` + the legacy static `[cloud]` key, which cannot see 868's EB environments → failed **100% of runs** since 2026-08-29 (`CloudWatch: No environments returned for region us-east-1`). Auto-terminate never worked.
|
|
89
|
+
- **Now:** `assumeCredentials()` once, SDK `ElasticBeanstalkClient` + `Ec2Client` per region (same shape as ElasticBeanstalkHealth).
|
|
90
|
+
- Account is const `INSTANCES_AWS_ACCOUNT_ID = 654654170868`, **not overridable** (it terminates). Optional `regions` must be in `INSTANCES_ALLOWED_REGIONS` (us-east-1, us-west-2, eu-west-1) — region goes into the SDK endpoint host, so allowlist it.
|
|
91
|
+
- Returns JSON `{isSuccess, awsAccountId, environmentCount, terminatedCount, alarmCount, errorCount, terminated[], alarms[], errors[], environments[]}`. Throws only on: region not allowed, assume-role fails, or no region readable. Unhealthy instances no longer throw (developer choice).
|
|
92
|
+
- Guards: 240s budget (`INSTANCES_TIME_BUDGET_SECONDS`; unreached envs go to `errors`); max 3 terminations per run; max floor(50%) of an env's instances but always at least 1 (a single-instance env's only instance may be terminated — EB replaces it; developer choice). Capped / over-budget items go to `errors`, never silently skipped.
|
|
93
|
+
- Termination email kept (private `notifyInstanceTerminated` → Notification/EmailTemplate/Send).
|
|
94
|
+
- `_Cloud::terminateInstance()` in `_underscore` now has no known callers in worker2/_underscore (left in place).
|
|
95
|
+
|
|
96
|
+
### Terminate guard on 868 WorkloadsRuntime
|
|
97
|
+
|
|
98
|
+
Applied 2026-09-28 (AWS CLI) to inline policy `WorkloadsRuntimePermissions` in 654654170868: statement `DenyTerminateNonBeanstalk` — Deny `ec2:TerminateInstances` on `*` when `aws:ResourceTag/elasticbeanstalk:environment-name` is `Null`. Any caller of WorkloadsRuntime can terminate **only EB-managed instances**. The other two accounts' roles do not have this statement.
|
|
99
|
+
|
|
85
100
|
### Legacy static key — being retired
|
|
86
101
|
|
|
87
102
|
The legacy `[cloud]` static access key is a **personal IAM user in account 502614707982**. Being retired for new code but **still used by older code paths** — ZoomInfo, VipSupport, and the `_Cloud` CLI path. **Retrofit of that existing code is deliberately deferred** (developer decision, this session): document the new approach; do not migrate old code yet. New code must not adopt the static key.
|
|
@@ -6,8 +6,8 @@ project: Worker
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-09-
|
|
10
|
-
owners: ["bala"]
|
|
9
|
+
updated: 2026-09-28
|
|
10
|
+
owners: ["bala", "jcardinal"]
|
|
11
11
|
files:
|
|
12
12
|
- worker2/Worker/Sync/TrackingNumbers.php
|
|
13
13
|
- _underscore/Component/Library/Carriers/Fedex/Fedex.php
|
|
@@ -156,6 +156,8 @@ bookkeeping columns.
|
|
|
156
156
|
|
|
157
157
|
## Gotchas
|
|
158
158
|
|
|
159
|
+
- **Every `c_` refresh column must exist in every `Client_*` DB.** One missing column fails that client's `RefreshClient` every run: Adyen failed 144 runs (2026-09-21 14:00 → 2026-09-22 13:50) on `Unknown column 'TrackingNumbers.c_trackingCheckFailures'` until the column was added. Check the fan-out when a new client is provisioned.
|
|
160
|
+
|
|
159
161
|
### ⚠ GO-LIVE GATE — worker2 → api2 hard-crashes on PHP 8.5
|
|
160
162
|
Writes go through api2 PUT, and a worker2 → api2 call **hard-crashes the request on PHP 8.5 (OpenSSL
|
|
161
163
|
3.5.5): a process-level 500 with no catchable trace, and the shutdown handler never fires.** The prod
|
package/package.json
CHANGED