toga-ai 1.0.289 → 1.0.290

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,9 +5,12 @@ project: _Underscore
5
5
  client: shared
6
6
  type: standard
7
7
  status: active
8
- updated: 2026-07-02
8
+ updated: 2026-07-08
9
9
  owners: [mhammontree]
10
- files: []
10
+ files:
11
+ - _underscore/Query.php
12
+ - _underscore/Database.php
13
+ - _underscore/Environment.php
11
14
  related:
12
15
  - ../apps/_underscore/architecture.md
13
16
  - ../apps/_underscore/features/per-client-database-connections.md
@@ -27,12 +30,22 @@ From a 2.0 app root (e.g. `worker2`): `chdir` into the app, require Composer aut
27
30
  `_underscore.php`, and set `ENVIRONMENT` before bootstrap:
28
31
 
29
32
  ```php
33
+ putenv('ENVIRONMENT=dev-markhammontree-laptop'); // REQUIRED, before requiring _underscore.php
34
+ // e.g. dev-<yourname>-laptop — matches your Config/<ENVIRONMENT>.ini
30
35
  chdir('/path/to/worker2');
31
36
  require 'vendor/autoload.php';
32
37
  require '_underscore.php'; // boots Loader/Config/etc.
33
- // ENVIRONMENT must be set (env var / server) so _Config picks the right INI
34
38
  ```
35
39
 
