toga-ai 1.0.442 → 1.0.444

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,11 +3,12 @@
3
3
  | Doc | Summary | Files |
4
4
  |-----|---------|-------|
5
5
  | [TOGa Desk Architecture](architecture.md) | TOGa Desk is the staff-facing support desk **and field-service platform** (analysts work at `/desk/`). | desk/index.php, desk/includes/loader.php, desk/config.php, desk/includes/controllers/actions.php, desk/includes/controllers/data.php, desk/includes/controllers/modals.php, desk/includes/classes/class.app.php, desk/includes/classes/class.ticket.php, desk/api/index.php, desk/api/resources/tickets.php, crons/tickets.php |
6
- | [Email-to-Ticket Intake (crons/tickets.php)](features/email-to-ticket-intake.md) | TOGa Desk ingests support email into tickets through a cron-driven IMAP poller (`crons/tickets.php`) plus a postfix pipe variant (`crons/pipe.php`). | crons/tickets.php, crons/tickets_prod.php, crons/pipe.php, desk/includes/classes/class.ticket.php |
6
+ | [Email-to-Ticket Intake (crons/tickets.php)](features/email-to-ticket-intake.md) | TOGa Desk ingests support email into tickets through a cron-driven IMAP poller (`crons/tickets.php`) plus a postfix pipe variant (`crons/pipe.php`). | crons/tickets.php, crons/tickets_prod.php, crons/pipe.php, desk/includes/classes/class.ticket.php, vendor/classes/class.imap.php |
7
7
  | [Field-Service Dispatch (central / repair orders)](features/field-service-dispatch.md) | The **central** subsystem is TOGa Desk's field-service dispatch domain: repair-order lifecycle, technician scheduling, onsite vs depot service, parts, and shipm | desk/includes/controllers/actions/central/, desk/includes/classes/class.repair.php, desk/includes/classes/class.repairhistory.php, desk/_/browser/datatable/central.php, desk/template/pages/central.php, desk/template/pages/central/view.php, desk/template/modals/central/addTracking.php, library/app/model/togadesk/repairorder.php, library/app/model/togadesk/repairordertracking.php, library/app/api/carrier/ups.php |
8
8
  | [Managed Service Order Create Flow (New MSO modal → tickets/add)](features/managed-service-order-create.md) | The **Managed Service Order (MSO) create flow** is how a TOGa Desk user manually creates a managed service order: pick an End User (or a Client Location), choos | desk/includes/controllers/actions/tickets/add.php, desk/template/modals/tickets/addNew.php, desk/template/pages/managed.php, desk/template/pages/getinfo.php, desk/template/footer.php, library/app/model/togadesk/repairorder.php |
