toga-ai 1.0.258 → 1.0.259
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.
|
@@ -14,40 +14,41 @@ updated: 2026-06-30
|
|
|
14
14
|
# Session: talos-pricing-platform
|
|
15
15
|
**Date:** 2026-06-30
|
|
16
16
|
**Project/Repo:** tools (1.0) + worker2 (2.0) + dbchanges2 (2.0 Team DB)
|
|
17
|
-
**Task:** Build a data-driven Talos pricing platform (Team-DB schema + tools onboarding/dashboard UI + worker2 cron automation) to replace the Excel calculator; then fix tools SSO login that was failing in production.
|
|
17
|
+
**Task:** Build a data-driven Talos pricing platform (Team-DB schema + tools onboarding/dashboard UI + worker2 cron automation) to replace the Excel calculator; then fix tools SSO login (both consumer and initiate legs) that was failing in production.
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
21
|
## What WORKED
|
|
22
|
-
- **Schema (Team DB):** `dbchanges2/Team/2026-06-29a - TalosPricingTables.sql` — 9 tables
|
|
23
|
-
- **worker2 automation:** `worker2/Worker/Talos/Pricing.php` (`_Worker_Talos_Pricing`) + `worker2/Database/TalosPricingCrons.sql` — `php -l` clean.
|
|
24
|
-
- **tools UI:** nav folder + 6 pages +
|
|
25
|
-
- **SSO 500 fix:** `tools/mvc/sso/get.php` `tools_ssoFail()` — added `if (!headers_sent())` guard around `http_response_code(401)`.
|
|
26
|
-
- **SSO key sourcing:** `tools/_/app/auth.php` `
|
|
27
|
-
- **Crypto format confirmed:** `App_String::encryptWithKey/decryptWithKey` (library/app/string.php:1075-1094) = AES-256-CBC, `base64(iv . base64ciphertext)`, interoperable with 2.0 `_String`. The
|
|
28
|
-
- **
|
|
22
|
+
- **Schema (Team DB):** `dbchanges2/Team/2026-06-29a - TalosPricingTables.sql` — 9 tables, SQL-reviewed (0 critical), all 7 important review fixes applied (dtUpdated on fact tables, DECIMAL(6,4) margins, isFeature* booleans, DECIMAL(14,8) calibration factors, column comments, band-range CHECK). `dbchanges2/Team/` is the Team-DB migration folder (unqualified table names).
|
|
23
|
+
- **worker2 automation:** `worker2/Worker/Talos/Pricing.php` (`_Worker_Talos_Pricing`) + `worker2/Database/TalosPricingCrons.sql` — `php -l` clean. 3 monthly crons: ImportAwsActuals (Cost Explorer), RecomputeMargins (calibration + margin/streak/recommendation), MonthlyReport (PhpSpreadsheet xlsx + EmailTemplate). initialize() registers Team DB via `_underscore::DB_TEAM`.
|
|
24
|
+
- **tools UI:** nav folder + 6 pages + `App_Talos_Estimator` + CSS, all `php -l` clean. Onboarding get/post (live JS estimate + recommended per-band fees), pricing dashboard, usage benchmarks, cost-factors get/post.
|
|
25
|
+
- **SSO 500 fix (consumer leg):** `tools/mvc/sso/get.php` `tools_ssoFail()` — added `if (!headers_sent())` guard around `http_response_code(401)`. Root cause: `App_FrameworkIndex::render()` flushes the preloader buffer (`page.php:213`) BEFORE `body()`/`loadFile()`, so headers are already sent when any mvc page runs.
|
|
26
|
+
- **SSO key sourcing → Core.Parameters (BOTH legs):** `tools/_/app/auth.php` — `decryptHandoffValue()` (consumer) reads keys via new cached `handoffKeys()`; added public `currentApiSecret()` for the initiate leg; `const CORE_DB='db_toga2core'`. `tools/mvc/sso/initiate/get.php` now passes `'apiSecretAccessToken' => App_Auth::currentApiSecret()`. Both `php -l` clean.
|
|
27
|
+
- **Crypto format confirmed:** `App_String::encryptWithKey/decryptWithKey` (library/app/string.php:1075-1094) = AES-256-CBC, `base64(iv . base64ciphertext)`, interoperable with 2.0 `_String`. The real `?saml=` payload decoded to exactly that shape — proving SSO failure was a key/config issue, not a format bug.
|
|
28
|
+
- **"Sign in failed" root cause found + fixed:** that banner is `login/get.php` `?error=1`, set ONLY by `sso/initiate/get.php:33,38` when `App_Sso::initiate()` throws. The initiate leg still read `api_secret_access_token` from config; after it was removed from config (per earlier wrong advice), `App_Sso::initiate()` (library/app/sso.php:64-65, empty() guard) threw InvalidArgumentException → `/login?error=1`. Fixed by sourcing the secret from Core.Parameters on the initiate leg too.
|
|
29
|
+
- **Knowledge captured + pushed (4 times):** pricing platform (6 docs incl. approved ELEVATED `2.0/apps/talos/architecture.md` section), SSO fixes (`saml-sso-auth.md` + `mvc-data-access-patterns.md`), and the SSO-initiate correction (`saml-sso-auth.md` again). All PUSHED to `_main`.
|
|
29
30
|
|
|
30
31
|
## What did NOT work — DO NOT RETRY THESE
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
- **
|
|
34
|
-
- **Calling `http_response_code()
|
|
35
|
-
- **Writing `[database_team]`/`[database_toga2core]`
|
|
32
|
+
- **Removing `api_secret_access_token` from `config.production.ini` `[saml]`** — broke SSO. The INITIATE leg (`sso/initiate/get.php`) reads it from config to encrypt the RelayState; empty → `App_Sso::initiate()` throws `InvalidArgumentException('...missing required parameter: apiSecretAccessToken')` → `/login?error=1` "Sign in failed". DO NOT keep the rotating secret in config; it now comes from Core.Parameters on both legs.
|
|
33
|
+
- **`App_Database::escape()`** does NOT exist — use `App_Database::sqlEscape()`.
|
|
34
|
+
- **Passing `App_Database::query(...)` inline to `buildArrayOfRows()`/`fetchOne()`** (both take `&$res`) — triggers PHP "Only variables should be passed by reference" (renders with display_errors on). Assign the query result to a variable first.
|
|
35
|
+
- **Calling `http_response_code()`/`header()`/`session_regenerate_id()` from a page loaded inside `body()`** — preloader buffer already flushed → fatals/no-ops. Guard with `headers_sent()`.
|
|
36
|
+
- **Writing `[database_team]`/`[database_toga2core]` with a guessed host** — avoided. The 2.0 Core/Team host is `production-core-cluster…us-west-2` (from config.alpha.ini `[database_prod_toga2core]`), distinct from the 1.0 prod-cluster and the 2.0 client cluster (`reader1.client.database.togahub.com` = db_true).
|
|
36
37
|
|
|
37
38
|
## Not tried yet (candidates for next session)
|
|
38
|
-
- Seeding/calibrating `TalosCostFactors` from
|
|
39
|
-
- Wiring
|
|
39
|
+
- Seeding/calibrating `TalosCostFactors` from real Langfuse aggregates (estimator ships placeholder DEFAULTS).
|
|
40
|
+
- Wiring xlsx as an email attachment — `_Email` attachment support unconfirmed (MonthlyReport writes xlsx to temp; email body has HTML table).
|
|
40
41
|
- Confirming the AWS Cost Explorer cost-allocation tag key (worker assumes `Client`).
|
|
41
|
-
- Creating the leadership `EmailTemplates` record in Client_True and replacing the placeholder `REPORT_EMAIL_TEMPLATE` UUID
|
|
42
|
-
-
|
|
42
|
+
- Creating the leadership `EmailTemplates` record in Client_True and replacing the placeholder `REPORT_EMAIL_TEMPLATE` UUID.
|
|
43
|
+
- Live end-to-end SSO verification after `[database_toga2core]` is configured + deployed.
|
|
43
44
|
|
|
44
45
|
## Current file state
|
|
45
46
|
| File | Status | Notes |
|
|
46
47
|
|------|--------|-------|
|
|
47
48
|
| dbchanges2/Team/2026-06-29a - TalosPricingTables.sql | created | 9 Talos* tables, reviewed+fixed. Apply to Team DB. |
|
|
48
|
-
| worker2/Worker/Talos/Pricing.php | created | `_Worker_Talos_Pricing`; lint clean. REPORT_EMAIL_TEMPLATE
|
|
49
|
+
| worker2/Worker/Talos/Pricing.php | created | `_Worker_Talos_Pricing`; lint clean. REPORT_EMAIL_TEMPLATE placeholder UUID. |
|
|
49
50
|
| worker2/Database/TalosPricingCrons.sql | created | 3 Core.CronJobs seeds (4th of month). Not yet inserted. |
|
|
50
|
-
| tools/_/app/nav.php | modified |
|
|
51
|
+
| tools/_/app/nav.php | modified | "Talos Pricing" folder (4 links; Cost Factors narrowed to technical personas). |
|
|
51
52
|
| tools/_/app/talos/estimator.php | created | `App_Talos_Estimator`; placeholder DEFAULT factors. |
|
|
52
53
|
| tools/mvc/talos/onboarding/get.php + post.php | created | Form + live estimate; writes TalosClients + TalosPricingBands in a txn. |
|
|
53
54
|
| tools/mvc/talos/pricing/get.php | created | Read-only margin/recommendation dashboard (db_team). |
|
|
@@ -55,21 +56,23 @@ updated: 2026-06-30
|
|
|
55
56
|
| tools/mvc/talos/factors/get.php + post.php | created | Technical-only cost-factor editor (upsert TalosCostFactors). |
|
|
56
57
|
| tools/assets/css/style.css | modified | Appended .pricing-table / .badge / form-grid / estimate-readout styles. |
|
|
57
58
|
| tools/mvc/sso/get.php | modified | headers_sent() guard in tools_ssoFail() (500→graceful 401). |
|
|
58
|
-
| tools/_/app/auth.php | modified | decryptHandoffValue()
|
|
59
|
+
| tools/_/app/auth.php | modified | decryptHandoffValue() + currentApiSecret() read tokens from Core.Parameters via db_toga2core; handoffKeys() cache; CORE_DB const. |
|
|
60
|
+
| tools/mvc/sso/initiate/get.php | modified | apiSecretAccessToken now from App_Auth::currentApiSecret() (Core.Parameters), not config. |
|
|
59
61
|
|
|
60
62
|
## Decisions made
|
|
61
|
-
- **Pricing model:** flat monthly ORG FEE (
|
|
62
|
-
- **Cost methodology:** calibrate Langfuse→AWS (monthly factor = AWS_actual / Langfuse_costCorrected; new clients use a global blended factor).
|
|
63
|
-
- **Table location:**
|
|
63
|
+
- **Pricing model:** flat monthly ORG FEE (adjustable margin lever) + per-user fee that STEPS by user-count band; band rate schedule locked at signing; on a band crossing the per-user fee auto-steps, THEN org fee is adjusted. Rejected: pure per-user banded; both-vary.
|
|
64
|
+
- **Cost methodology:** calibrate Langfuse→AWS (monthly factor = AWS_actual / Langfuse_costCorrected; new clients use a global blended factor). Always use cache-corrected Langfuse cost. Rejected: AWS-only; Langfuse-only.
|
|
65
|
+
- **Table location:** Team DB (`_underscore::DB_TEAM`). Tenant link to Core.Clients is a plain indexed column, NOT a hard FK (Team DB may be a separate instance).
|
|
64
66
|
- **Onboarding writes:** direct DB write from the 1.0 tools app (not via api2) for speed.
|
|
65
|
-
- **SSO
|
|
67
|
+
- **SSO secret source:** the rotating `API_SECRET_ACCESS_TOKEN` (+ `_PREVIOUS`) lives ONLY in `Core.Parameters`, read by BOTH SSO legs (initiate encrypts RelayState; consumer decrypts current→previous) via the `db_toga2core` connection. Config copies go stale on rotation and silently break SSO. `[saml] true_client_uuid` and the IdP URLs STAY in config. Rejected: config-stored tokens.
|
|
66
68
|
|
|
67
69
|
## Blockers
|
|
68
|
-
- **SSO login still fails until
|
|
69
|
-
-
|
|
70
|
+
- **SSO login still fails until `[database_toga2core]` is added to the tools configs AND tools is redeployed.** `App_Auth::CORE_DB='db_toga2core'` is referenced by both SSO legs, but no `[database_toga2core]` section exists in `config.production.ini` yet (developer handling creds). Template: hostname `production-core-cluster.cluster-clwbyqvxdm4q.us-west-2.rds.amazonaws.com`, username awsroot, dbname `Core`. DIAGNOSTIC: a **500 at initiate** = db_toga2core unconfigured (query against unregistered alias throws, uncaught); **/login?error=1** = empty/absent token in Core.Parameters.
|
|
71
|
+
- `Core.Parameters.API_SECRET_ACCESS_TOKEN` must be populated and match the gateway; `[saml] true_client_uuid` must remain in config (consumer leg sso/get.php:80-84 reads it).
|
|
72
|
+
- All Talos UI pages need the `[database_team]` connection (db_team → Team DB) before they render data.
|
|
70
73
|
|
|
71
74
|
## Exact next step
|
|
72
|
-
> Add
|
|
75
|
+
> Add `[database_toga2core]` (alias db_toga2core, dbname=Core, host=production-core-cluster…us-west-2) to `tools/config.production.ini` (and the dev configs you test with), confirm `Core.Parameters.API_SECRET_ACCESS_TOKEN` is set and `[saml] true_client_uuid` is still present, deploy tools, then click "Sign in with SSO" at https://tools.togatech.com — expect redirect to the IdP (not `/login?error=1`); a 500 at initiate means db_toga2core isn't wired.
|
|
73
76
|
|
|
74
77
|
---
|
|
75
78
|
_Saved by /session-save on 2026-06-30_
|
package/package.json
CHANGED