toga-ai 1.0.181 → 1.0.183

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,7 +5,7 @@
5
5
  | [Worker (1.0 Framework) Architecture](architecture.md) | `worker` is the legacy (**1.0** `App_` framework) **background-job tier**. | worker/index.php, worker/_/app/framework.php, worker/crons/, worker/schedules/, worker/ebs/cron.worker.php, worker/.ebextensions/035_cron.worker.config |
6
6
  | [Compass MA Sales Order Exception Report](features/compass-ma-sales-order-exception-report.md) | A worker cron that emails operations the "Compass Refresh Exception Report" — Compass `MA%` sales orders whose corresponding Office Depot (ODP) sales order has | worker/crons/toga2/compass/workflow/7_generate_ma_sales_order_exception_report.php |
7
7
  | [Compass Partial In-Transit & Delivered Emails (per package)](features/compass-partial-in-transit-delivered-emails.md) | Compass USA and Compass Canada send a **per-package** in-transit email (and a matching delivered email) instead of one email listing the whole order. | worker/crons/toga2/compass/update_salesorder_status_from_odp.php, worker/crons/toga2/compasscanada/workflow/3_update_salesorder_status_from_grand_and_toy.php |
8
- | [Forecast2 ↔ NetSuite Reconciliation & Trueup Tooling](features/forecast2-netsuite-reconciliation.md) | CLI tools to **audit** and **repair** drift between the production `Forecast` DB (core2) and NetSuite. | test/@dave/reconcile_netsuite_totals.php, test/@dave/analyze_netsuite_forecast_diff.php, test/@dave/trueup_sales.php, test/@dave/trueup_open_orders.php, test/@dave/trueup_opportunities.php, test/@dave/probe_sales_gap_direct.php, test/@dave/probe_missing_oo_timing.php, test/@dave/probe_missing_oo_createdby.php, test/@dave/probe_drift_so_dates.php, worker/crons/toga2/forecast2/common_import_sales_from_netsuite.php |
8
+ | [Forecast2 ↔ NetSuite Reconciliation & Trueup Tooling](features/forecast2-netsuite-reconciliation.md) | CLI tools to **audit** and **repair** drift between the production `Forecast` DB (core2) and NetSuite. | test/@dave/reconcile_netsuite_totals.php, test/@dave/analyze_netsuite_forecast_diff.php, test/@dave/trueup_sales.php, test/@dave/trueup_open_orders.php, test/@dave/trueup_opportunities.php, test/@dave/probe_sales_gap_direct.php, test/@dave/probe_missing_oo_timing.php, test/@dave/probe_missing_oo_createdby.php, test/@dave/probe_drift_so_dates.php, test/@dave/probe_profit_invoices.php, test/@dave/probe_profit_gap.php, worker/crons/toga2/forecast2/common_import_sales_from_netsuite.php |
9
9
  | [NetSuite → TOGa Supply Per-Client Sync (thin wrappers)](features/netsuite-togasupply-per-client-sync.md) | Syncs NetSuite transactions (sales orders, purchase orders, invoices, item receipts, item fulfillments, inventory adjustments) into each TOGa Supply (2.0) clien | worker/crons/toga2/netsuite/common_sync_togasupply.php, worker/crons/toga2/netsuite/sync_togasupply_canon.php, worker/schedules/cron.worker.sync.json, dbchanges2/_modules/netsuite/2026-04-01 - Parameters.sql |
10
10
  | [Prudential: Send Shipments for the Day report (daily cron)](features/send-shipments-for-the-day.md) | Daily cron (9:00 PM) that emails Prudential and Dell stakeholders an Excel report of all devices shipped that day, including tracking number, serial number, emp | worker/crons/notifications/reports/send_shipments_for_the_day.php |
11
11
  | [Onboarding a Client to the NetSuite TOGa Supply Sync](workflows/onboarding-client-to-netsuite-togasupply-sync.md) | How to add a new TOGa 2 client to the per-client NetSuite → TOGa Supply importer (`worker/crons/toga2/netsuite/`). | worker/crons/toga2/netsuite/sync_togasupply.php, worker/crons/toga2/netsuite/common_sync_togasupply.php, worker/schedules/cron.worker.sync.json, dbchanges2/_modules/netsuite/2026-04-01 - Parameters.sql |
@@ -6,7 +6,7 @@ project: Worker
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-06-23
9
+ updated: 2026-06-24
10
10
  owners: [dfranks]
11
11
  files:
12
12
  - test/@dave/reconcile_netsuite_totals.php
@@ -18,6 +18,8 @@ files:
18
18
  - test/@dave/probe_missing_oo_timing.php
19
19
  - test/@dave/probe_missing_oo_createdby.php
20
20
  - test/@dave/probe_drift_so_dates.php
21
+ - test/@dave/probe_profit_invoices.php
22
+ - test/@dave/probe_profit_gap.php
21
23
  - worker/crons/toga2/forecast2/common_import_sales_from_netsuite.php
22
24
  related:
23
25
  - ../architecture.md
@@ -35,9 +37,14 @@ by reconciling a chosen tranDate range directly against NetSuite.
35
37
 