9
9
  | [Ticket Email Notifications (notifications table)](features/notifications.md) | Which TOGa Desk emails fire for a given client is driven **entirely by data**, not code: the `TOGaDeskSupport.notifications` table holds one row per `(clientid, | desk/includes/classes/class.notification.php, crons/tickets.php, crons/tickets_prod.php |
10
10
  | [REST API (RPC-over-POST) & API-Key Auth](features/rest-api.md) | TOGa Desk exposes a programmatic API at `desk/api/`. | desk/api/index.php, desk/api/resources/tickets.php, desk/api/resources/assets.php, desk/api/resources/authenticate.php, desk/includes/classes/class.apikey.php, desk/includes/functions.php |
11
11
  | [SMB Contract Editing & the clientMspId Corruption Trap](features/smb-contract-editing.md) | The SMB contracts page (`/desk/?route=toga/smbcontracts&togaClientId=<id>`) edits `TOGA_*.SMBContracts` rows via a modal. | desk/template/modals/toga/smbcontracts/smbContract.php, desk/includes/controllers/modals/toga/smbcontracts/smbContract.php, desk/includes/controllers/actions/toga/smbcontracts/smbContract.php, desk/includes/controllers/actions/toga/smbcontracts/edit.php |
12
12
  | [Ticket Lifecycle (class.ticket.php)](features/ticket-lifecycle.md) | All TOGa Desk ticket creation and reply handling funnels through `Ticket` in `desk/includes/classes/class.ticket.php`. | desk/includes/classes/class.ticket.php, desk/includes/controllers/actions.php, desk/includes/controllers/actions/tickets/addReply.php, desk/api/resources/tickets.php, desk/api/resources/ticket_replies.php, crons/tickets.php, crons/pipe.php, desk/includes/controllers/actions/tickets/merge.php |
13
+ | [Reverting a TOGa Desk _production Deploy (revert-forward)](workflows/production-revert-forward.md) | How to cleanly and verifiably roll back a single ticket's changes from the togadesk `_production` branch. | |
13
14
  | [Standalone PHP Test Script Bootstrap (TOGa Desk)](workflows/standalone-test-scripts.md) | How to write a standalone CLI PHP script that bootstraps the TOGa Desk framework for read-only testing of desk classes (e.g. | |
@@ -6,13 +6,14 @@ project: TOGa Desk
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-07-09
9
+ updated: 2026-07-27
10
10
  owners: ["jcardinal", "dfranks", "mhammontree"]
11
11
  files:
12
12
  - crons/tickets.php
13
13
  - crons/tickets_prod.php
14
14
  - crons/pipe.php
15
15
  - desk/includes/classes/class.ticket.php
16
+ - vendor/classes/class.imap.php
16
17
  related:
17
18
  - 1.0/apps/togadesk/architecture.md
18
19
  - 1.0/apps/togadesk/features/ticket-lifecycle.md
@@ -84,6 +85,17 @@ config framework**: noise filtering is ad-hoc inline guards in the crons (the ha
84
85
  (`E_ALL` + `App_Error::handleError`), so an intake cron could **halt**. Hardened to
85
86
  `return $matches[0] ?? '';` (TRUE-79975) — important because `isSuppressedNoiseEmail` routes
86
87
  nullable/malformed sender input through `extractEmail`, putting this latent bug on the hot path.
88
+ - **`class.imap.php` duplicate trap — the OPPOSITE direction from `class.ticket.php`.** Two
89
+ copies of `class.imap.php` exist with different contents: root-level
90
+ `vendor/classes/class.imap.php` and `desk/vendor/classes/class.imap.php`. For the
91
+ email-intake path the **root-level `vendor/classes/class.imap.php` is the LIVE file** — the
92
+ one the intake cron uses and the one PR edits/reverts must target (confirmed: TRUE-80116's
93
+ attachment MIME-walker rewrite, and its revert, both touched `vendor/classes/class.imap.php`;
94
+ the `desk/vendor/...` copy has a different blob and was never touched). This is the reverse of
95
+ the `class.ticket.php` rule (where `desk/includes/classes/` is live and the repo-root copy is
96
+ dead). Verifying the wrong copy gives a false "byte-identical across commits" result because
97
+ the untouched copy trivially matches. Prior guidance naming `desk/vendor/classes/class.imap.php`
98
+ as live is wrong for intake.
87
99
  - Attachments are deleted locally immediately after the S3 upload with **no retry** if S3 fails.
88
100
  - **`adminid` clobber on reply routing:** after `emailToTicket()` sets `$data['adminid']` from
89
101
  the FROM address (~line 1407), an asset lookup (~line 1437-1442) overwrites it with the
@@ -93,6 +105,9 @@ config framework**: noise filtering is ad-hoc inline guards in the crons (the ha
93
105
  classification. See the ticket-lifecycle doc.
94
106
 
95
107
  ## Change history
108
+ - 2026-07-27 — corrected the live IMAP-class location: root-level `vendor/classes/class.imap.php`
109
+ is the file the intake cron uses (NOT `desk/vendor/classes/class.imap.php`), the opposite of the
110
+ `class.ticket.php` duplicate rule; added it to `files:` (dfranks)
96
111
  - 2026-07-09 — added `Ticket::isSuppressedNoiseEmail()` noise suppression (no-reply sender + "Staples PO"
97
112
  subject) wired into both feeders before ticket creation; hardened `extractEmail()` no-match to
98
113
  `''`; documented the `tickets_defaultdepartment` → "Support Desk" catch-all fall-through
@@ -0,0 +1,67 @@
1
+ ---
2
+ title: Reverting a TOGa Desk _production Deploy (revert-forward)
3
+ framework: "1.0"
4
+ repo: togadesk
5
+ project: TOGa Desk
6
+ client: shared
7
+ type: workflow
8
+ status: active
9
+ updated: 2026-07-27
10
+ owners: ["dfranks"]
11
+ files: []
12
+ related:
13
+ - 1.0/apps/togadesk/architecture.md
14
+ - 1.0/apps/togadesk/features/email-to-ticket-intake.md
15
+ ---
16
+
17
+ ## Summary
18
+ How to cleanly and verifiably roll back a single ticket's changes from the togadesk
19
+ `_production` branch. Deploys land on `_production` as **two-parent merge commits**, so a
20
+ rollback is a `git revert -m 1` of the merge — and when later tickets have since touched the
21
+ same file, the correct rollback is a per-hunk revert (not a whole-file restore), verified with
22
+ `git patch-id`.
23
+
24
+ ## The deploy model
25
+ Changes reach `_production` as merge commits in one of two shapes:
26
+ - PR merge commit — `Merge pull request #NNN from agilantsolutions/TRUE-XXXX`
27
+ - Automated merge — `Merged from TRUE-XXXX to _production (automated)`
28
+
29
+ Both have two parents: parent 1 is the prior `_production` tip, parent 2 is the ticket branch.
30
+
31
+ ## Steps
32
+ 1. Identify the merge commit SHA for the ticket to roll back (`git log --merges` /
33
+ `--grep=TRUE-XXXX`).
34
+ 2. Revert it keeping the `_production` mainline:
35
+ ```
36
+ git revert -m 1 <merge-sha>
37
+ ```
38
+ `-m 1` keeps first parent (`_production`) and undoes the branch's changes. Git reverses only
39
+ that ticket's hunks and auto-merges around any commits that landed later.
40
+ 3. **Do not** do a whole-file restore (e.g. `git checkout <old-sha> -- path`) when a later
41
+ ticket has since modified the same file — that would also wipe the later ticket's work.
42
+
43
+ ## Verifying the revert is exact
44
+ - **File untouched by any later ticket:** whole-file blob/byte equality vs. the pre-ticket
45
+ version is a valid check.
46
+ - **File changed by later tickets:** blob equality is meaningless (line offsets shifted). Prove
47
+ the revert is the precise inverse of the original change with `git patch-id`:
48
+ ```
49
+ # inverse of the original merge's diff for the file
50
+ git show <merge-sha> -- <file> | ...invert... | git patch-id --stable
51
+ # our revert's diff for the file
52
+ git show <revert-sha> -- <file> | git patch-id --stable
53
+ ```
54
+ Equal patch-ids prove the revert change is the exact inverse of the original regardless of
55
+ line-offset shifts from intervening commits.
56
+
57
+ ## Gotchas
58
+ - Confirm you are targeting the **live** copy of any duplicated file before verifying — e.g.
59
+ the email-intake IMAP class is root-level `vendor/classes/class.imap.php`, while the live
60
+ ticket class is `desk/includes/classes/class.ticket.php` (opposite duplicate directions). A
61
+ verification against the wrong (untouched) duplicate falsely reports "identical". See the
62
+ email-to-ticket-intake feature doc.
63
+ - `_production` is the deploy target for togadesk (not `_main`).
64
+
65
+ ## Change history
66
+ - 2026-07-27 — documented the revert-forward rollback + `git patch-id` precision check for the
67
+ togadesk merge-commit deploy model (dfranks)
@@ -7,7 +7,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
7
7
  - **library** (Library) _(framework core)_ — 14 doc(s) → [1.0/apps/library/INDEX.md](1.0/apps/library/INDEX.md)
