toga-ai 1.0.140 → 1.0.142
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.
|
@@ -100,6 +100,26 @@ None — uniform (platform-wide Forecast2 sync).
|
|
|
100
100
|
handler sees them). NB: `App_ApiTransaction::execute(false)` returns a raw JSON **string** for a record
|
|
101
101
|
GET — `json_decode` it directly; double-encoding it (`json_decode(json_encode($resp))`) silently yields
|
|
102
102
|
an empty object and a false "empty record" reading.
|
|
103
|
+
- **REST `item.items` sublist has read-after-write LAG → partial or empty syncs that freeze (this is the deeper root of the gotcha above).** The handler builds `OpenOrderItems` from the REST record GET's
|
|
104
|
+
`item.items` sublist, and that sublist **trails the committed record for seconds after edits** — it can
|
|
105
|
+
return *fewer lines than the order actually has*. Because `syncOpenLines` reconciles to exactly what it
|
|
106
|
+
read (upsert + delete-not-returned), a lagged read commits a **partial** line set (N of M) or an **empty**
|
|
107
|
+
one (0 of 1), and it **freezes there** — no later webhook fires to correct it, so the only repair is a
|
|
108
|
+
re-sync/trueup. **Confirmed live 2026-06-18 on SO 7170669** (tranId 279851): 14 PUT jobs ran **strictly
|
|
109
|
+
sequentially on one instance, in order** (`dtStarted`/`instanceId` proven — *not* concurrent, *not*
|
|
110
|
+
out-of-order); the **last** (authoritative) read at 18:03:49 committed **4 lines**, while the order has
|
|
111
|
+
**15** ($4,634 of $8,714 — short $4,080). A later REST GET returned all 15 (the sublist had caught up),
|
|
112
|
+
and SuiteQL `transactionline` showed 15 throughout. SO 7152319 is the 0-of-1 form. **Ruled OUT:**
|
|
113
|
+
concurrency/ordering (jobs were serial on one instance) and enqueue/drain (jobs all `isSuccess=1`) — so
|
|
114
|
+
"trust the current REST state" fails specifically because the REST *sublist isn't reliably current*.
|
|
115
|
+
**Fix direction (not yet implemented):** source the open lines from **SuiteQL `transactionline`** (which
|
|
116
|
+
was consistent exactly when the REST sublist lagged — same query `probe_open_order_lines.php` uses)
|
|
117
|
+
rather than the REST `expandSubResources` sublist; *or* re-read until the line count is stable before
|
|
118
|
+
committing. A `lastModifiedDate` freshness/ordering guard does **NOT** help — it isn't an ordering bug.
|
|
119
|
+
The fix **must stay real-time** — do **not** defer to the 15-min cron (see the AMQ real-time constraint /
|
|
120
|
+
`project_amq_realtime_requirement` in dev memory). Diagnose with `probe_open_order_lines.php` (SuiteQL vs
|
|
121
|
+
Forecast) + `probe_so_rest_lines.php` (live REST sublist count) + the `WorkerJobs` `dtStarted`/`instanceId`
|
|
122
|
+
timing (to confirm serial-vs-concurrent before blaming ordering).
|
|
103
123
|
- **REST shape ≠ SOAP shape.** The cron reads the SOAP-shim shape; this handler reads the REST record
|
|
104
124
|
(`status->refName`, line `quantityBilled`, `class->refName`, `entity->id`, `salesRep->id`,
|
|
105
125
|
`shippingCost`). Verified against live orders via `test/@dave/probe_salesorder_rest_shape.php`.
|
|
@@ -154,6 +174,15 @@ and are a candidate to extract into a shared `_Component_Forecast_Db` before the
|
|
|
154
174
|
|
|
155
175
|
## Change history
|
|
156
176
|
|
|
177
|
+
- 2026-06-18 — **Root-caused the open-order delta to REST `item.items` read-after-write lag** (not the
|
|
178
|
+
drainer/enqueue fixes, not ordering). SO 7170669 committed 4 of 15 open lines despite 14 *strictly
|
|
179
|
+
sequential, single-instance, in-order* PUTs — the last authoritative read returned a lagged partial
|
|
180
|
+
sublist; REST later caught up to 15 and SuiteQL showed 15 throughout. Disproved the earlier
|
|
181
|
+
out-of-order/concurrency hypothesis (verified via `WorkerJobs.dtStarted`/`instanceId`) and a
|
|
182
|
+
`lastModified` ordering guard (irrelevant — reads were in order). Fix direction recorded: source open
|
|
183
|
+
lines from **SuiteQL `transactionline`** instead of the REST sublist (or re-read until line count is
|
|
184
|
+
stable), keeping the path real-time (no cron deferral). New diagnostic: cross-check
|
|
185
|
+
`probe_open_order_lines.php` (SuiteQL) vs `probe_so_rest_lines.php` (REST sublist). (dfranks)
|
|
157
186
|
- 2026-06-18 — **Verified live in production** after the SalesOrder enqueuer left Testing. 14 orders
|
|
158
187
|
reconciled against NetSuite SuiteQL (`probe_open_order_lines.php`); 13 at $0.00 delta. Found one
|
|
159
188
|
miss — SO 7151688 (open, ~$20.31, 0 rows) — traced to the **async-recalc race** above (see new
|
|
@@ -115,6 +115,16 @@ process is identical for all.
|
|
|
115
115
|
no-op), then updates `s3Key` + `dtMeeting`. Run `dryRun:true` first, inspect `sample[]`, then
|
|
116
116
|
`dryRun:false` (optional `limit` for a first batch). `$limit` caps candidates touched, not
|
|
117
117
|
rows scanned, so a run of failures stops at `$limit` instead of sweeping the table.
|
|
118
|
+
**`Backfill()` recomputes the WHOLE key, not just the date.** Rows written by an earlier
|
|
119
|
+
`buildS3Key` produce a different `shortId`/time even when the date was already right, so a
|
|
120
|
+
full table run flags every row (the 2026-06-18 run moved 61/66 for this reason) and renames
|
|
121
|
+
those files. Acceptable as a one-off — the ledger `s3Key` is updated to match — but if you
|
|
122
|
+
ever need a minimal re-file, change the move test to compare only the `YYYY-MM-DD` folder
|
|
123
|
+
segment and relocate while preserving the original filename.
|
|
124
|
+
- **Cron rows cannot be `DELETE`d once they have fired.** `Core.WorkerJobs.cronJobId` has a FK
|
|
125
|
+
(`WorkerJobs_CronJobs_FK`) to `CronJobs.id`, so a schedule change must `UPDATE` an existing
|
|
126
|
+
row (and set `isActive = 0` on the ones being retired), not delete-and-reinsert. The historical
|
|
127
|
+
`WorkerJobs` rows are preserved.
|
|
118
128
|
|
|
119
129
|
- **`getAllTranscripts` requires an AAD object-id (GUID), NOT a UPN.** Passing a UPN
|
|
120
130
|
(e.g. `ajean@togatech.com`) returns the opaque `HTTP 400 BadRequest / "UnknownError"`.
|
|
@@ -154,8 +164,10 @@ Policy gap; a `400` only on a UPN means the id was never resolved to a GUID. (A
|
|
|
154
164
|
|
|
155
165
|
- 2026-06-18 — Fixed recurring-meeting date misfiling: archive date + `dtMeeting` now come from
|
|
156
166
|
the transcript `createdDateTime`, not the series-anchor `meeting->startDateTime` (worker2 PR
|
|
157
|
-
#82). Added `Backfill()`
|
|
158
|
-
Rescheduled to weekdays 9:30–17:30 CT
|
|
167
|
+
#82, merged + deployed). Added `Backfill()` and ran it in prod (61/66 objects re-filed, 0
|
|
168
|
+
errors). `dtExported` → `UTC_TIMESTAMP()`. Rescheduled to weekdays 9:30–17:30 CT via a single
|
|
169
|
+
consolidated cron row, applied by UPDATE+deactivate (DELETE blocked by the WorkerJobs FK) —
|
|
170
|
+
dbchanges2 PR #398, merged + applied. (ajean)
|
|
159
171
|
- 2026-06-12 — **Merged (PR #78) and verified in production**: a real `Team/Transcripts/Export`
|
|
160
172
|
run returned 6/6 organizers, 33 found, 33 exported, 0 errors (classified 30 general / 3 Elite).
|
|
161
173
|
Added fail-fast on unresolvable organizers (`resolveUserId` → null, loop throws clear error
|
package/package.json
CHANGED