36
38
  ## Key files / entry points
37
39
 
38
- - `reconcile_netsuite_totals.php [from] [to]` — category grand totals NS vs Forecast2 (Sales,
39
- Sales Profit, Open Orders, Opportunities) with deltas. Read-only. Connects explicitly to the
40
- **prod core2 reader**; NetSuite via SuiteQL SUMs.
40
+ - `reconcile_netsuite_totals.php [from] [to] [--verbose]` — category grand totals NS vs Forecast2
41
+ (Sales, Sales Profit, Open Orders, Opportunities) with deltas. Read-only. Connects explicitly to
42
+ the **prod core2 reader**; NetSuite via SuiteQL SUMs. `--verbose` additionally prints the
43
+ per-transaction presence diffs (Sales `salesPerTransactionDiff()` + Open Orders
44
+ `openOrderPerOrderDiff()`), each under a large `#`-banner heading with a date column in every
45
+ bucket. The diffs are **gated** because they materialize every transaction/order in the window
46
+ into PHP arrays and OOM on multi-year windows — default is summary-only; positional `[from] [to]`
47
+ work alongside the flag.
41
48
  - `analyze_netsuite_forecast_diff.php [from] [to]` — decomposes the delta **per transaction** into
42
49
  NS_ONLY (missing from FC), FC_ONLY (stale/extra), DRIFT (value differs). Read-only.
43
50
  - `trueup_sales.php --from --to [--chunk-days N] [--prod] [--dry-run]` — makes `Forecast.Sales`
@@ -49,6 +56,11 @@ by reconciling a chosen tranDate range directly against NetSuite.
49
56
  ~4,000 opps in ~13s to a $0 delta.
50
57
  - `probe_sales_gap_direct.php` / `probe_open_orders_gap.php` — read-only NS-vs-FC2 revenue
51
58
  breakdowns by type+month using **direct prod mysqli** (demonstrate the sandbox-dev bypass below).
59
+ - `probe_profit_gap.php` — read-only: attributes a Sales **profit** delta **by transaction type**
60
+ and measures the actual contribution of the `tl.iscogs='F'` filter (see the COGS gotcha below).
61
+ - `probe_profit_invoices.php` — read-only per-invoice profit localizer: lists drifted invoices
62
+ (`id` / `tranid` / `tranDate` / NS profit / FC profit / delta) over a tranDate window. Bootstraps
63
+ worker2's `_Component_Api_Netsuite` adapter + a direct prod core2 `Forecast` reader.
52
64
 
53
65
  ## How it works
54
66
 
@@ -88,6 +100,36 @@ None — Forecast2 is a single shared dataset.
88
100
 
89
101
  ## Gotchas / known issues
90
102
 