8
8
  - **worker** (Worker) — 15 doc(s) → [1.0/apps/worker/INDEX.md](1.0/apps/worker/INDEX.md)
9
9
  - **worker1.5** (Worker 1.5) — 0 doc(s) → [1.0/apps/worker1.5/INDEX.md](1.0/apps/worker1.5/INDEX.md)
10
- - **togadesk** (TOGa Desk) — 9 doc(s) → [1.0/apps/togadesk/INDEX.md](1.0/apps/togadesk/INDEX.md)
10
+ - **togadesk** (TOGa Desk) — 10 doc(s) → [1.0/apps/togadesk/INDEX.md](1.0/apps/togadesk/INDEX.md)
11
11
  - **togaview** (TOGa View) — 6 doc(s) → [1.0/apps/togaview/INDEX.md](1.0/apps/togaview/INDEX.md)
12
12
  - **webhook** (Webhook) — 1 doc(s) → [1.0/apps/webhook/INDEX.md](1.0/apps/webhook/INDEX.md)
13
13
  - **walmarttechservices** (Walmart Tech Services) — 1 doc(s) → [1.0/apps/walmarttechservices/INDEX.md](1.0/apps/walmarttechservices/INDEX.md)
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  type: session
3
3
  slug: true-79533-pin-depth
