toga-ai 1.0.447 → 1.0.449
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/INDEX.md +1 -0
- package/knowledge/2.0/apps/_underscore/features/database-alias-repointing.md +120 -0
- package/knowledge/2.0/apps/_underscore/features/per-client-database-connections.md +10 -1
- package/knowledge/2.0/apps/api2/features/cross-client-data-retrieval.md +11 -1
- package/knowledge/INDEX.md +1 -1
- package/knowledge/sessions/2026-07-27-true-79191-fulfill-ship-mhammontree.md +35 -38
- package/package.json +1 -1
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
| [Carrier Shipping Labels (UPS/FedEx) & NetSuite Item Fulfillment](features/carrier-shipping-labels.md) | Backend mechanics behind TOGa Supply's Fulfill & Ship: buying a carrier label (UPS/FedEx), persisting it, and creating the NetSuite Item Fulfillment with tracki | _underscore/Model/Client/ItemFulfillment.php, _underscore/Model/Client/TrackingNumber.php, _underscore/Model/Client/ItemFulfillments/TrackingNumber.php, _underscore/Component/Library/LabelPdf/LabelPdf.php, _underscore/Component/Library/Carriers/ShipmentRequest/ShipmentRequest.php, _underscore/Component/Library/Carriers/Ups/Ups.php, _underscore/Component/Library/Carriers/Fedex/Fedex.php, _underscore/Trait/Netsuite/ItemFulfillment.php, _underscore/Trait/Netsuite/SalesOrder.php, _underscore/Component/Library/NetSuite/NetSuite.php, _underscore/Model/Client/TrackingNumber.php, _underscore/Model/Client/ShippingMethod.php, _underscore/Model.php, _underscore/Cloud.php |
|
|
13
13
|
| [_Cloud S3 helpers (copy / get / delete / list)](features/cloud-s3-helpers.md) | `_Cloud` centralizes AWS SDK S3 usage for the 2.0 stack so the `S3Client` never leaks into workers or app code. | _underscore/Cloud.php |
|
|
14
14
|
| [_Component_*/_Model_* project-namespace registration (autoloader) & backslash-qualify traps](features/component-model-namespace-registration.md) | Every **project-local** `_Component_*` and `_Model_*` class in a 2.0 app **must declare the project namespace** at the top of the file: ```php namespace <NAMESP | _underscore/Loader.php, worker2/_.php, api2/_.php, worker2/Component/Forecast/Db/Db.php, worker2/Component/Forecast/SaleImport/SaleImport.php, api2/Component/Api/Netsuite/Netsuite.php |
|
|
15
|
+
| [Re-pointing a DB alias mid-request (_Database::register park/restore)](features/database-alias-repointing.md) | `_Database` keys **all live per-database runtime state by the connection ALIAS** (`Client` / `_underscore::DB_CLIENT`, `ClientLogs`, `Archive`), **not** by the | _underscore/Database.php, _underscore/Query.php, api2/Component/Api/V2/V2.php, api2/Component/Api/CrossClient/CrossClient.php |
|
|
15
16
|
| [Client Email Template Sending](features/email-template-sending.md) | `_Model_Client_EmailTemplate` sends a stored, client-defined email template by UUID. | _underscore/Model/Client/EmailTemplate.php, _underscore/Model/Client/EmailTemplateOutgoingEmailAddress.php, _underscore/Email.php |
|
|
16
17
|
| [Error Reporting — Issue/Event Aggregation (agreed POST-to-receiver design)](features/error-reporting-issue-event.md) | Platform-wide error-reporting infrastructure for TOGA 2.0, built around a two-table **Issue / Event** aggregation model in the shared **Core Logs DB**. | _underscore/Error.php, _underscore/Model/Core/Logs/Issue.php, _underscore/Model/Core/Logs/Event.php, dbchanges2/Logs/2026-07-06 - Issue and Event tables.sql |
|
|
17
18
|
| [Record-Changed Event Publishing (_Event::publish to SQS)](features/event-publish-sqs.md) | `_Event::publish()` (in `_underscore/Event.php`) is the PHP side of the real-time event pipeline. | _underscore/Event.php |
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Re-pointing a DB alias mid-request (_Database::register park/restore)
|
|
3
|
+
framework: "2.0"
|
|
4
|
+
repo: _underscore
|
|
5
|
+
project: _Underscore
|
|
6
|
+
client: shared
|
|
7
|
+
type: feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-07-27
|
|
10
|
+
owners: ["jcardinal"]
|
|
11
|
+
files:
|
|
12
|
+
- _underscore/Database.php
|
|
13
|
+
- _underscore/Query.php
|
|
14
|
+
- api2/Component/Api/V2/V2.php
|
|
15
|
+
- api2/Component/Api/CrossClient/CrossClient.php
|
|
16
|
+
related:
|
|
17
|
+
- ./per-client-database-connections.md
|
|
18
|
+
- ../../api2/features/cross-client-data-retrieval.md
|
|
19
|
+
- ../architecture.md
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Summary
|
|
23
|
+
|
|
24
|
+
`_Database` keys **all live per-database runtime state by the connection ALIAS**
|
|
25
|
+
(`Client` / `_underscore::DB_CLIENT`, `ClientLogs`, `Archive`), **not** by the physical schema
|
|
26
|
+
name. Four statics are alias-keyed: `$_connections`, `$_queryCache`, `$_transactionStarts`,
|
|
27
|
+
`$_modelCache`.
|
|
28
|
+
|
|
29
|
+
Historically `_Database::register()` only rewrote `$_registers[$alias]`. It never touched
|
|
30
|
+
`$_connections`, and `getConnection()` returns an already-cached link if one exists under that
|
|
31
|
+
key. So **re-registering an alias changed the credentials but not the open mysqli link** — every
|
|
32
|
+
query after a mid-request client switch silently ran against the *previous* client's database.
|
|
33
|
+
`register()` now **parks and restores** the alias-keyed live state when an alias is re-pointed at a
|
|
34
|
+
different physical database, which makes mid-request client switching actually work.
|
|
35
|
+
|
|
36
|
+
## Key files / entry points
|
|
37
|
+
|
|
38
|
+
- **`_underscore/Database.php`** — `register()` (park/restore), `registerClientDatabases()`
|
|
39
|
+
(per-client alias registration + Core host lookup), `getConnection()`,
|
|
40
|
+
`transactionCommit()` / `transactionRollback()` / `resolveParkedTransactions()`.
|
|
41
|
+
- **`api2/Component/Api/V2/V2.php`** — a call site that switches the `Client` alias mid-request.
|
|
42
|
+
- **`api2/Component/Api/CrossClient/CrossClient.php`** (~lines 193, 201, 207) — the cross-client
|
|
43
|
+
fan-out uses the same `registerClientDatabases()` + `_underscore::DB_CLIENT` pattern.
|
|
44
|
+
|
|
45
|
+
## How it works
|
|
46
|
+
|
|
47
|
+
Two new statics on `_Database`:
|
|
48
|
+
|
|
49
|
+
- `public static $_aliases` — alias => the physical database name currently behind it.
|
|
50
|
+
- `private static $_parked` — physical database name => that database's parked live state
|
|
51
|
+
(connection, queryCache, transactionStart, modelCache).
|
|
52
|
+
|
|
53
|
+
On `register()`:
|
|
54
|
+
|
|
55
|
+
1. If the alias is being pointed at the **same** physical database, this is a **no-op** for live
|
|
56
|
+
state. (This also fixes a latent bug where a redundant `register()` reset an already-begun
|
|
57
|
+
transaction flag from `true` back to `false`.)
|
|
58
|
+
2. If it is being pointed at a **different** database, the **outgoing** database's connection,
|
|
59
|
+
queryCache, transactionStart and modelCache are parked under its own physical name, and the
|
|
60
|
+
alias slots are cleared.
|
|
61
|
+
3. The **incoming** database's previously-parked state is restored if present — so an open
|
|
62
|
+
transaction on that database continues uninterrupted. If nothing is parked for it,
|
|
63
|
+
`transactionStart()` is armed as before.
|
|
64
|
+
|
|
65
|
+
`registerClientDatabases()` caches only the **Core host-lookup row** per clientId
|
|
66
|
+
(`static $cachedLookups`), and always runs the three `register()` calls. It **throws** when the
|
|
67
|
+
Core host lookup returns no row.
|
|
68
|
+
|
|
69
|
+
**Request boundary.** `transactionCommit(null)` / `transactionRollback(null)` iterate
|
|
70
|
+
`$_connections`, which is alias-keyed, so a parked database would be skipped and left with an open
|
|
71
|
+
transaction on a pooled connection. The null-branch of both now calls private
|
|
72
|
+
`resolveParkedTransactions(bool $isCommit)`, which sweeps `$_parked` for any entry with
|
|
73
|
+
`transactionStart === true`, commits or rolls it back, and marks it resolved so a later
|
|
74
|
+
switch-back cannot double-commit.
|
|
75
|
+
|
|
76
|
+
## Key rules
|
|
77
|
+
|
|
78
|
+
- **Re-registering an alias does not, by itself, reconnect.** Any code that changes credentials
|
|
79
|
+
under an existing alias must go through `register()`'s park/restore path.
|
|
80
|
+
- **Any change that hides a connection from `$_connections` must also resolve its transaction at
|
|
81
|
+
the request boundary** — otherwise the transaction leaks onto a pooled connection.
|
|
82
|
+
- **Client-DB config that cannot be resolved must throw, not fall through.** Falling through leaves
|
|
83
|
+
the aliases pointed at the previous client, which reads as "wrong data," not "an error."
|
|
84
|
+
|
|
85
|
+
## Design tradeoff (deliberate)
|
|
86
|
+
|
|
87
|
+
Park/restore was chosen over re-keying all four caches by **physical database name**, which would
|
|
88
|
+
have touched `Database.php`, `Query.php` and `Model.php`. Park/restore is contained to one function
|
|
89
|
+
and keeps every existing call site working unchanged. It is correct **only while every access to
|
|
90
|
+
those four caches goes through the alias** — nothing accesses them by physical name today. If that
|
|
91
|
+
ever changes, the re-keying approach becomes the right fix.
|
|
92
|
+
|
|
93
|
+
## Gotchas / known issues
|
|
94
|
+
|
|
95
|
+
- **The original symptom is silent, not an error.** A cross-client user lookup aimed at
|
|
96
|
+
`Client_Compass` returned **0 rows** because it actually ran against `Client_True` (the home
|
|
97
|
+
client). Wrong-database bugs here look like missing data.
|
|
98
|
+
- **The old `static $cached` guard in `registerClientDatabases()` made switch-back a no-op.** It was
|
|
99
|
+
keyed on clientId (commented as an "efficiency patch so we don't re-register and break
|
|
100
|
+
connections") and skipped the entire registration block for any client already seen in the
|
|
101
|
+
request — so the common "switch to B, then switch back to A" pattern never re-registered A.
|
|
102
|
+
Replaced by `$cachedLookups`, which caches only the Core lookup.
|
|
103
|
+
- **`CrossClient.php` had the same latent bug** and needed no edit — the `Database.php` fix corrects
|
|
104
|
+
its cross-client reads in place.
|
|
105
|
+
- **Not yet runtime-tested** as of this capture: `php -l` passes and php-reviewer cleared the diff,
|
|
106
|
+
but no live cross-client run has confirmed it.
|
|
107
|
+
|
|
108
|
+
## Change history
|
|
109
|
+
|
|
110
|
+
- 2026-07-27 — Initial capture. Root-caused a cross-client API bug to alias-keyed live state in
|
|
111
|
+
`_Database`: re-registering an alias never swapped the open mysqli link, so post-switch queries
|
|
112
|
+
hit the previous client's DB. Added `$_aliases`/`$_parked` park/restore in `register()`,
|
|
113
|
+
`resolveParkedTransactions()` on the null-branch of commit/rollback (parked transactions were
|
|
114
|
+
invisible to the request boundary), a throw when the Core host lookup returns no row, and
|
|
115
|
+
replaced the `static $cached` no-op guard with `$cachedLookups`. (jcardinal)
|
|
116
|
+
|
|
117
|
+
## Related docs
|
|
118
|
+
|
|
119
|
+
- [Per-Client Database Connections & the Local Logs Trap](./per-client-database-connections.md)
|
|
120
|
+
- [Multi-Client (Cross-Client) Data Retrieval](../../api2/features/cross-client-data-retrieval.md)
|
|
@@ -6,7 +6,7 @@ project: _Underscore
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-07-
|
|
9
|
+
updated: 2026-07-27
|
|
10
10
|
owners: ["dfranks", "jcardinal", "mhammontree", "apeterson", "kyalamarthi"]
|
|
11
11
|
files:
|
|
12
12
|
- _underscore/Database.php
|
|
@@ -16,6 +16,7 @@ files:
|
|
|
16
16
|
related:
|
|
17
17
|
- ../architecture.md
|
|
18
18
|
- ../workflows/local-db-refresh-from-beta.md
|
|
19
|
+
- ./database-alias-repointing.md
|
|
19
20
|
---
|
|
20
21
|
|
|
21
22
|
## Summary
|
|
@@ -118,12 +119,20 @@ here — they live in `Config/*.ini`.)
|
|
|
118
119
|
A connect failure here threw past `api()` and got masked by `Route.php` as the misleading line-525
|
|
119
120
|
"Failed to determine how to render view" error — see the Route.php swallow→mask gotcha in
|
|
120
121
|
[_underscore architecture](../architecture.md#gotchas--known-issues).
|
|
122
|
+
- **These aliases key ALL live connection state — re-registering one does not reconnect.**
|
|
123
|
+
`$_connections`, `$_queryCache`, `$_transactionStarts` and `$_modelCache` are keyed by the
|
|
124
|
+
alias (`Client`, `ClientLogs`, `Archive`), not by the physical schema, so switching a client
|
|
125
|
+
mid-request needs `_Database::register()`'s park/restore path. See
|
|
126
|
+
[Re-pointing a DB alias mid-request](./database-alias-repointing.md).
|
|
121
127
|
- Related 1.0 analogue: the legacy `App_` worker has the same hazard writing to `Logs.API`
|
|
122
128
|
(`db_logs`) — the laptop trap there is documented separately in the worker NetSuite bootstrap
|
|
123
129
|
notes.
|
|
124
130
|
|
|
125
131
|
## Change history
|
|
126
132
|
|
|
133
|
+
- 2026-07-27 — Recorded that the three per-client aliases key **all** live connection state, so
|
|
134
|
+
re-pointing an alias mid-request does not reconnect on its own; split the detail into
|
|
135
|
+
[Re-pointing a DB alias mid-request](./database-alias-repointing.md). (jcardinal)
|
|
127
136
|
- 2026-07-23 — Documented that the **`Team` schema** (`Tasks`/`Sprints`, `_Model_Team_*`,
|
|
128
137
|
`DB_TEAM`) is not a first-class api2 DB (not in `Records.aclDatabase`, which is CORE/CLIENT
|
|
129
138
|
only) and physically resolves to the **core cluster** (reads → `reader1.core…`, writes →
|
|
@@ -6,7 +6,7 @@ project: API
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: draft
|
|
9
|
-
updated: 2026-07-
|
|
9
|
+
updated: 2026-07-27
|
|
10
10
|
owners: [jcardinal]
|
|
11
11
|
files:
|
|
12
12
|
- api2/Component/Api/CrossClient/CrossClient.php
|
|
@@ -21,6 +21,7 @@ related:
|
|
|
21
21
|
- ./encrypted-user-uuid-auth-handoff.md
|
|
22
22
|
- ../../_underscore/features/per-client-database-connections.md
|
|
23
23
|
- ../../_underscore/features/acl-permission-chain.md
|
|
24
|
+
- ../../_underscore/features/database-alias-repointing.md
|
|
24
25
|
---
|
|
25
26
|
|
|
26
27
|
## What it is
|
|
@@ -111,10 +112,19 @@ for how it sits among the shared/per-client clusters.
|
|
|
111
112
|
emits `(object)$outRow`.
|
|
112
113
|
- **The X-Cross-Client / X-Cross-User custom-header transport was a dead stub** — the V2 engine
|
|
113
114
|
never reads such headers. The real transport is the two-phase encrypted-UUID auth handshake.
|
|
115
|
+
- **Switching the `Client` DB alias mid-request used to silently not switch.** `CrossClient.php`
|
|
116
|
+
(~lines 193/201/207) uses `_Database::registerClientDatabases()` + `_underscore::DB_CLIENT`, and
|
|
117
|
+
`_Database` keys its live connection state by **alias**, not physical schema — so cross-client
|
|
118
|
+
reads were executing against the *home* client's DB and returning 0 rows. Fixed in
|
|
119
|
+
`_underscore/Database.php` (no api2 edit needed); see
|
|
120
|
+
[Re-pointing a DB alias mid-request](../../_underscore/features/database-alias-repointing.md).
|
|
114
121
|
- **`curl_multi` busy-spin guard** — both multi loops `usleep(100)` when
|
|
115
122
|
`curl_multi_select() === -1`.
|
|
116
123
|
|
|
117
124
|
## Change history
|
|
125
|
+
- 2026-07-27 — Root-caused cross-client reads hitting the home client's DB: `_Database` keys live
|
|
126
|
+
connection state by alias, so re-registering `DB_CLIENT` never swapped the open link. Fixed in
|
|
127
|
+
`_underscore/Database.php`; CrossClient needed no edit. (jcardinal)
|
|
118
128
|
- 2026-07-07 — Initial capture: scatter-gather cross-client retrieval engine (orchestrator, watermark
|
|
119
129
|
k-way merge, keyset pagination Phase 0a/0b, `client`-option delegation, Cache cluster id 145).
|
|
120
130
|
Code-complete + reviewer-hardened, not yet runtime-tested. (jcardinal)
|
package/knowledge/INDEX.md
CHANGED
|
@@ -17,7 +17,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
17
17
|
|
|
18
18
|
## 2.0 framework
|
|
19
19
|
|
|
20
|
-
- **_underscore** (_Underscore) _(framework core)_ —
|
|
20
|
+
- **_underscore** (_Underscore) _(framework core)_ — 39 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
|
|
21
21
|
- **worker2** (Worker) — 31 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
|
|
22
22
|
- **api2** (API) — 17 doc(s) → [2.0/apps/api2/INDEX.md](2.0/apps/api2/INDEX.md)
|
|
23
23
|
- **dbchanges2** (Database Changes) _(framework core)_ — 3 doc(s) → [2.0/apps/dbchanges2/INDEX.md](2.0/apps/dbchanges2/INDEX.md)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
type: session
|
|
3
3
|
slug: true-79191-fulfill-ship
|
|
4
|
-
title: TRUE-79191 Fulfill & Ship —
|
|
4
|
+
title: TRUE-79191 Fulfill & Ship — Units of Measure shipped + verified, CodeRabbit review cleared, PRs up
|
|
5
5
|
author: mhammontree
|
|
6
6
|
repos: [dbchanges2, _underscore, api2, toga2-supply]
|
|
7
7
|
framework: "2.0"
|
|
@@ -14,61 +14,58 @@ updated: 2026-07-27
|
|
|
14
14
|
# Session: true-79191-fulfill-ship
|
|
15
15
|
**Date:** 2026-07-27
|
|
16
16
|
**Project/Repo:** toga2-supply (2.0) + _underscore / api2 / dbchanges2
|
|
17
|
-
**Task:**
|
|
17
|
+
**Task:** Ship package Units-of-Measure full-stack for Fulfill & Ship, verify save/retrieve, clear the CodeRabbit review, and get PRs up for deploy.
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
21
|
## What WORKED
|
|
22
|
-
|
|
23
|
-
- **
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
- **
|
|
30
|
-
- **
|
|
31
|
-
- **End-to-end save/retrieve VERIFIED in DB:** new tracking number **9676** (SO 7221433 / NetSuite, created 2026-07-27 12:06) has `lengthMeasureId=1` (inch) / `weightMeasureId=2` (pound) — populated by the **frontend create payload** (proves real persistence: column defaults NULL, and the 07-22 backfill predates this row).
|
|
32
|
-
- **Local-env fixes** (see failures section for why these were NOT our code): `pcre.jit=0` in php.ini; `Items.isFulfillable` column added to all 11 local client DBs.
|
|
33
|
-
- Deployment doc `C:\WWW\TRUE-79191_deployment_order.md` updated with all 4 UoM migrations + notes.
|
|
22
|
+
- **Package UoM full-stack — DONE, verified end-to-end.** `Measures.measureType` (ENUM LENGTH/WEIGHT) + `conversionFactorToBase`; seeded Inch/Pound (base, factor 1); `TrackingNumbers.lengthMeasureId`/`weightMeasureId` (+ hard FKs); backfill; Core RecordFields 2436-2438; Client ACL grants. `_underscore` Measure/TrackingNumber model fields. api2 = no code (metadata-driven). toga2-supply: two RHF selects fed by `GET /v2/measures` split by `measureType`; FK written as nested relation `{uuid}` (mirrors shippingCarrier).
|
|
23
|
+
- **Verified in DB:** new tracking number 9676 (SO 7221433, created 2026-07-27) persisted `lengthMeasureId=1`/`weightMeasureId=2` from the frontend save (new row, post-backfill, columns default NULL → proves real save). Reopen rehydrates correctly.
|
|
24
|
+
- **Empty-dropdowns bug FIXED:** `GET /v2/measures` omitted `measureType` because the field had no `AclFieldPermissions` grant — the V2 engine builds the GET output field list from AclFieldPermissions, so ungranted = omitted (READ, not just write). Granted `measureType` read by mirroring sibling `slug` per-client (dbchanges2 22c). Applied to all local clients; commit `ceeb95d`.
|
|
25
|
+
- **CodeRabbit review cleared — 3 batches, all committed, tsc clean each time:**
|
|
26
|
+
- Batch 1 (`d1eba64af`, 10 findings): BasicTable stopPropagation; ShipmentItemsTable pure updater; EditShipmentForm editContext guard + edit-mode validation; updateShipment null-safe derefs + step-identifying failures; ReturnShippingModal spans→buttons; SelectReturnAddressModal radio semantics + radiogroup; dedup field id; stale-comment removals.
|
|
27
|
+
- Batch 2 (`ba611989a`): `validateFormOnSubmit`/`checkDimensions` now RETURN a fresh boolean; caller branches on it (not the stale RHF `errors` snapshot) so the FIRST submit is blocked on invalid fields.
|
|
28
|
+
- Batch 3 (`e0942cb4f`): `checkDimensions` now clears errors when all L/W/H present (previously no all-present branch → a flagged dimension never cleared → permanent submit block).
|
|
29
|
+
- **Local env unblocked earlier:** `pcre.jit=0` (JIT/Sentry bootstrap 500-every-route); `Items.isFulfillable` column added to all local client DBs (model pulled ahead of local schema).
|
|
30
|
+
- **Deployment order doc updated** (`C:\WWW\TRUE-79191_deployment_order.md`) with the 4 UoM migrations + notes. **PRs are up.**
|
|
34
31
|
|
|
35
32
|
## What did NOT work — DO NOT RETRY THESE
|
|
36
|
-
- **
|
|
37
|
-
- **
|
|
38
|
-
-
|
|
39
|
-
- **
|
|
40
|
-
- `
|
|
33
|
+
- **Assuming read-only fields need no ACL grant** — WRONG. V2 builds GET output from `AclFieldPermissions`; a field with no grant row for the caller's role is silently omitted from the response (not just blocked on write). measureType needed a read grant. See `_underscore/features/acl-permission-chain.md`.
|
|
34
|
+
- **Mirroring `needsReturnLabel` for measure-field write grants** — its grants aren't present in every client (Client_True had none) → measure fields ungranted there → EV-9. Mirror **`shippingMethodId`** (stable/universal).
|
|
35
|
+
- **Branching on the RHF `errors` snapshot right after `setError`** — it lags one render, so the first submit slips through. Validation helpers must RETURN a fresh result and the caller must branch on that. Also the helper must `clearErrors` on the valid path or stale errors block submit forever.
|
|
36
|
+
- **Chasing the sales-orders 500 as feature code** — it was `pcre.jit` (bootstrap) then `Items.isFulfillable` missing column (local DB behind on migrations). Not our code.
|
|
37
|
+
- **Re-running `Client/2026-07-22b` after go-live** — one-time backfill; a re-run coerces later NULL rows to Inch/Pound.
|
|
41
38
|
|
|
42
39
|
## Not tried yet (candidates for next session)
|
|
43
|
-
- **Deploy** TRUE-79191 (deployment
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
-
|
|
40
|
+
- **Deploy** TRUE-79191 (DB → backend → frontend per the deployment doc). Before prod DB step: verify `MAX(Core.RecordFields.id)=2435` (else bump the 2436-2438 ids in `Core/2026-07-22a`); `composer install` api2 (FPDF) + prod carrier config; flag the unrelated `isFulfillable` migration `id=2434` collision to its owner.
|
|
41
|
+
- Monitor CodeRabbit for further findings on the updated diff.
|
|
42
|
+
- Seed cm/kg into a client (metric, per-client) to exercise the multi-option dropdown.
|
|
43
|
+
- Full local DB migration catch-up / reset from beta (drift scan: 16 genuine missing columns in unrelated tables; none block fulfill/ship).
|
|
44
|
+
- Weight symbol on Pending Shipments cards is static `"lbs."` (TODO — dynamic from weightMeasure.symbol).
|
|
45
|
+
- The submit caller still keeps `|| actualErrors.length > 0` (RHF snapshot) as a secondary guard covering create-mode serial errors from `formatShipmentData` (which doesn't return a hasErrors signal). If CodeRabbit flags it, give `formatShipmentData` a return value and drop the snapshot OR.
|
|
48
46
|
|
|
49
47
|
## Current file state
|
|
50
48
|
| File | Status | Notes |
|
|
51
49
|
|------|--------|-------|
|
|
52
|
-
|
|
|
53
|
-
|
|
|
54
|
-
|
|
|
55
|
-
| api2 | no changes | metadata-driven
|
|
56
|
-
| C:\WWW\TRUE-79191_deployment_order.md | updated (external) | UoM migrations + notes
|
|
57
|
-
| Local
|
|
50
|
+
| toga2-supply | committed + PR up | commits: e91f7029d (UoM UI), d1eba64af (CR batch 1), ba611989a (CR batch 2), e0942cb4f (CR batch 3). .env/.env.development/package-lock intentionally uncommitted |
|
|
51
|
+
| dbchanges2 | committed + PR up | UoM 4 files incl. 22c measureType read grant (ceeb95d) |
|
|
52
|
+
| _underscore | committed + PR up | Measure/TrackingNumber UoM model fields (77fae34c) |
|
|
53
|
+
| api2 | no changes | metadata-driven |
|
|
54
|
+
| C:\WWW\TRUE-79191_deployment_order.md | updated (external) | UoM migrations + notes |
|
|
55
|
+
| Local DBs | migrated (local only) | all clients: UoM + isFulfillable; Core_2 RecordFields 2436-2438 + measureType; php.ini pcre.jit=0 |
|
|
58
56
|
|
|
59
57
|
## Decisions made
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
-
|
|
64
|
-
-
|
|
65
|
-
- **isFulfillable: add column only locally**, skip RecordField (its migration hardcodes `id=2434`, colliding with returnAddressId `2026-07-10a` also 2434 — flag to that feature's owner).
|
|
58
|
+
- Columns `lengthMeasureId`/`weightMeasureId` (volume dropped); reuse Measures + `measureType` enum, zero new tables; base Inch/Pound; hard FK constraints.
|
|
59
|
+
- Mirror `shippingMethodId` for write grants, `slug` for measureType read grant (per-client role adaptation).
|
|
60
|
+
- FIELD_CHAR for measureType (matches signatureType).
|
|
61
|
+
- RHF validation: helpers RETURN a fresh boolean; caller branches on it; helpers clear on the valid path.
|
|
62
|
+
- pcre.jit=0 and isFulfillable column are LOCAL env fixes only (not shipped).
|
|
66
63
|
|
|
67
64
|
## Blockers
|
|
68
|
-
None
|
|
65
|
+
None. Ready to deploy. Verify prod `MAX(Core.RecordFields.id)=2435` before running `Core/2026-07-22a`.
|
|
69
66
|
|
|
70
67
|
## Exact next step
|
|
71
|
-
> Deploy TRUE-79191 per `C:\WWW\TRUE-79191_deployment_order.md` (
|
|
68
|
+
> Deploy TRUE-79191 per `C:\WWW\TRUE-79191_deployment_order.md` (DB → backend → frontend), after confirming prod `MAX(Core.RecordFields.id)=2435`, running api2 `composer install`, and applying prod carrier config. Keep monitoring CodeRabbit on the PRs and address any new findings the same way (verify → minimal fix → tsc → commit).
|
|
72
69
|
|
|
73
70
|
---
|
|
74
71
|
_Saved by /session-save on 2026-07-27_
|
package/package.json
CHANGED