103
+ - **An audit must apply the sync's own inclusion rules or it manufactures phantom deltas.**
104
+ `reconcile`'s NetSuite Sales SUM/diff originally had **no transaction-status filter**, but the
105
+ sync (`trueup_sales` / `common_import_sales_from_netsuite.php`) deliberately **excludes** Invoice
106
+ *Voided*/*Rejected*, CashSale *"Unapproved Payment"*, and CreditMemo *Voided*. So the audit counted
107
+ rows the sync would never store → a **permanent phantom gap no true-up could ever close** (a single
108
+ Unapproved-Payment cash sale, $23.76, internalId 7184894, drove it). Fix: add a status filter
109
+ matching the sync to **both** Sales SUM queries and the per-transaction diff —
110
+ `BUILTIN.DF(t.status) NOT LIKE '%Unapproved Payment' / '%Voided' / '%Rejected'` (the display value
111
+ ends with the status name). Closed the revenue delta to `$0`. Generalize: when an audit reports a
112
+ delta no trueup closes, first check the audit applies the sync's exact inclusion filters.
113
+ - **Don't blame a profit delta on COGS lines without measuring it.** Adding `tl.iscogs='F'` to the
114
+ audit's profit SUM (to match the sync's line set) changed the profit number by **exactly $0.00** in
115
+ the tested window — COGS postings were **not** the cause of the profit gap. The filter is kept for
116
+ definitional consistency with the sync (which filters `iscogs='F'`), but it was not the fix.
117
+ `probe_profit_gap.php` measures the iscogs contribution directly so the next investigator doesn't
118
+ repeat the wrong hypothesis.
119
+ - **A Sales PROFIT-only gap (revenue matches, profit off) is a LINE-STRUCTURE mismatch, not value
120
+ drift — localize then window.** Production `Forecast.Sales` carries stale lines NetSuite no longer
121
+ returns *plus* is missing some, so the per-invoice profit SUM differs while revenue ties out.
122
+ `trueup_sales` surfaces this as **inserted>0 + deleted>0 with updated=0** (it reconciles by
123
+ `(type, txnId, lineNumber)`; a changed lineNumber is delete+insert, not update). **Key:**
124
+ `trueup_sales` *does* correct profit, but **only within its `--from/--to` tranDate window** — the
125
+ delta persists if the drifted transactions fall outside the window trued up. Diagnostic ladder:
126
+ (a) `reconcile` summary shows a profit delta with revenue at `$0`; (b) `probe_profit_gap.php`
127
+ attributes the delta to a transaction **type** (was 100% invoices); (c) `probe_profit_invoices.php`
128
+ lists the specific drifted invoices with tranDate; (d) run `trueup_sales --from/--to` over **that
129
+ exact window** with `--prod`. Resolved example: 23 invoices dated 2026-05-07/08 carried $1,277.37;
130
+ `trueup_sales --prod` over 2026-05-07..2026-05-08 applied 12 inserts + 35 deletes → `$0`. ⚠
131
+ `--prod` must be passed or trueup writes to the **laptop sandbox `db_forecast2`** (and that repoint
132
+ also drives which `Forecast.Items` lookup loads).
91
133
  - **NVL the cost in NS profit SUMs.** `reconcile`/`analyze` compute NS profit as
92
134
  `SUM(-foreignamount + NVL(costestimate,0))`. Without `NVL`, ShipItem lines (NULL cost) drop from
93
135
  the SUM and NS profit is understated, producing a **fake FC-over-NS "gap"** ($663K across 2025).
@@ -169,6 +211,13 @@ None — Forecast2 is a single shared dataset.
169
211
 
170
212
  ## Change history
171
213
 
214
+ - 2026-06-24 — **Sales audit correctness pass.** Fixed a phantom Sales delta: `reconcile`'s NS Sales
215
+ SUM/diff now applies the sync's status exclusions (Unapproved Payment / Voided / Rejected) so it can't
216
+ count rows the sync never stores (closed revenue delta to $0). Added a Sales per-transaction presence
217
+ diff and gated both diffs behind `--verbose` (they OOM on wide windows). Documented that a profit-only
218
+ gap is a line-structure mismatch fixed by `trueup_sales` **only within its tranDate window**
219
+ (localize-then-window ladder), and that `tl.iscogs='F'` contributed exactly $0.00 — COGS was not the
220
+ cause. Added `probe_profit_invoices.php` + `probe_profit_gap.php`. (dfranks)
172
221
  - 2026-06-23 — **Framed open-orders drift as three distinct categories** mapping to
173
222
  `trueup_open_orders`'s Insert/Update/Delete buckets — whole-order-missing (dominant by $),
174
223
  line-level value drift (largest by count), and stale FC rows (smallest) — correcting the common
@@ -6,7 +6,7 @@ project: Forwarder
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-06-23
9
+ updated: 2026-06-24
10
10
  owners: ["jcardinal"]
11
11
  files:
12
12
  - forward/design/index.php
@@ -83,9 +83,21 @@ auto-deploy ("live in a few minutes").
83
83
  regenerates the stub.
84
84
  - **Remove = unlist only** — sets a `hidden` flag in `project.json`; files are **never
85
85
  deleted** (explicit owner decision).
86
+ - **Edit version metadata** (`apiEditVersion`) — an "Edit" button on each version row opens
87
+ a modal pre-filled with the version's label, author ("your name"), and notes. Saving
88
+ commits an **updated `project.json` only** — the version id and the hosted `vN/index.html`
89
+ are unchanged, and the redirect stub does not depend on this metadata, so **no stub
90
+ rebuild**. Reuses the existing `isValidVersionId` guard and `postField` length caps (notes
91
+ cap 2000).
92
+ - **Copy URL** — a button on each project card copies the project's main live URL
93
+ (`https://demo.togatech.com/<project>`) to the clipboard via `navigator.clipboard`, with a
94
+ brief "Copied ✓" confirmation.
86
95
  - **Copy Claude Design prompt** — one-click copy of the standard self-contained-HTML export
87
96
  prompt (the same prompt documented in [static-demo-hosting](static-demo-hosting.md)).
88
97
 
98
+ The full action set is: `list`, `create-project`, `upload`, `adopt`, `set-latest`,
99
+ `toggle-version`, `edit-version`, `toggle-project` (plus `bootstrap`).
100
+
89
101
  ### Naming & validation
90
102
 
91
103
  - Folder names auto-normalized to **lowercase kebab-case**, validated against a kebab regex
@@ -141,6 +153,11 @@ None — internal/shared design-team tool.
141
153
  `/vN` versioning with a `project.json` manifest + auto-generated latest-pointer stub,
142
154
  adopt/unlist actions, `/design` route. Fixed the >1 MB Contents-API empty-content bug
143
155
  (raw media type) and the tracked-token leak (env/`.config.php`). (jcardinal)
156
+ - 2026-06-24 — Added **edit-version** (`apiEditVersion`): an Edit button + modal to revise a
157
+ version's label/author/notes, committing `project.json` only (no stub rebuild; reuses
158
+ `isValidVersionId` + length caps). Added a **Copy URL** button on each project card
159
+ (`navigator.clipboard` → `https://demo.togatech.com/<project>`). Both additive; no new
160
+ security surface. (jcardinal)
144
161
 
145
162
  ## Related docs
146
163
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.181",
3
+ "version": "1.0.183",
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",