toga-ai 1.0.368 → 1.0.369

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.
@@ -8,5 +8,5 @@
8
8
  | [Rate SAML SSO](features/saml-sso.md) | 2.0 | Rate uses Azure AD as its IdP (`login.rate.com`). | _underscore/Model/Rate/ClientAuthentication.php, saml/Controller/Index.php, toga2-view/src/hooks/useAuthenticationFlow.ts |
9
9
  | [Service Card Entitlement Display](features/service-card-entitlements.md) | 2.0 | Rate's home and services pages display one service card per purchased entitlement. | src/components/ServiceCard/ServiceCard.tsx, src/components/ServiceCard/index.ts, src/hooks/useBundleServices.ts, src/pages/Home/api/homeApi.ts, src/pages/Home/view/HomePage.tsx, src/pages/Home/viewModels/useHomePageViewModel.ts, src/pages/Services/view/ServicesPage.tsx, src/pages/Services/viewModels/useServicePageViewModel.ts |
10
10
  | [Rate Service-Purchase Confirmation Emails (Tech / Warranty)](features/service-purchase-emails.md) | 2.0 | When a Rate customer purchases a service, a confirmation email is sent. | _underscore/Model/Rate/Entitlement.php, worker2/Worker/Notification/EmailTemplate.php, dbchanges2/Client_Rate/2026-06-30a - Rate purchase email templates.sql |
11
- | [Rate Whole Home Warranty Per-Address Purchase Guard](features/whole-home-warranty-purchase-guard.md) | 2.0 | A customer may hold **one active Whole Home Warranty (WH) per validated address, globally** (across all borrowers). | _underscore/Model/Rate/Entitlement.php, _underscore/Model/Client/Address.php, dbchanges2/Client_Rate/2026-07-07a - WholeHomeWarrantyPerAddressGuard.sql, test/@Mark/Rate/verify_wholehome_per_address_guard.php |
11
+ | [Rate Whole Home Warranty Per-Address Purchase Guard](features/whole-home-warranty-purchase-guard.md) | 2.0 | > **⚠ NOT IN PRODUCTION (as of 2026-07-17).** TRUE-79533 is **not** merged to `_production`. | _underscore/Model/Rate/Entitlement.php, _underscore/Model/Client/Address.php, dbchanges2/Client_Rate/2026-07-07a - WholeHomeWarrantyPerAddressGuard.sql, test/@Mark/Rate/verify_wholehome_per_address_guard.php |
12
12
  | [Rate](profile.md) | 2.0 | Rate is a mortgage/lending client. | |
@@ -6,7 +6,7 @@ project: _Underscore
6
6
  client: rate
7
7
  type: client-feature
8
8
  status: active
9
- updated: 2026-06-30
9
+ updated: 2026-07-17
10
10
  owners: [mhammontree]
11
11
  files:
12
12
  - _underscore/Model/Rate/Entitlement.php
@@ -118,6 +118,15 @@ Email web-font reality: Gmail/Outlook strip web fonts and fall back; Apple Mail/
118
118
 
119
119
  ## Gotchas / known issues
120
120
 
121
+ - **Shared interceptor with TRUE-79533 (WH per-address guard) — same `prePost`/`postPost`.** This
122
+ workflow's `postPost` trigger + helpers live in the **same** `_Model_Rate_Entitlement`
123
+ interceptors that the [Whole Home Warranty per-address guard](whole-home-warranty-purchase-guard.md)
124
+ edits, and TRUE-79251 also adds the passThrough `const PASSTHROUGH_KEY_FULFILLMENT_PREFERENCE` +
125
+ the contractFulfillmentPreference (EV-8) fix inside `prePost`. A bad `_production`→`_beta` merge
126
+ already mis-resolved this once and fatally broke every Rate purchase save. When merging either
127
+ ticket across branches, hand-merge into ONE `prePost()` keeping both features' logic — see the
128
+ **shared-interceptor merge hazard** gotcha on that doc for the correct resolution and why `php -l`
129
+ is not a sufficient gate.
121
130
  - **`border-radius` on a `<td>` renders SQUARE in many clients (Outlook).** Use an `<img>` for
122
131
  circular badges/icons (e.g. the green circle-check) instead of a CSS-rounded table cell.
123
132
  - **ASCII-only subjects (mojibake workaround).** `_Email::send()` does not set PHPMailer
@@ -150,6 +159,9 @@ Remaining items are **optional / separate, not go-live blockers**:
150
159
 
151
160
  ## Change history
152
161
 
162
+ - 2026-07-17 — Added a cross-reference to the [WH per-address guard](whole-home-warranty-purchase-guard.md):
163
+ both tickets edit the same `_Model_Rate_Entitlement` `prePost`/`postPost` interceptors, a
164
+ shared-interceptor merge hazard that already broke `_beta` once. No behavior change here. (mhammontree)
153
165
  - 2026-06-30 — Built the Rate service-purchase confirmation email workflow (TRUE-79251):
154
166
  `postPost` trigger + helpers in `_Model_Rate_Entitlement`, two DB-stored `Client_Rate`
155
167
  templates (tech / warranty) dispatched off-thread via
@@ -5,8 +5,8 @@ repo: _underscore
5
5
  project: _Underscore
6
6
  client: rate
7
7
  type: client-feature
8
- status: active
9
- updated: 2026-07-08
8
+ status: draft
9
+ updated: 2026-07-17
10
10
  owners: [mhammontree]
11
11
  files:
12
12
  - _underscore/Model/Rate/Entitlement.php
@@ -19,6 +19,13 @@ related:
19
19
  - ../../../2.0/apps/_underscore/features/address-validation.md