4
- title: TRUE-79533 WH service-address pin blocked by depth=-1 starving postPost
4
+ title: TRUE-79533 WH service-address pin — SHIPPED & verified on beta (was blocked by depth=-1)
5
5
  author: mhammontree
6
6
  repos: [_underscore, dbchanges2, toga2-view]
7
7
  framework: "2.0"
@@ -14,60 +14,61 @@ updated: 2026-07-27
14
14
  # Session: true-79533-pin-depth
15
15
  **Date:** 2026-07-27
16
16
  **Project/Repo:** _underscore / dbchanges2 / toga2-view (2.0, client Rate)
17
- **Task:** Get the validated Whole Home Warranty service address to pin (`Entitlements.serviceAddressId`) and render on beta. Backend is done and correct; the blocker was the beta purchase POST sending `depth=-1`, which starved the `postPost` interceptor of the just-created address id. **FIX CHOSEN: front-end drops `depth`; deploying to beta now — awaiting verification.**
17
+ **Task:** Pin the validated Whole Home Warranty service address (`Entitlements.serviceAddressId`) and render it on beta. **DONE + verified on beta 2026-07-27.** The blocker was the purchase POST sending `depth=-1`, which starved the `postPost` interceptor of the created address id; the front-end dropped `depth` and it now works. Remaining = deploy/merge close-out + knowledge captured.
18
18
 
19
19
  ---
20
20
 
21
21
  ## What WORKED
22
22
  <!-- Include specific file paths and evidence -->
