toga-ai 1.0.1199 → 1.0.1201

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.
@@ -3,5 +3,6 @@
3
3
  | Doc | Summary |
4
4
  |-----|---------|
5
5
  | [API 1.0 (api) Architecture](architecture.md) | The 1.0 REST `api` (clients, suppliers, Talos Voice): single front controller `api.php`, route classes in `_/app/route/`, no sessions, error handling from libra |
6
+ | [BitStorm diagnostic post (1.0 api POST /order/<n>/diagnostic) — Device + Diagnostics + results document](features/bitstorm-order-diagnostic-endpoint.md) | How BitStorm posts PC scan results to an ODP quote, why one failure wipes the whole post, and how to debug the 1.0 api; open when a quote has no device/diag dat |
6
7
  | [Talos Ticket API (1.0 api POST/PUT /ticket) — Desk tickets + file uploads from Talos Voice](features/talos-ticket-endpoint.md) | 1.0 `api` route that Talos Voice calls to create (`POST /ticket`) and update (`PUT /ticket/{ticketNumber}`) TOGa Desk tickets and attach call files; open before |
7
8
  | [Deploying API 1.0 to Elastic Beanstalk (PHP 8.5 / Amazon Linux 2023)](workflows/deploy-to-elastic-beanstalk-al2023.md) | How the 1.0 `api` deploys on EB PHP 8.5 / AL2023 (Apache proxy) — prod env + pipeline, the nonprod api sandbox (= beta), s3fs 1.97 mount over IMDSv2, cross-acco |
@@ -0,0 +1,49 @@
1
+ ---
2
+ title: "BitStorm diagnostic post (1.0 api POST /order/<n>/diagnostic) — Device + Diagnostics + results document"
3
+ framework: "1.0"
4
+ repo: api
5
+ project: API 1.0
6
+ client: office-depot
7
+ type: feature
8
+ status: active
9
+ updated: 2026-10-29
10
+ owners: ["snaredla"]
11
+ files:
12
+ - api/_/app/route/order.php
13
+ - api/api.php
14
+ - api/ebs/s3fs.prod.json
15
+ - library/app/model/toga/document.php
16
+ related:
17
+ - ../../library/features/app-cloud-aws-credentials.md
18
+ - ./talos-ticket-endpoint.md
19
+ - ../../togadesk/features/s3fs-asifiles-file-storage.md
20
+ - ../../library/features/error-capture-1-0.md
21
+ - ../../toga/features/odp-tech-services-job-jacket-answers.md
22
+ - ../../../../clients/office-depot/profile.md
23
+ ---
24
+ How BitStorm posts PC scan results to an ODP quote, why one failure wipes the whole post, and how to debug the 1.0 api; open when a quote has no device/diag data or a diag post returns 500.
25
+
26
+ ## Summary
27
+
28
+ `postOrderDiagnostic` in `api/_/app/route/order.php` saves the Device, the Diagnostics rows and (on a full scan, i.e. every Existing PC quote) the HTML results document via `App_Model_Toga_Document::save()`. The store needs the device/diag data to sell a service.
29
+
30
+ ## How it works
31
+
32
+ - `api.php` ~229 wraps **every** route in `App_Database::beginTransaction()`. Any fatal → HTTP 500 → the Device and Diagnostics rows roll back too.
33
+ - Results document → `Document::save()` → s3fs mount write (`api` has no AWS SDK; see the no-SDK fallback in [App_Cloud](../../library/features/app-cloud-aws-credentials.md)).
34
+
35
+ ## Gotchas
36
+
37
+ - **~2026-10-05 to TRUE-83311: every post with a results document returned 500** (`Document::save()` called `App_Cloud::copyFileToS3` → missing SDK `Error`). Posts with an empty document passed. Quotes from that window with Existing PC diag posts have no diag data — the store must re-run the diag.
38
+ - **OPEN (developer to decide): result documents are now public-read.** `api/ebs/s3fs.prod.json` mounts `asifiles` with `default_acl=public-read`; `copyFileToS3` uploaded private. systemInformation and Talos uploads already go through the same mount.
39
+ - **OPEN (seen, not confirmed a bug):** toga `finalizequote.php` ~628 skips saving service answers when a device is in session.
40
+
41
+ ### Debugging the 1.0 api
42
+
43
+ 1. `Logs.API` row with `responseCode` NULL = the request died.
44
+ 2. api errors are **not** in `Logs.Errors`: api's `App_Error` inserts columns (`dtStamp`, `framework`, `urlDetails`, …) the legacy table lacks.
45
+ 3. EB env `togatech-legacy-api-production` (profile `toga-production`, us-east-1) has no CloudWatch log shipping. Use `aws elasticbeanstalk request-environment-info --info-type bundle`, then read httpd `access_log` (`500 1105` = App_Error page).
46
+ 4. Compare failing vs passing posts with `JSON_EXTRACT` on `Logs.API.requestPayload`.
47
+
48
+ ## Change history
49
+ - 2026-10-29 — Created: no-SDK document save fixes 500 + rollback of diag data; api debug recipe; open ACL risk (TRUE-83311) (snaredla)
@@ -6,7 +6,7 @@ project: Library
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-10-23
9
+ updated: 2026-10-29
10
10
  owners: [jcardinal, mhammontree, bala, snaredla, rgirish]