20
20
  ---
21
21
 
22
+ > **⚠ NOT IN PRODUCTION (as of 2026-07-17).** TRUE-79533 is **not** merged to `_production`.
23
+ > Its `_underscore` + `dbchanges2` PRs are still OPEN / "BACK-END REVIEW" (git-verified: commit
24
+ > `be5002f4` is contained only in branches `TRUE-79533` and `_beta`, never `_production`). An
25
+ > earlier belief that it "shipped weeks ago" is incorrect — TRUE-79251 (purchase emails) shipped,
26
+ > this guard did not. The branch is being caught up to `_production` now. See the
27
+ > **shared-interceptor merge hazard** gotcha below before merging.
28
+
22
29
  ## Summary
23
30
 
24
31
  A customer may hold **one active Whole Home Warranty (WH) per validated address, globally**
@@ -127,6 +134,36 @@ live carrier waterfall is opt-in via `RUN_LIVE=1` (defaults off). Verified **18/
127
134
 
128
135
  ## Gotchas / known issues
129
136
 
137
+ - **Shared-interceptor merge hazard — TRUE-79533 and TRUE-79251 edit the SAME methods.** Both
138
+ this guard and the [purchase-email workflow](service-purchase-emails.md) (TRUE-79251) modify the
139
+ **same** `prePost`/`postPost` interceptors on `_Model_Rate_Entitlement`, and TRUE-79251 also adds
140
+ the passThrough `const PASSTHROUGH_KEY_FULFILLMENT_PREFERENCE` + the contractFulfillmentPreference
141
+ (EV-8) fix inside `prePost`. This makes the file a merge landmine:
142
+ - **What already went wrong (on `_beta`):** a later `Merge branch '_production' into _beta`
143
+ mis-resolved the conflict — it reverted `prePost` to production's version and **deleted** the
144
+ private helpers `isWholeHomeWarranty()`, `normalizedField()`, `hasActiveWarrantyAtAddress()`,
145
+ while leaving the caller `persistWarrantyServiceAddress()` (a separate hunk). Result:
146
+ `postPost` → `persistWarrantyServiceAddress()` → `self::isWholeHomeWarranty()` = fatal
147
+ `Error: Call to undefined method`, thrown **before** the method's own try/catch (so it is NOT
148
+ swallowed). This breaks the entitlement save for **every** Rate purchase (tech + warranty).
149
+ Because the crash happens **after** `sendPurchaseEmail()` was enqueued and the record saved, the
150
+ symptom is: record created + email sent, yet the API returns an error → user retries →
151
+ **duplicate entitlements / emails / AIG contracts**.
152
+ - **Correct conflict resolution is NEITHER side alone, and NOT "accept both".** The conflict is a
153
+ single block where HEAD (TRUE-79533) defines the WH-guard `prePost()` + 3 helpers and
154
+ `_production` defines the passThrough `prePost()` + `PASSTHROUGH_KEY_FULFILLMENT_PREFERENCE`.
155
+ Both sides define `prePost()`. accept-HEAD drops the constant (→ undefined-constant fatal in
156
+ `postPost`, and regresses the EV-8 contractFulfillment fix); accept-theirs reproduces the
157
+ `isWholeHomeWarranty` undefined-method crash; accept-both yields a fatal duplicate `prePost()`
158
+ redeclare. **Hand-merge into ONE `prePost()`** that (1) strips `contractFulfillmentPreference`
159
+ → `$api->passThrough` for every purchase, then (2) runs the WH guard for warranty purchases —
160
+ keeping the constant AND all three private helpers. The common `postPost` below the conflict
161
+ references **both** symbols (the constant at the AIG-contract build, and `isWholeHomeWarranty()`
162
+ in `persistWarrantyServiceAddress`), so both must survive.
163
+ - **`php -l` is NOT a sufficient gate here.** Lint passes on the broken accept-HEAD state — the
164
+ two failures (undefined class constant, EV-8 regression) are runtime, not syntax. Verify with
165
+ `test/@Mark/Rate/verify_wholehome_per_address_guard.php` (18/18 against `Client_Rate`,
166
+ carrier calls off).
130
167
  - **TOCTOU on the uniqueness check (accepted).** The check-then-persist dedup is **not**
131
168
  lock-guarded. Two truly concurrent same-address WH purchases could both pass. Accepted for
132
169
  sequential purchases; documented in code.
@@ -143,6 +180,13 @@ live carrier waterfall is opt-in via `RUN_LIVE=1` (defaults off). Verified **18/
143
180
 
144
181
  ## Change history
145
182
 
183
+ - 2026-07-17 — **Status corrected to `draft` / not-in-production** (TRUE-79533): git-verified the
184
+ guard was never merged to `_production` (PRs open / back-end review), contrary to a belief it had
185
+ shipped. Documented the **shared-interceptor merge hazard** with TRUE-79251 and the correct
186
+ hand-merge of the dual `prePost()` — a bad `_production`→`_beta` merge had deleted the WH helpers
187
+ (`isWholeHomeWarranty()` et al.) while keeping the caller, fatally breaking every Rate purchase
188
+ save and causing duplicate entitlements/emails/AIG contracts. Resolved the catch-up merge;
189
+ `php -l` clean and 18/18 verify against `Client_Rate`. (mhammontree)
146
190
  - 2026-07-08 — Added a backend verification script
147
191
  (`test/@Mark/Rate/verify_wholehome_per_address_guard.php`, 18/18 pass against the migrated
148
192
  `Client_Rate` schema) and a Verification pointer. (mhammontree)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.368",
3
+ "version": "1.0.369",
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",