23
- - **Backend pin implemented** in `_underscore/Model/Rate/Entitlement.php` `postPost` → `persistWarrantyServiceAddress`: reads the created address id from the in-memory hydrated payload (`$payload->contact->primaryContactAddress->address->id`), then `UPDATE Addresses SET isValidated=1` + `UPDATE Entitlements SET serviceAddressId=… WHERE uuid=…`. Committed `dff1fb5e`. **Proven working AND already on the beta backend**: ET100057 — a purchase whose request had **no `depth` param** (query string `transactionId=…`, 64,650-byte deep response) — pinned `serviceAddressId=56`, address 56 (STE 400) `isValidated=1`, on the same beta instance that fails for `depth=-1` calls. This is the exact config the FE fix reproduces.
24
- - **`serviceAddressId` is a STANDARD field** on base `_underscore/Model/Client/Entitlement.php:20` (`FIELD_FOREIGNKEY` → `_Model_Client_Address`), inherited by the Rate model.
25
- - **Display EZ-2 fixed**: `dbchanges2/Client_Rate/2026-07-24a - AddressIdFieldPermission.sql` grants READ on `Addresses.id` for roles 1/2/3. Committed `ea1e0fb`. Applied on beta manually and verified.
26
- - **Hard-blocks return HTTP 400** via `_Exception_Validation` (committed `41a5dc1a`) — mapped by `api2/Controller/Index.php:204-222`. (NOT yet on beta — see blockers.)
27
- - **Dedup** `hasActiveWarrantyAtAddress` forces WRITE host + disables query cache; `COALESCE(serviceAddressId, ContactAddresses.addressId)` fallback.
28
- - **Root cause proven via `Logs_Rate.Api`** (MCP env `dev-sandbox`): local-FE and beta-FE purchases hit the SAME beta instance (`i-0ce5624547cfecc93`). Only difference = request query string depth: no-depth → 64 KB deep → **pins**; `depth=-1` → 644 B shallow (`meta.calcDepth: 1`, no `address` node) → **starved**.
29
- - **`-1` source = front-end**: `toga2-view/src/pages/CheckOut/api/checkoutApi.ts:21` (`createService` passed `{ 'depth': -1 }`). Confirmed in the logged query string.
30
- - **Interceptor config (Rohan-confirmed):** `ApiPayloadInterceptors` `minDepth` defaults to **3** when null; entitlements `postPost` (id 2) is explicitly **5**; `prePost` (id 4) & sales-orders (id 3) are null→3. Omitting the request `depth` yields a full/deep build that clears the 5 floor and includes the `address` node.
23
+ - **END-TO-END VERIFIED ON BETA (2026-07-27):** after Tanner removed `depth` from the FE purchase call, both post-fix purchases pinned on their own, no backfill — ET100068 (`serviceAddressId=67` → 233 S WACKER DR, `isValidated=1`) and ET100067 (`serviceAddressId=66` → 1864 HIGH GROVE LN STE 1900, `isValidated=1`). Everything before the FE deploy is still null (clean cutoff). Paulina is PM-testing beta.
24
+ - **FE fix = drop the `depth` param** at `toga2-view/src/pages/CheckOut/api/checkoutApi.ts` (`createService` no longer sends `{depth:-1}`). Deployed to beta. This reproduces the proven-good no-depth config (ET100057 had pinned the same way pre-fix).
25
+ - **Backend pin** in `_underscore/Model/Rate/Entitlement.php` `postPost`→`persistWarrantyServiceAddress`: reads the created address id from the in-memory hydrated payload (`$payload->contact->primaryContactAddress->address->id`), sets `Addresses.isValidated=1` + `Entitlements.serviceAddressId`. Committed `dff1fb5e`. Already live on beta (that's why ET100057/67/68 pinned).
26
+ - **`serviceAddressId` = STANDARD FK field** on base `_underscore/Model/Client/Entitlement.php:20`.
27
+ - **Display EZ-2 fixed**: `dbchanges2/Client_Rate/2026-07-24a - AddressIdFieldPermission.sql` grants read on `Addresses.id` (roles 1/2/3). Committed `ea1e0fb`; applied+verified on beta.
28
+ - **Hard-blocks → HTTP 400** via `_Exception_Validation` (committed `41a5dc1a`), mapped by `api2/Controller/Index.php:204-222`. (On `TRUE-79533`, NOT yet on beta — see blockers.)
29
+ - **Root cause proven via `Logs_Rate.Api`**: local-FE and beta-FE calls hit the SAME beta instance (`i-0ce5624547cfecc93`); only the request `depth` differed (no-depth → 64 KB deep → pins; `depth=-1` → 644 B shallow, `calcDepth 1`, no `address` node → starved). The `-1` came from the FE (`checkoutApi.ts`), not the interceptor.
30
+ - **Interceptor config (Rohan-confirmed):** `ApiPayloadInterceptors.minDepth` defaults to 3 (null); entitlements `postPost` = 5; `prePost`/sales-orders = null→3.
31
+ - **Knowledge CAPTURED + PUSHED (2026-07-27):** 9 docs — Rate WH guard (draft→active), service-card Addresses.id ACL, aig-contract standard-field correction, api2 EZ-2 (`id` case), and 5 elevated standards/architecture (depth-starvation + `_Exception_Validation` in `2.0/standards/backend-php.md`; uncommitted-nested-write in `_underscore/architecture.md`; `_sandbox-dev` branch map + `Logs.Api` in the api2 deploy workflow; committed-PAT security note in `api2/architecture.md`).
31
32
 
32
33
  ## What did NOT work — DO NOT RETRY THESE
33
34
  <!-- Exact failure reasons — do not vague-ify -->
34
- - **Forcing the write host inside `persistWarrantyServiceAddress`** (commit `7b63955d`, removed in `dff1fb5e`): NO EFFECT. V2 already disables the read host for the whole create block (`V2.php:5024`) — the lookup was already on the writer.
35
- - **The 3-table JOIN lookup** (`Entitlement → Contacts.primaryContactAddressId → ContactAddresses → addressId`) in postPost: returns 0 rows *in-request* even on the writer; resolves only *post-commit*. Superseded by the payload approach.
36
- - **Payload-based `$address->id` on beta with `depth=-1`**: null — the shallow payload (`calcDepth 1`) has NO `contact.primaryContactAddress.address` node at all, so there's nothing to read. Code is correct; depth is the cause.
37
- - **Merging `_underscore` to `_beta` did NOT deploy to beta.** API-Sandbox-Dev EB pulls `_underscore` from **`_sandbox-dev`** via `api2/.platform/hooks/prebuild/git.sh` + `.ebextensions/git.sandbox-dev.json`.
38
- - **"Removed depth" curl test (earlier)**: the edited curl STILL had `depth=-1` (per logged `queryString`) — proved nothing.
39
- - **Single-host vs multi-host connection theory**: DISPROVEN — same beta instance both ways; the variable is the request `depth`, not topology.
35
+ - **Forcing the write host inside `persistWarrantyServiceAddress`** (commit `7b63955d`, removed in `dff1fb5e`): NO EFFECT — V2 already disables the read host for the whole create block (`V2.php:5024`).
36
+ - **The 3-table JOIN lookup** (`Entitlement → Contacts.primaryContactAddressId → ContactAddresses → addressId`) in postPost: returns 0 rows *in-request* even on the writer (resolves only post-commit). Superseded by the payload approach.
37
+ - **Payload-based `$address->id` while the FE sent `depth=-1`**: null — the shallow payload (`calcDepth 1`) has NO `contact.primaryContactAddress.address` node. Code was correct; depth was the cause.
38
+ - **Merging `_underscore` to `_beta`**: does NOT deploy to beta — API-Sandbox-Dev pulls `_underscore` from **`_sandbox-dev`** via `api2/.platform/hooks/prebuild/git.sh` + `.ebextensions/git.sandbox-dev.json`.
39
+ - **"Removed depth" curl test (earlier)**: the edited curl STILL had `depth=-1` in the logged query string — proved nothing.
40
+ - **Single-host vs multi-host connection theory**: DISPROVEN — same beta instance both ways; the variable was request `depth`.
41
+ - **Relying on `minDepth` to protect the interceptor**: it's set to 5 on the postPost row yet the payload still built at `calcDepth 1` for a `depth=-1` request — the clamp is a latent no-op (framework bug to ticket). The real fix was the FE dropping `depth`.
40
42
 
41
43
  ## Not tried yet (candidates for next session)
42
- - **PRIMARY (in flight):** Tanner removed `depth` from `checkoutApi.ts:21` on the front-end; the `toga2-view` change is **deploying to beta now**. Verify a fresh beta purchase pins (see Exact next step). This reproduces the proven-good ET100057 config.
43
- - **FALLBACK if the FE fix somehow doesn't take:** on beta `Client_Rate`, `UPDATE ApiPayloadInterceptors SET minDepth = 10 WHERE id = 2;`, fire a purchase, check whether `calcDepth` rises and it pins. (Open Q: does the `minDepth` clamp engage for the `-1` sentinel? It's 5 yet built at `calcDepth 1`.)
44
- - Merge `_underscore` `TRUE-79533` → `_sandbox-dev` + deploy (ships the `_Exception_Validation` 400 fix + full backend; pin itself is already on beta).
45
- - Merge `dbchanges2` `TRUE-79533` for prod parity (beta already has the migrations).
46
- - Run `/capture`.
47
- - File side tickets: (1) framework `minDepth`-clamp no-op for low/`-1` depth (starves ALL payload interceptors); (2) AIG contract block has the SAME `depth` starvation — silently skipped for beta-FE purchases; (3) SECURITY: plaintext GitHub PAT committed in `api2/.ebextensions/git.*.json` — rotate + move to env config.
44
+ - **Merge `_underscore` `TRUE-79533` → `_sandbox-dev` + deploy** — puts the `_Exception_Validation` 400-fix (`41a5dc1a`) on beta so Paulina's *blocked-purchase* testing (duplicate / unverifiable address) shows a clean 400 toaster instead of a 500 + stack trace. Do this before she hits those paths.
45
+ - **Merge `dbchanges2` `TRUE-79533`** to its deploy branch for prod parity (beta already has the migrations applied).
46
+ - **File the framework ticket:** `ApiPayloadInterceptors.minDepth` clamp does not deepen the built payload for a `depth=-1` request (WO-1 says "raised to 5" but `calcDepth` stays 1) — starves ANY payload interceptor. Plus: AIG contract block had the same starvation; and the committed GitHub PAT in `api2/.ebextensions/git.*.json` needs rotating + moving to SSM.
47
+ - Optionally credit Tanner as an `owners` on the FE-touching Rate doc once his kb-username is known.
48
48
 