11
11
  files:
12
12
  - library/app/cloud.php
@@ -80,6 +80,7 @@ CodePipeline `Worker` (502, us-west-2) sources `_production` of **both** `agilan
80
80
  - **Testing gotcha:** after one passing run, `databaseReadHost.txt` is fresh for 30-60 s, so a control run right after also passes. Wait > 60 s (or delete the cache file) before the control.
81
81
  - store: fixed on branch (TRUE-82856, ae1861f4f — same pins plus aws-crt-php 1.2.7, psr/http-client 1.0.3, polyfill-mbstring 1.31.0; verified on PHP 7.2.33); needs merge + deploy. Its `.ebextensions/015_install_composer.config` already runs `composer install --no-dev`.
82
82
  - **Missed by the audit (TRUE-82935): the 1.0 `api` repo** (no composer at all) and **togadesk's email cron** (`crons/tickets.php` loads only `desk/vendor/autoload.php`; the root togadesk composer with aws is not loaded there). Both stopped `App_Cloud`: [Talos ticket API](../../api/features/talos-ticket-endpoint.md), [email intake](../../togadesk/features/email-to-ticket-intake.md). Audit per **entry point**, not per repo: a CLI cron or sub-app can load a different autoloader than the web app.
83
+ - **`App_Model_Toga_Document::save()` has a no-SDK fallback (TRUE-83311).** If `!class_exists('Aws\S3\S3Client')` it writes to `storage_folder` + the same `/togadocuments-<env>/<clientId>/<id>` path (`storage_folder` = s3fs mount of `asifiles`) instead of `App_Cloud::copyFileToS3`. SDK apps (toga, togadesk, worker, togaview) unchanged; api, vision, store, worker1.5, compass take the mount path. The library autoloader returns `false` on a `class_exists` miss, so the check is safe. Caller: [BitStorm diagnostic endpoint](../../api/features/bitstorm-order-diagnostic-endpoint.md).
83
84
  - The missing class throws **`Error`, not `Exception`** — `catch (Exception)` around an App_Cloud call does not catch it; use `\Throwable` where a fallback is meant.
84
85
  - Not changed on TRUE-82856: walmarttechservices — GitHub repo `agilantsolutions/walmarttechservices` no longer exists ("Repository not found", checked 2026-10-16); webhook — reported no longer active by the developer (2026-10-16). Removal / deprecation is left to the owners.
85
86
  - Verify assume-role in CloudTrail (`AssumeRole` on `WorkloadsRuntime`, by session name: `library-app-cloud`, `setup-git-libraries`, `register-instance`, `worker-deploy`).
@@ -87,6 +88,7 @@ CodePipeline `Worker` (502, us-west-2) sources `_production` of **both** `agilan
87
88
  - Every long-lived key still in code across repos (SES SMTP, s3fs, ALB scripts, other accounts): [audit 2026-10-13](../../../../2.0/apps/worker2/features/cross-account-aws-access.md#long-lived-keys-still-in-code-audit-2026-10-13).
88
89
 
89
90
  ## Change history
91
+ - 2026-10-29 — `App_Model_Toga_Document::save()` falls back to the s3fs mount when the SDK is missing (TRUE-83311) (snaredla)
90
92
  - 2026-10-23 — walmart-activate added aws-sdk-php; moved-app check + read-host cache testing gotcha (TRUE-83161) (rgirish)
91
93
  - 2026-10-22 — Leaked key was abused (Bedrock LLM-jacking, GuardDuty, TRUE-82983) (jcardinal)
92
94
  - 2026-10-19 — aws-sdk-php audit missed `api` + togadesk email cron; `Error` not `Exception` (TRUE-82935) (jcardinal)
@@ -6,12 +6,14 @@ project: Library
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-10-16
10
- owners: ["rgirish"]
9
+ updated: 2026-10-29
10
+ owners: ["rgirish", "snaredla"]
11
11
  files:
12
12
  - library/app/session.php
13
+ - library/app/framework.php
13
14
  related:
14
15
  - ../architecture.md
16
+ - ../../toga/features/odp-tech-services-job-jacket-answers.md
15
17
  - ../../store/features/prudential-equipme-home.md
16
18
  ---
17
19
  How 1.0 `App_Session` stores sessions (DB `Sessions` + local cache file + `SessionUpdates`), why concurrent AJAX requests can overwrite each other, and what read-only endpoints must do; open before adding AJAX endpoints or session writes in a 1.0 app.
@@ -34,6 +36,8 @@ How 1.0 `App_Session` stores sessions (DB `Sessions` + local cache file + `Sessi
34
36
  - **Read-only endpoints: copy what you need from `$_SESSION`, then `session_abort()`.** No write, no 0.5s sleep, no stale overwrite.
35
37
  - **Long endpoints that change the session: make the change first, then `session_write_close()`** so it saves now, not at shutdown.
36
38
  - **Do not rely on a value set at the end of the same page load** being visible to a parallel request, especially one served by another instance.
39
+ - **`$_SESSION` writes inside an `ajaxAction` method are silently lost.** `App_Framework::ajaxHandler` (`library/app/framework.php` ~147) calls `session_write_close()` before running the action. To save a session value there: `if (session_status() !== PHP_SESSION_ACTIVE) { session_start(); }`, set it, then `session_write_close()` — same as `App_Model_ServiceRequest::createNewServiceRequest`. Missing this created every ODP Existing PC quote twice ([job jacket flow](../../toga/features/odp-tech-services-job-jacket-answers.md), TRUE-83311).
37
40
 
38
41
  ## Change history
39
42
  - 2026-10-16 — Initial: storage model, no-locking stale-write risk, `session_abort()` / early `session_write_close()` rules (found on TRUE-82596). (rgirish)
43
+ - 2026-10-29 — Gotcha: ajaxHandler closes the session before ajax actions (TRUE-83311). (snaredla)
@@ -6,8 +6,8 @@ project: TOGa
6
6
  client: office-depot
7
7
  type: client-feature
8
8
  status: active
9
- updated: 2026-10-23
10
- owners: [jcardinal]
9
+ updated: 2026-10-29
10
+ owners: [jcardinal, snaredla]
11
11
  files:
12
12
  - toga/app/togarefresh2026/customersearch/computerquestions.php
13
13
  - toga/app/togarefresh2023/customersearch/computerquestions.php
@@ -38,9 +38,11 @@ The Tech Services path asks job jacket questions, carries the answers in the URL
38
38
 
39
39
  - **Every argument is user input.** Both methods are called by browser `ajaxAction`, so `$serviceId`, question ids and option ids come from the client. Cast ids to `(int)`; save option id `0` / `'undefined'` as `null`. FK fields are NOT cast by the 1.0 model layer — see the `App_Model::getFieldValueForQuery()` gotcha in the [library architecture](../../library/architecture.md).
40
40
  - **A stray quote in the redirect URL broke the whole path** (MySQL 1064). The old "Next" code ended with `+ "'"`, so the last option id became `0'` and reached the INSERT raw. When editing the redirect, check the last pair survives the `&`/`=` split clean.
41
+ - **Quote must be in `$_SESSION['serviceRequestId']` before `servicequestions.php` runs.** `servicequestions.php` (~21-32) creates a new quote when that key is empty. `createNewServiceRequestRefresh()` (ajax from 2026 `view.php` ~638, 2023 `view.php` ~600) did not save it (ajax session gotcha, see [App_Session](../../library/features/app-session-db-store.md)), so every Existing PC quote (job jacket 1) was created twice, 0-2 s apart (since at least 2026-10-01). Fixed TRUE-83311.
41
42
  - **Two copies of `computerquestions.php`** (togarefresh2023 and togarefresh2026) — fix both.
42
43
  - **OPEN (not fixed, needs a ticket): no ownership check.** Neither method checks that the session user may write to the given ServiceRequest id — any logged-in user can rewrite another SR's answers.
43
44
  - **OPEN (not fixed, needs a ticket): `refreshArrayJobJacketQuestions` saves the option id into the wrong property** — `jobJacketQuestionId` (~line 679) and `answerJobJacketQuestion` (~line 707) instead of `answerJobJacketQuestionOptionId`.
44
45
 
45
46
  ## Change history
46
47
  - 2026-10-23 — Removed stray `+ "'"` from both `computerquestions.php` redirects (fixed MySQL 1064 on save); `(int)`-cast serviceId/question/option ids in both refresh methods, option 0 → null (TRUE-83172) (jcardinal)
48
+ - 2026-10-29 — `createNewServiceRequestRefresh()` now saves `serviceRequestId` to session; stops duplicate quotes (TRUE-83311) (snaredla)
@@ -11,6 +11,7 @@
11
11
  | [_ApiRequest — JSON encode/decode & api-logging behavior](features/apirequest-json-content-type.md) | `_ApiRequest`, the 2.0 outbound HTTP client — JSON encode/decode, retry, and api-logging traps; open before calling it or reading `Logs.Api`. |
12
12
  | [Assortment Name Translation (AssortmentTranslations sidecar)](features/assortment-name-translation.md) | Serves Assortment names in multiple languages via an `AssortmentTranslations` sidecar table on the metadata-driven translation layer; open when translating asso |
13
13
  | [Asynchronous Query Execution (writes-only, via Worker)](features/async-query-execution.md) | Run a slow WRITE asynchronously via the Worker tier so a long request write cannot hold a stale connection and hit "MySQL server has gone away"; open before usi |
14
+ | [Aurora MySQL binlog on the 2.0 clusters — current settings, who reads it, and what a change costs](features/aurora-binlog-configuration.md) | Binlog state of the prod and non-prod 2.0 Aurora MySQL clusters, the us-east-1 vs us-west-2/eu-west-1 parameter group mismatch, proof nothing reads the binlog, |
14
15
  | [Record numbering (FIELD_AUTOINCREMENT: per-client sequential numbers from RecordNumbers)](features/autoincrement-record-numbering.md) | ORM record numbers (`SA139197`, `AJ100000`, `CL146`) counted in order per client from a `RecordNumbers` table; open when adding a numbered model/prefix, debuggi |
15
16
  | [Calculated-column filter options (`<field>FilterOptions` model static → table meta)](features/calculated-column-filter-options.md) | Lets a calculated (`FIELD_SQL`) table column supply its own filter dropdown options via a `<field>FilterOptions` model static; open when adding a data-driven co |
16
17
  | [FIELD_SQL calculated fields — the underscore-prefix + same-name-method contract](features/calculated-sql-fields.md) | A `FIELD_SQL` (calculated) field on a `_Model` is bound by a **two-part contract that `_Model` enforces by throwing at model-construction time**, not by convent |
@@ -0,0 +1,82 @@
1
+ ---
2
+ title: Aurora MySQL binlog on the 2.0 clusters — current settings, who reads it, and what a change costs
3
+ framework: "2.0"
4
+ repo: _underscore
5
+ project: _Underscore
6
+ client: shared
7
+ type: feature
8
+ status: active
9
+ updated: 2026-10-29
10
+ owners: ["rgirish"]
11
+ files: []
12
+ related:
13
+ - ../architecture.md
14
+ - ../../../../1.0/apps/worker1.5/features/database-backups.md
15
+ ---
16
+
17
+ Binlog state of the prod and non-prod 2.0 Aurora MySQL clusters, the us-east-1 vs us-west-2/eu-west-1 parameter group mismatch, proof nothing reads the binlog, and why a binlog_format change needs a writer reboot (outage); open before touching any binlog parameter or planning CDC/replication off the 2.0 databases.
18
+
19
+ ## Summary
20
+
21
+ Prod has binlog ON (`STATEMENT`, enhanced binlog) on core/client/archive/logs, but **nothing reads it** (checked 2026-10-29, TRUE-83342). `binlog_format` is a **static** parameter: changing it needs a **writer reboot**, and every prod cluster has **one instance only**, so the reboot is a real write outage for that family. The same-named parameter group **differs by region** — change all 3 regions together.
22
+
23
+ ## How it works
24
+
25
+ ### Prod (account 654654170868, primary us-east-1)
26
+
27
+ - 5 Aurora MySQL Global Databases, engine `8.0.mysql_aurora.3.08.2`: `production-{core,client,archive,logs,cache}-global`.
28
+ - Writer cluster `production-<x>-1` (us-east-1); secondaries `-2` (us-west-2), `-3` (eu-west-1).
29
+ - **Each cluster has exactly 1 instance** (`production-<x>-1-i01`). No in-region reader, no in-region failover target.
30
+ - Global Database replicates at the **storage layer**, not via binlog. Binlog is not needed for the secondaries.
31
+
32
+ | Cluster | Cluster parameter group | Binlog |
33
+ |---|---|---|
34
+ | core, client, archive, logs | `true-rds-cluster-parameters` | ON |
35
+ | cache | `default.aurora-mysql8.0` | OFF |
36
+
37
+ `true-rds-cluster-parameters` values per region:
38
+
39
+ | Parameter | us-east-1 (writers today) | us-west-2 and eu-west-1 |
40
+ |---|---|---|
41
+ | `binlog_format` | `STATEMENT` | `STATEMENT` |
42
+ | `aurora_enhanced_binlog` | `1` | off |
43
+ | `binlog_backup` | `0` | `1` |
44
+ | `binlog_replication_globaldb` | `0` | `1` |
45
+ | `binlog_row_image` | `MINIMAL` | not checked |
46
+
47
+ Live check on us-east-1 writers: `log_bin = ON`.
48
+
49
+ ### Non-prod (account 975050298201, us-east-1)
50
+
51
+ - 19 single-instance clusters (`sandbox-dev`, `sandbox-client`, `stage`, `demo`, `client-*`, `qa-*`, `qc-*`), engine `3.10.3`.
52
+ - All on `true-rds-cluster-parameters` with `binlog_format = OFF` (`log_bin = 0`). No Global Database.
53
+
54
+ ### Who reads the binlog (2026-10-29: nobody)
55
+
56
+ - No `Binlog Dump` threads on prod core/client/archive/logs writers (the login sees `rdsadmin` threads, so the processlist is complete).
57
+ - Only `rdsadmin` and `rds_superuser_role` hold `REPLICATION SLAVE` / `REPLICATION CLIENT`.
58
+ - No RDS zero-ETL integrations and no binlog replica clusters in us-east-1, us-west-2, eu-west-1.
59
+ - **Not checked:** AWS DMS — SSO role `GoAgilant-Developers` gets AccessDenied on `dms:Describe*`. The processlist check is one point in time.
60
+
61
+ ### Changing a binlog parameter
62
+
63
+ 1. Re-run the reader checks below first (a reader may have appeared).
64
+ 2. Change the parameter in `true-rds-cluster-parameters` in **all 3 regions** (us-east-1, us-west-2, eu-west-1).
65
+ 3. `binlog_format` (and other `ApplyType = static` parameters) leave the cluster `pending-reboot` until the writer reboots.
66
+ 4. Reboot each writer in a window. Estimate ~30-60 s per writer, maybe longer: with binlog ON, binlog recovery runs at startup (enhanced binlog shortens it). Secondaries keep serving reads during the primary reboot. No real reboot timing exists (no reboot events in the last 14 days); a non-prod test gives only a lower bound because binlog is off there.
67
+
68
+ ### Read-only checks
69
+
70
+ - Static vs dynamic: `aws rds describe-db-cluster-parameters --db-cluster-parameter-group-name true-rds-cluster-parameters --region <r>` → `ApplyType` column.
71
+ - Binlog readers (toga-db): `SELECT * FROM information_schema.PROCESSLIST WHERE COMMAND LIKE 'Binlog Dump%'`.
72
+ - Replication grants: `SELECT * FROM information_schema.USER_PRIVILEGES WHERE PRIVILEGE_TYPE LIKE 'REPLICATION%'`.
73
+ - Zero-ETL: `aws rds describe-integrations --region <r>`.
74
+
75
+ ## Gotchas
76
+
77
+ - **Region mismatch:** after a Global Database failover, the new writer (us-west-2 or eu-west-1) runs plain, non-enhanced binlog with `binlog_backup = 1`. Settings silently change on failover unless all 3 regions match.
78
+ - **Reboot = outage:** one instance per cluster, so rebooting `production-<x>-1-i01` stops writes for that whole family.
79
+ - Binlog ON with no reader only costs write overhead and storage; turning it off is safe today only if the reader checks are still empty.
80
+
81
+ ## Change history
82
+ - 2026-10-29 — First version: prod/non-prod binlog state, region mismatch, no readers found, static-parameter reboot cost (TRUE-83342) (rgirish)
@@ -18,11 +18,11 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
18
18
  - **store** (Store) — 5 doc(s) → [1.0/apps/store/INDEX.md](1.0/apps/store/INDEX.md)
19
19
  - **tools** (Tools) — 25 doc(s) → [1.0/apps/tools/INDEX.md](1.0/apps/tools/INDEX.md)
20
20
  - **vision** (Vision) — 2 doc(s) → [1.0/apps/vision/INDEX.md](1.0/apps/vision/INDEX.md)
21
- - **api** (API 1.0) — 3 doc(s) → [1.0/apps/api/INDEX.md](1.0/apps/api/INDEX.md)
21
+ - **api** (API 1.0) — 4 doc(s) → [1.0/apps/api/INDEX.md](1.0/apps/api/INDEX.md)
22
22
 
23
23
  ## 2.0 framework
24
24
 
25
- - **_underscore** (_Underscore) _(framework core)_ — 117 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
25
+ - **_underscore** (_Underscore) _(framework core)_ — 118 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
26
26
  - **worker2** (Worker) — 102 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
27
27
  - **api2** (API) — 29 doc(s) → [2.0/apps/api2/INDEX.md](2.0/apps/api2/INDEX.md)
28
28
  - **dbchanges2** (Database Changes) _(framework core)_ — 24 doc(s) → [2.0/apps/dbchanges2/INDEX.md](2.0/apps/dbchanges2/INDEX.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.1199",
3
+ "version": "1.0.1201",
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",