40
+ - **`ENVIRONMENT` is mandatory.** The bootstrap uses it to select `worker2/Config/<ENVIRONMENT>.ini`.
41
+ If it is unset, `_underscore.php` throws *"The environment variable 'ENVIRONMENT' is required and
42
+ has not been set"* (`_underscore/Environment.php:12`). Set it via `putenv(...)` in the script
43
+ before the `require`, or export it in the shell.
44
+ - **On Windows the shell is PowerShell** — set env vars as `$env:VAR='x'; php script.php`, **not**
45
+ the bash `VAR=x php script.php` prefix. The bash-style prefix silently does nothing in
46
+ PowerShell, so the script falls back to its defaults (a confusing "it ran but used the wrong
47
+ config" failure).
48
+
36
49
  ## You MUST pin the client DB explicitly
37
50
 
38
51
  `_underscore::DB_CLIENT` is a **logical alias**, not a schema name — there is no database literally
@@ -51,8 +64,41 @@ Without this, any `Model/Client/*` query resolves the unmapped alias and fails.
51
64
  schema you have locally/on the target env (internal testing uses `Client_True` = TOGA Technology).
52
65
  Remember the per-client **logs** connection trap too (see the per-client-database-connections doc).
53
66
 
67
+ ## Commit before you read your own writes (lazy-transaction trap)
68
+
69
+ Standalone scripts run under `_underscore`'s **lazy-transaction model with a separate read
70
+ connection**, so a write is invisible to a later read — and to the code under test — until it is
71
+ committed. Concretely:
72
+
73
+ - `_Database::register(..., alias: _underscore::DB_CLIENT)` sets up a pending transaction for that
74
+ DB. The **first** write (via `_Query`) flips autocommit **OFF** and opens the transaction
75
+ (`_underscore/Query.php` ~303–304, keyed by the database value passed to `_Query`).
76
+ - INSERTs therefore sit **uncommitted**. A subsequent `SELECT` on the read connection returns
77
+ nothing, so a read-back-by-marker returns `null` and dependent FK inserts fail (classic symptom:
78
+ `saleItemId = 0` FK violation).
79
+
80
+ **Pattern:** after seeding base rows, call
81
+ `_Database::transactionCommit(_underscore::DB_CLIENT)` (`_underscore/Database.php` ~165–212). This
82
+ commits **and** restores `autocommit(true)`, so all later writes — and reads of them — behave
83
+ normally. Order your script:
84
+
85
+ 1. seed base rows →
86
+ 2. **commit** →
87
+ 3. read ids back →
88
+ 4. insert dependent rows →
89
+ 5. assert →
90
+ 6. cleanup — and **commit the cleanup too**, so the `DELETE`s persist rather than being rolled
91
+ back when the script exits.
92
+
93
+ This is the same lazy-transaction write-drop family noted in the `_underscore` architecture doc;
94
+ it bites the standalone-script/verification case specifically. Demonstrated working in
95
+ `test/@Mark/Rate/verify_wholehome_per_address_guard.php`.
96
+
54
97
  ## Rules
55
98
 
56
99
  - Do not add or assume a PHPUnit suite for 2.0 backend work; write a `test`-repo script instead.
100
+ - Always set `ENVIRONMENT` before bootstrap (PowerShell: `$env:ENVIRONMENT='...'`, or `putenv`).
57
101
  - Always pin the concrete `Client_<Id>` schema to `DB_CLIENT` (and logs/archive if the code logs).
102
+ - **Commit seeded rows before you read them back** — the read connection cannot see uncommitted
103
+ writes; commit cleanup too so it persists.
58
104
  - Keep scripts in your per-dev `test` folder; never point them at production databases.
@@ -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 |
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 |
12
12
  | [Rate](profile.md) | 2.0 | Rate is a mortgage/lending client. | |
@@ -6,12 +6,13 @@ project: _Underscore
6
6
  client: rate
7
7
  type: client-feature
8
8
  status: active
9
- updated: 2026-07-07
9
+ updated: 2026-07-08
10
10
  owners: [mhammontree]
11
11
  files:
12
12
  - _underscore/Model/Rate/Entitlement.php
13
13
  - _underscore/Model/Client/Address.php
14
14
  - dbchanges2/Client_Rate/2026-07-07a - WholeHomeWarrantyPerAddressGuard.sql
15
+ - test/@Mark/Rate/verify_wholehome_per_address_guard.php
15
16
  related:
16
17
  - clients/rate/profile.md
17
18
  - clients/rate/features/aig-contract-creation.md
@@ -113,6 +114,17 @@ suggested-vs-entered when `success && address1`, and a "couldn't verify" toaster
113
114
  [address-validation feature](../../../2.0/apps/_underscore/features/address-validation.md) for the
114
115
  endpoint mechanics.
115
116
 
117
+ ## Verification
118
+
119
+ A self-contained backend verification script lives at
120
+ `test/@Mark/Rate/verify_wholehome_per_address_guard.php` (run via PHP CLI with `ENVIRONMENT`
121
+ set, pinned to the real migrated **`Client_Rate`** schema — see the
122
+ [2.0 backend-testing standard](../../../2.0/standards/backend-testing.md)). It applies
123
+ `c_serviceAddressId` idempotently, seeds a token-tagged scratch WH graph (2 addresses / 2 items /
124
+ 2 active subscriptions / 2 entitlements), then exercises the pure helpers, the dedup matrix (via
125
+ reflection on the private methods), and the `prePost` branches, cleaning up in a `finally`. The
126
+ live carrier waterfall is opt-in via `RUN_LIVE=1` (defaults off). Verified **18/18 pass**.
127
+
116
128
  ## Gotchas / known issues
117
129
 
118
130
  - **TOCTOU on the uniqueness check (accepted).** The check-then-persist dedup is **not**
@@ -131,6 +143,9 @@ endpoint mechanics.
131
143
 
132
144
  ## Change history
133
145
 
146
+ - 2026-07-08 — Added a backend verification script
147
+ (`test/@Mark/Rate/verify_wholehome_per_address_guard.php`, 18/18 pass against the migrated
148
+ `Client_Rate` schema) and a Verification pointer. (mhammontree)
134
149
  - 2026-07-07 — Built the WH per-address purchase guard (TRUE-79533): `prePost` on
135
150
  `_Model_Rate_Entitlement` hard-blocks invalid addresses and second active WH at the same
136
151
  normalized address (global), adopts the carrier-normalized address onto the payload, and
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.289",
3
+ "version": "1.0.290",
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",