49
49
  ## Current file state
50
50
  | File | Status | Notes |
51
51
  |------|--------|-------|
52
- | `_underscore/Model/Rate/Entitlement.php` | Committed on `TRUE-79533` (HEAD `41a5dc1a`) | payload pin (`dff1fb5e`) + dedup write-host + `_Exception_Validation` (`41a5dc1a`). Pin already on beta; the 400-fix is NOT (needs `_sandbox-dev` merge). |
52
+ | `toga2-view/src/pages/CheckOut/api/checkoutApi.ts` | **FIXED + deployed to beta (Tanner)** | dropped `{depth:-1}` → deep payload reaches `postPost`. THE unblocker; pin now works. |
53
+ | `_underscore/Model/Rate/Entitlement.php` | Committed on `TRUE-79533` (HEAD `41a5dc1a`) | payload pin (`dff1fb5e`, already on beta) + dedup write-host + `_Exception_Validation` (`41a5dc1a`, NOT yet on beta). |
53
54
  | `_underscore/Model/Client/Entitlement.php` | Committed | `serviceAddressId` standard FK (line 20). |
54
- | `dbchanges2/Client_Rate/2026-07-24a - AddressIdFieldPermission.sql` | Committed (`ea1e0fb`) | `Addresses.id` read ACL. Applied on beta. |
55
- | `dbchanges2` serviceAddressId col + `Core` field + ACL migrations | Committed on `TRUE-79533` | Applied on beta manually; branch needs merge for prod. |
56
- | `toga2-view/src/pages/CheckOut/api/checkoutApi.ts` | **Tanner removed `depth` — DEPLOYING to beta now** | Line 21 `{ 'depth': -1 }` dropped so `postPost` gets a deep payload. THE unblocker. |
57
- | `test/@Mark/Rate/verify_wholehome_per_address_guard.php` | Updated (personal, not in a repo) | `c_serviceAddressId` → `serviceAddressId`; documents the depth caveat. |
55
+ | `dbchanges2/Client_Rate/2026-07-24a - AddressIdFieldPermission.sql` | Committed (`ea1e0fb`) | Applied on beta. Needs branch merge for prod. |
56
+ | `dbchanges2` serviceAddressId col + `Core` field + ACL | Committed on `TRUE-79533` | Applied on beta manually; needs merge for prod. |
57
+ | team KB (`~/toga-tech/knowledge/…`) | **9 docs published to `_main` (capture)** | Rate WH guard active + 5 elevated standards/arch docs. |
58
+ | `test/@Mark/Rate/verify_wholehome_per_address_guard.php` | Updated (personal, not in a repo) | Not team knowledge. |
58
59
 
59
60
  ## Decisions made
60
- - **Fix depth on the FRONT-END (drop the `depth` param)** rather than bumping the interceptor `minDepth`. Rationale: it reproduces the already-proven ET100057 (no-depth) config that pinned on beta, needs no DB config change, and un-starves the AIG block for free. The `minDepth` bump remains the fallback / the proper systemic guardrail. (Rohan confirmed minDepth 3-default / 5 on postPost.)
61
- - **Pin from the in-memory hydrated payload, not a DB read-back** (in-request reads can't see uncommitted nested writes; `getFullModelData` hydrates the payload before `postPost`).
61
+ - **Fix depth on the FRONT-END (drop the `depth` param)** rather than bumping the interceptor `minDepth`. Rationale: reproduces the proven ET100057 no-depth config, no DB config change, and un-starves the AIG block too. Verified working on beta. `minDepth` bump remains the fallback / the systemic guardrail (whose clamp bug is now a separate ticket).
62
+ - **Pin from the in-memory hydrated payload, not a DB read-back** (in-request reads can't see the txn's own uncommitted nested writes).
62
63
  - **`serviceAddressId` = STANDARD field** (per Jeff), not `c_serviceAddressId`.
63
- - **Hard-blocks throw `_Exception_Validation`** → HTTP 400 + surfaced message (FE checkout expects 400).
64
+ - **Hard-blocks throw `_Exception_Validation`** → HTTP 400 + message (FE expects 400).
64
65
 
65
66
  ## Blockers
66
- - **Verification pending** — the front-end `depth` removal is mid-deploy to beta; can't confirm the pin until it lands and a fresh purchase is made.
67
- - The `_Exception_Validation` 400-fix (`41a5dc1a`) and the rest of `TRUE-79533` are on `TRUE-79533` but NOT yet on beta (beta deploys `_underscore` from `_sandbox-dev`). Does NOT block the pin test (the pin code is already on beta), but needs merging for the 400/toaster behavior + prod.
67
+ - **None blocking the pin** — it's verified working on beta.
68
+ - Soft/pending: the `_Exception_Validation` 400-fix (`41a5dc1a`) is not yet on beta (beta deploys `_underscore` from `_sandbox-dev`), so Paulina's blocked-purchase paths currently return 500 until the `_sandbox-dev` merge+deploy. Not a pin blocker.
68
69
 
69
70
  ## Exact next step
70
- > As soon as Tanner's `toga2-view` deploy lands, make ONE fresh WH purchase on beta and verify in the DB (MCP `dev-sandbox`, `Client_Rate`): the newest WH entitlement has `serviceAddressId` populated AND its `Addresses.isValidated = 1`, with NO manual backfill. Also confirm the create response no longer shows the `WO-1` depth warning (and `meta.calcDepth` is higher), and that AIG outbound calls resume in `Logs_Rate.Api`. If it pins → success; then merge `_underscore TRUE-79533` → `_sandbox-dev` (for the 400 fix), merge `dbchanges2`, and run `/capture`. If it still returns null → apply the FALLBACK (`UPDATE ApiPayloadInterceptors SET minDepth=10 WHERE id=2` on beta) and re-test.
71
+ > Merge `_underscore` `TRUE-79533` → `_sandbox-dev` and deploy API-Sandbox-Dev (prebuild hook re-clones `_sandbox-dev`), so the `_Exception_Validation` hard-block 400s reach beta before Paulina tests duplicate/invalid-address rejections. Then merge `dbchanges2` `TRUE-79533` for prod parity, and file the framework `minDepth`-clamp-no-op ticket (+ AIG-starvation + committed-PAT follow-ups). Verify a deliberate duplicate-address purchase on beta returns HTTP 400 with the toaster message (not 500).
71
72
 
72
73
  ---
73
74
  _Saved by /session-save on 2026-07-27_
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.442",
3
+ "version": "1.0.444",
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",