toga-ai 1.0.507 → 1.0.508

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.
@@ -9,9 +9,9 @@
9
9
  | [Tools — Developers Folder (UUID & Password Generators)](features/developer-tools.md) | The first two tools shipped in the Tools app, both under the **Developers** folder and gated to personas **Development Team** / **TOGa Technology**. | tools/mvc/developers/uuid/get.php, tools/mvc/developers/password/get.php |
10
10
  | [/errors Curation Console (Tools → shared Core Logs DB)](features/errors-curation-console.md) | Internal-only triage/curation screen for the 2.0 Issue/Event error-reporting pipeline, built as a 1.0 Tools MVC page reading the **shared Core Logs DB** through | tools/mvc/errors/get.php, tools/mvc/errors/post.php, tools/mvc/errors/issue/get.php, tools/assets/css/style.css, tools/_/app/nav.php, tools/config.production.ini |
11
11
  | [Legacy Email Notifier (tools /email-migration/notify)](features/legacy-email-notifier.md) | An SSO-gated admin tool at **`/email-migration/notify`** (nav group **Email Migration** > **Legacy Notifier**, personas `['TOGa Technology','Development Team']` | tools/mvc/email-migration/notify/get.php, tools/mvc/email-migration/notify/post.php, tools/_/app/nav.php |
12
- | [Tools MVC — Routing, CSRF & App_Database Access Patterns](features/mvc-data-access-patterns.md) | The load-bearing 1.0 (`App_`) framework conventions a developer needs when adding a page to the Tools app — URL routing, CSRF, and DB access through `App_Databa | tools/_/app/nav.php, tools/mvc/get.php, library/app/error.php |
12
+ | [Tools MVC — Routing, CSRF & App_Database Access Patterns](features/mvc-data-access-patterns.md) | The load-bearing 1.0 (`App_`) framework conventions a developer needs when adding a page to the Tools app — URL routing, CSRF, and DB access through `App_Databa | tools/_/app/nav.php, tools/mvc/get.php, library/app/error.php, library/app/database.php |
13
13
  | [Tools Persona-Gated Navigation (App_Nav)](features/persona-gated-navigation.md) | `App_Nav` is the Tools app's two-level, **persona-gated** navigation. | tools/_/app/nav.php, tools/mvc/get.php |
14
14
  | [Tools SAML SSO Consumer & Persona-Gated Auth (App_Auth)](features/saml-sso-auth.md) | `App_Auth` is the Tools app's authentication layer: it consumes the SAML gateway `?saml=` handoff (see the 2.0 SAML downstream integration contract), establishe | tools/_/app/auth.php, tools/mvc/sso/initiate/get.php, tools/mvc/sso/get.php, tools/mvc/login/get.php, tools/mvc/login/post.php, tools/mvc/logout/get.php, tools/mvc/get.php, tools/config.production.ini, tools/config.local.ini |
15
15
  | [Talos Knowledge Base Admin UI (KB Documents + Vocabulary)](features/talos-kb-documents-admin.md) | > **PER-AI-MODEL, DATA-DRIVEN SCOPING (2026-07-29).** The KB-documents and Vocabulary admin > UIs were refactored from a single hard-coded **"development-team"* | tools/mvc/talos/kb-documents/get.php, tools/mvc/talos/kb-documents/post.php, tools/mvc/talos/knowledge-bases/get.php, tools/mvc/talos/knowledge-bases/post.php, tools/mvc/talos/vocabulary/get.php, tools/mvc/talos/vocabulary/post.php, tools/_/app/talos/s3.php, tools/_/app/talos/bedrock.php, tools/_/app/pg.php, tools/_/app/model/true/aimodels.php, tools/_/app/model/true/vectorindexes.php, tools/_/app/model/true/aimodels_vectorindexes.php, tools/_/app/worker.php, tools/_/app/nav.php, tools/config.production.ini, tools/config.alpha.ini, tools/.platform/httpd/conf.d/timeouts.conf, tools/.platform/hooks/prebuild/01-install-php-pgsql.sh, tools/.platform/hooks/postdeploy/01-restart-php.sh |
16
- | [Talos Pricing UI (Onboarding, Dashboard, Benchmarks, Cost Factors + Estimator)](features/talos-pricing-ui.md) | The 1.0 (tools app) face of the **Talos Pricing Platform** — a "Talos Pricing" nav folder with four pages plus a client-side estimate engine. | tools/_/app/nav.php, tools/_/app/talos/estimator.php, tools/mvc/talos/onboarding/get.php, tools/mvc/talos/onboarding/post.php, tools/mvc/talos/pricing/get.php, tools/mvc/talos/benchmarks/get.php, tools/mvc/talos/factors/get.php, tools/mvc/talos/factors/post.php, tools/assets/css/style.css |
16
+ | [Talos Pricing UI (Contracts, Pricing Dashboard, Usage, Settings + Estimator)](features/talos-pricing-ui.md) | The 1.0 (tools app) face of the **Talos Pricing Platform** — a "Talos Pricing" nav folder with four pages plus the estimate engine. | tools/_/app/nav.php, tools/_/app/talos/estimator.php, tools/_/app/talos/usage.php, tools/mvc/talos/contracts/get.php, tools/mvc/talos/contracts/post.php, tools/mvc/talos/pricing/get.php, tools/mvc/talos/usage/get.php, tools/mvc/talos/settings/get.php, tools/mvc/talos/settings/post.php, tools/assets/css/style.css |
17
17
  | [Deploying Tools to Elastic Beanstalk (PHP 8.5 / Amazon Linux 2023)](workflows/deploy-to-elastic-beanstalk-al2023.md) | How the **Tools** 1.0 app boots on Elastic Beanstalk running `PHP 8.5 on 64bit Amazon Linux 2023/4.13.1 (aarch64)`. | tools/.ebextensions/004_http_to_https.config, tools/.ebextensions/006_mount-s3fs.config, tools/.ebextensions/007_setup_export_cache_folders.config, tools/.ebextensions/008_setup_ldap.config, tools/.ebextensions/009_setup_phpini.config, tools/.ebextensions/020_setup_git_libraries.config, tools/.ebextensions/050_register_instance_to_shared_application_load_balancer.config, tools/ebs/git.json, tools/ebs/setup_export_cache_folders.php, tools/_/app/frameworkindex.php |
@@ -6,12 +6,13 @@ project: Tools
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-08-03
9
+ updated: 2026-08-04
10
10
  owners: [jcardinal, bala]
11
11
  files:
12
12
  - tools/_/app/nav.php
13
13
  - tools/mvc/get.php
14
14
  - library/app/error.php
15
+ - library/app/database.php
15
16
  related:
16
17
  - ./persona-gated-navigation.md
17
18
  - ./saml-sso-auth.md
@@ -71,6 +72,38 @@ $res = App_Database::query($sql, 'db_team');
71
72
  $rows = App_Database::buildArrayOfRows($res, false);
72
73
  ```
73
74
 
75
+ ### Gotcha — `fetchOne()` CANNOT be used as an existence test (library-wide footgun)
76
+ `App_Database::fetchOne()` (`library/app/database.php:335-340`) does `mysqli_data_seek()` and
77
+ then returns `$row[$col]` with **no empty-result check**. On zero rows it dereferences `null`,
78
+ and the 1.0 error handler escalates that to an uncaught `ErrorException` — a bare **500**.
79
+ This affects **every 1.0 app**, not just Tools.
80
+
81
+ ```php
82
+ // WRONG — 500s whenever the row does not exist (i.e. exactly the case you're testing for)
83
+ $res = App_Database::query("SELECT id FROM TalosClients WHERE slug = '$slug'", 'db_team');
84
+ if (App_Database::fetchOne($res)) { ... }
85
+
86
+ // CORRECT — COUNT(*) always returns exactly one row
87
+ $res = App_Database::query("SELECT COUNT(*) FROM TalosClients WHERE slug = '$slug'", 'db_team');
88
+ $exists = (int) App_Database::fetchOne($res) > 0;
89
+
90
+ // CORRECT — or materialise and check
91
+ $rows = App_Database::buildArrayOfRows($res, false);
92
+ if (!empty($rows)) { ... }
93
+ ```
94
+
95
+ ## Gotcha — Tools runs PHP 8.5, where a deprecation is a fatal
96
+ The framework escalates deprecations (see the error-handler gotcha below), and **"Using null
97
+ as an array offset" is deprecated in PHP 8.5 even inside `isset()`**. So
98
+ `$arr[$row['nullableColumn']]` is a **fatal**, not a notice. Cast before indexing:
99
+
100
+ ```php
101
+ $bucket = $arr[(string) $row['nullableColumn']] ?? null;
102
+ ```
103
+
104
+ **Local dev on PHP 8.2 does not reproduce this.** 8.5-strictness is a hard requirement for
105
+ this app, not a warning — test against it before shipping.
106
+
74
107
  ## Gotcha — a page CANNOT set HTTP status/headers (preloader already flushed)
75
108
  `App_FrameworkIndex::render()` turns on the preloader and calls `App_Page::flushCapture()`
76
109
  (`ob_end_flush + flush`, `library/app/page.php:213`) **before** `body() → App_MVC::loadFile()` runs
@@ -109,6 +142,7 @@ set_error_handler(fn(): bool => true); // swallow non-fatal notices/deprecations
109
142
  `App_Talos_Estimator` → `_/app/talos/estimator.php`.
110
143
 
111
144
  ## Change history
145
+ - 2026-08-04 — Added two gotchas found rebuilding the Talos Pricing UI: (1) `App_Database::fetchOne()` is **not** an existence test — it `data_seek`s and returns `$row[$col]` with no empty check, so zero rows dereferences null → uncaught `ErrorException` → bare 500; a **library-wide** footgun affecting every 1.0 app (use `COUNT(*)` or `buildArrayOfRows` + `empty()`). (2) Tools runs **PHP 8.5**, where "using null as an array offset" is deprecated even inside `isset()` and the framework escalates deprecations to fatals — cast to `(string)` before indexing; PHP 8.2 local dev does not reproduce it. (jcardinal)
112
146
  - 2026-08-03 — Added the error-handler escalation gotcha: `App_Error::handleError` promotes ANY PHP
113
147
  notice/deprecation to a thrown `ErrorException` (ignoring `error_reporting`) and, without Sentry,
114
148
  echoes "Sentry is not installed…" into the response — corrupting JSON on AJAX endpoints; workaround
@@ -1,22 +1,23 @@
1
1
  ---
2
- title: Talos Pricing UI (Onboarding, Dashboard, Benchmarks, Cost Factors + Estimator)
2
+ title: Talos Pricing UI (Contracts, Pricing Dashboard, Usage, Settings + Estimator)
3
3
  framework: "1.0"
4
4
  repo: tools
5
5
  project: Tools
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-06-29
9
+ updated: 2026-08-04
10
10
  owners: [jcardinal]
11
11
  files:
12
12
  - tools/_/app/nav.php
13
13
  - tools/_/app/talos/estimator.php
14
- - tools/mvc/talos/onboarding/get.php
15
- - tools/mvc/talos/onboarding/post.php
14
+ - tools/_/app/talos/usage.php
15
+ - tools/mvc/talos/contracts/get.php
16
+ - tools/mvc/talos/contracts/post.php
16
17
  - tools/mvc/talos/pricing/get.php
17
- - tools/mvc/talos/benchmarks/get.php
18
- - tools/mvc/talos/factors/get.php
19
- - tools/mvc/talos/factors/post.php
18
+ - tools/mvc/talos/usage/get.php
19
+ - tools/mvc/talos/settings/get.php
20
+ - tools/mvc/talos/settings/post.php
20
21
  - tools/assets/css/style.css
21
22
  related:
22
23
  - ./persona-gated-navigation.md
@@ -30,65 +31,78 @@ related:
30
31
  ## Summary
31
32
 
32
33
  The 1.0 (tools app) face of the **Talos Pricing Platform** — a "Talos Pricing" nav folder
33
- with four pages plus a client-side estimate engine. Sales onboard a client and sign a
34
- contract here; everything else is read-only or technical-only. All four pages read the
35
- **Team DB** through a new `db_team` connection (`[database_team]` in `config.*.ini`; creds
36
- added by the developer separately).
34
+ with four pages plus the estimate engine. Restructured 2026-08-03 to
35
+ **Contracts / Pricing Dashboard / Usage / Pricing Settings**. All pages read the **Team DB**
36
+ through the `db_team` connection (`[database_team]` in `config.*.ini`).
37
37
 
38
38
  ## How it works
39
39
 
40
- ### Nav
41
- `App_Nav::definition()` gains a **"Talos Pricing"** folder with 4 actions: Onboarding,
42
- Pricing Dashboard, Usage Benchmarks, Cost Factors. Persona-gated like every other folder
43
- (see `persona-gated-navigation`). **Cost Factors is technical-only** — because
44
- `personasForRoute()` returns the *union* of folder+action personas, the Factors page must
45
- **narrow** explicitly with its own `requireAuth([technical])` rather than trusting
46
- `personasForRoute()`.
40
+ ### Contracts (`mvc/talos/contracts/{get,post}.php`) — replaces `onboarding/*`
41
+ The old Onboarding page could only **INSERT** (hardcoded `status='ONBOARDED'`, no edit, no
42
+ delete), which is why nothing ever reached the tables. Contracts is a real lifecycle, reusing
43
+ the existing status enum: **PROSPECT** = draft, **ACTIVE** = signed, **CHURNED** = ended.
47
44
 
48
- ### Estimator (`App_Talos_Estimator`, `_/app/talos/estimator.php`)
49
- Reads `TalosCostFactors` (with built-in fallback defaults if a key is missing) and produces
50
- a live cost/user + monthly estimate and recommended per-band per-user fees. **Sales never
51
- enters conversations-per-user** — that is the input they cannot know; it is derived from the
52
- cost factors / usage data we already have. The same math drives the live JS estimate on the
53
- Onboarding page.
45
+ - **A signed contract can never be hard-deleted.** `TalosPricingBands` is
46
+ `ON DELETE CASCADE`, so deleting the client would destroy the agreed rate schedule and the
47
+ margin history with it. Signed contracts **churn**; they do not delete.
48
+ - **Post-signature edits append to `TalosContractAmendments`** rather than mutating the
49
+ signed terms.
50
+ - Includes an **Actual-vs-Estimate** comparison with variance chips, a month-by-month history
51
+ table plus cost/margin chart, and a one-click **"apply recommended org fee"**.
52
+
53
+ ### Pricing Dashboard (`pricing/get.php`) — rebuilt for sales leadership
54
+ Portfolio KPIs, a 12-month blended-margin trend with the target band shaded, an exception
55
+ list with deterministic explanations, and licensed-vs-active utilisation.
54
56
 
55
- ### Onboarding (`onboarding/get.php` + `post.php`)
56
- Sales enters name / slug / offering / # users / features / # apps / min-max margin band /
57
- org fee / consecutive-months smoothing window. Live JS shows the estimate and recommended
58
- per-band fees; fees are editable. **"Sign contract" locks the band schedule** and writes
59
- `TalosClients` + `TalosPricingBands` in a single transaction. Write goes through
60
- `mvc/talos/onboarding/post.php` (the App_MVC `post.php` convention — see
61
- `mvc-data-access-patterns`).
57
+ ### Usage (`usage/get.php`, `_/app/talos/usage.php`)
58
+ Adds `costIntensity()` and a **Cost intensity** panel (tool-mix driven cost).
62
59
 
63
- ### Pricing model surfaced in the UI
64
- A flat monthly **org fee** (the adjustable margin lever) PLUS a **per-user fee that steps by
65
- user-count band**. The band rate schedule is locked at signing; when user count crosses a
66
- band the per-user fee auto-steps to the pre-agreed rate, then the org fee is adjusted to
67
- restore margin. The per-user fee never changes outside the agreed schedule. (Full
68
- methodology + COGS economics in the talos `pricing-cogs-model` doc.)
60
+ **Fixed:** `clientOptions()` read `TalosClients WHERE status='ONBOARDED'` from an
61
+ always-empty table, so the client selector rendered **empty**. It now calls
62
+ `GET /api/usage/clients` with a Team-DB fallback.
69
63
 
70
- ### Service offerings + cost multipliers
71
- Three offerings with cost multipliers stored in `TalosCostFactors`: **CHAT = 1.0** (base),
72
- **VOICE_TO_VOICE = 0.25**, **NATURAL_VOICE = 0.50**.
64
+ ### Pricing Settings (`settings/{get,post}.php`) — replaces `factors/*`
65
+ Technical-only (persona-narrowed on the action, per `mvc-data-access-patterns`). **Measured
66
+ (derived) cost-factor rows are worker-owned and read-only**, enforced server-side with
67
+ `UPDATE ... AND isDerived = 0`. Policy rows are editable and carry full-sentence labels.
73
68
 
74
- ### Read-only pages
75
- - **Pricing Dashboard** (`pricing/get.php`) — read-only per-client margin/recommendation view.
76
- - **Usage Benchmarks** (`benchmarks/get.php`) — read-only Langfuse-derived benchmarks.
77
- - **Cost Factors** (`factors/get.php` + `post.php`) — technical-only editor for the
78
- `TalosCostFactors` key/value constants (the "technical tab").
69
+ ### Removed
70
+ - `mvc/talos/benchmarks/get.php` — read the never-populated `TalosUsageMonthly` and
71
+ duplicated a worse subset of the Usage page.
72
+ - `mvc/talos/onboarding/*` and `mvc/talos/factors/*` — superseded above.
73
+
74
+ ### Estimator (`App_Talos_Estimator`, `_/app/talos/estimator.php`)
75
+ Now driven by the **token unit price** and **workload profiles** instead of the feature
76
+ checklist and per-client calibration factor (methodology in `pricing-cogs-model`). Service
77
+ offering (CHAT / VOICE_TO_VOICE / NATURAL_VOICE) describes **modality only** and says nothing
78
+ about cost; cost is driven by tool-call **intensity** via the profile
79
+ (retrieval / general / analytics).
79
80
 
80
81
  ## Gotchas
81
- - **`db_team` is read-only on the dashboards** but read/write on onboarding + factors. Add
82
- the `[database_team]` config section (alias `db_team`) — same pattern as `db_true → Client_True`.
83
- - **Voice multiplier wording is ambiguous** — "1/4 / 1/2 the cost of chat" is flagged; full
84
- voice modeling is deferred. Treat 0.25 / 0.50 as placeholders.
85
- - **Narrowing personas:** do not use `personasForRoute()` for a page stricter than its folder
86
- (Cost Factors). See `mvc-data-access-patterns`.
82
+
83
+ - **`App_Database::fetchOne()` is not an existence test** — it 500s on zero rows. See
84
+ [mvc-data-access-patterns](./mvc-data-access-patterns.md); the original
85
+ `onboarding/post.php` carried this exact bug and would have fataled on the first save
86
+ anyone attempted, which is good evidence nobody ever completed an onboarding through it.
87
+ - **This app runs PHP 8.5 and escalates deprecations to fatals** — `$arr[$row['nullableCol']]`
88
+ is fatal even inside `isset()`. Local dev on PHP 8.2 does **not** reproduce it. Cast to
89
+ `(string)` before indexing. See `mvc-data-access-patterns`.
90
+ - **`.tool--wide` did nothing.** `assets/css/style.css` documented the class as escaping the
91
+ 960px `.app-content` cap "via `:has()`", but that rule was never written. Added
92
+ `.app-content:has(.tool--wide) { max-width: 100% }` — which also makes the pre-existing
93
+ `mvc/errors` pages genuinely full-width for the first time.
94
+ - **Put Talos page CSS in `style.css`, not a page-local `<style>` block.** The Contracts page
95
+ **returns early** for list mode, so a `<style>` block placed after that return applied to
96
+ the calculator only and the list rendered with no CSS at all.
97
+ - **Voice multipliers (0.25 / 0.50) are UNVALIDATED** — supplied second-hand, never measured,
98
+ and possibly inverted. Flagged in the UI. **Do not quote voice from them.**
99
+ - **`db_team`** is read/write on Contracts and Settings, read-only on the dashboards.
87
100
 
88
101
  ## Security
89
- - `config.*.ini` already carries committed plaintext secrets (team-accepted, see architecture
90
- Known issues), including a reused plaintext DB password across `config.production.ini`
91
- sections — flagged for rotation. Location only; no values recorded. Do not add more secrets.
102
+ - `config.*.ini` carries committed plaintext secrets (team-accepted, see architecture Known
103
+ issues) — **all still owe rotation**. Config keys referenced by name only
104
+ (`[api] talos_backend_url` / `talos_backend_key`); no values recorded. Do not add secrets.
92
105
 
93
106
  ## Change history
107
+ - 2026-08-04 — Restructured to **Contracts / Pricing Dashboard / Usage / Pricing Settings**. New Contracts pages replace Onboarding with a real PROSPECT/ACTIVE/CHURNED lifecycle (signed contracts churn, never hard-delete — `TalosPricingBands` cascades; post-signature edits append to `TalosContractAmendments`), plus actual-vs-estimate variance, month history chart and one-click apply-recommended-org-fee. Settings replaces the Cost Factors editor with measured rows read-only (`UPDATE ... AND isDerived = 0`). Benchmarks page deleted. Pricing Dashboard rebuilt for sales leadership. Fixed `usage.php clientOptions()` reading an always-empty `TalosClients` (selector rendered empty) → `GET /api/usage/clients` with Team-DB fallback; added cost-intensity panel. Estimator moved to token unit price + workload profiles. Wrote the missing `.app-content:has(.tool--wide)` rule and consolidated Talos CSS into `style.css`. (jcardinal)
94
108
  - 2026-06-29 — Built the Talos Pricing UI: nav folder + 4 pages (Onboarding w/ live JS estimate and contract-signing that locks the band schedule into `TalosClients`+`TalosPricingBands` in one txn; read-only Pricing Dashboard + Usage Benchmarks; technical-only Cost Factors editor) and `App_Talos_Estimator` (reads `TalosCostFactors`, derives conversations/user so sales need not enter it). Reads Team DB via new `db_team` connection. Offerings CHAT/VOICE_TO_VOICE/NATURAL_VOICE = 1.0/0.25/0.50 (voice ambiguous, deferred). (jcardinal)
@@ -7,5 +7,5 @@
7
7
  | [Deployment — Docker, Compose, Entrypoint, External PG/Redis](features/deployment.md) | TOGa IQ ships as a **single container** (`aegra` service) wrapping the `aegra-api` FastAPI server. | talos/docker-compose.yml, talos/deployments/docker/Dockerfile, talos/deployments/docker/entrypoint.sh |
8
8
  | [MCP Servers — clickup-mcp and toga-db-mcp](features/mcp-servers.md) | Two internal **FastMCP** servers exposed over **HTTP** with API-key auth and PM2 process management: - **`clickup-mcp`** — ClickUp workspace surface (spaces / f | talos/mcp-servers/clickup-mcp/src, talos/mcp-servers/clickup-mcp/ecosystem.config.js, talos/mcp-servers/clickup-mcp/ecosystem.dev.config.js, talos/mcp-servers/clickup-mcp/pyproject.toml, talos/mcp-servers/clickup-mcp/.env.example, talos/mcp-servers/toga-db-mcp/src, talos/mcp-servers/toga-db-mcp/clusters.yaml, talos/mcp-servers/toga-db-mcp/ecosystem.config.js, talos/mcp-servers/toga-db-mcp/pyproject.toml, talos/mcp-servers/toga-db-mcp/.env.example |
9
9
  | [Observability — Langfuse, OTEL, Prometheus, OneUptime](features/observability.md) | TOGa IQ uses **two complementary tracing planes** plus optional Prometheus metrics and external uptime monitoring: - **Langfuse (native v3 SDK)** — LLM-shaped t | talos/libs/aegra-api/src/aegra_api/observability/__init__.py, talos/libs/aegra-api/src/aegra_api/observability/setup.py, talos/libs/aegra-api/src/aegra_api/observability/base.py, talos/libs/aegra-api/src/aegra_api/observability/langfuse_provider.py, talos/libs/aegra-api/src/aegra_api/observability/langfuse_client.py, talos/libs/aegra-api/src/aegra_api/observability/otel.py, talos/libs/aegra-api/src/aegra_api/observability/metrics.py, talos/libs/aegra-api/src/aegra_api/observability/span_enrichment.py, talos/libs/aegra-api/src/aegra_api/observability/targets |
10
- | [Pricing & COGS Model (Talos / TOGa IQ Pricing Calculator)](features/pricing-cogs-model.md) | The cost basis and pricing methodology for selling Talos (TOGa IQ) chat and voice deployments. | |
10
+ | [Pricing & COGS Model (Talos / TOGa IQ Pricing Calculator)](features/pricing-cogs-model.md) | The cost basis and pricing methodology for selling Talos (TOGa IQ) chat and voice deployments. | worker2/Worker/Talos/Pricing.php, tools/_/app/talos/estimator.php, dbchanges2/Team/2026-08-03a - TalosPricingTokenCostModel.sql |
11
11
  | [talos_agent — LangGraph ReAct Agent with Plan, BLP, MCP, Canvas](features/talos-agent.md) | `talos_agent` is the **reference LangGraph agent** shipped under `agents/talos_agent/`. | talos/agents/talos_agent/graph.py, talos/agents/talos_agent/state.py, talos/agents/talos_agent/context.py, talos/agents/talos_agent/prompts.py, talos/agents/talos_agent/tool_router.py, talos/agents/talos_agent/model_helpers.py, talos/agents/talos_agent/config/context.py, talos/agents/talos_agent/config/model_config.py, talos/agents/talos_agent/config/tool_config.py, talos/agents/talos_agent/config/plan_config.py, talos/agents/talos_agent/config/memory_config.py, talos/agents/talos_agent/config/mcp_config.py, talos/agents/talos_agent/config/blp_config.py, talos/agents/talos_agent/config/interrupt_config.py, talos/agents/talos_agent/config/artifact_config.py, talos/agents/talos_agent/plan/planner.py, talos/agents/talos_agent/plan/nodes.py, talos/agents/talos_agent/llm/system_prompt.py, talos/agents/talos_agent/llm/tool_binding.py, talos/agents/talos_agent/llm/message_ops.py, talos/agents/talos_agent/mcp/client.py, talos/agents/talos_agent/mcp/security.py, talos/agents/talos_agent/mcp/session_manager.py, talos/agents/talos_agent/blp/registry.py, talos/agents/talos_agent/blp/embedder.py, talos/agents/talos_agent/blp/nodes.py, talos/agents/talos_agent/tools/__init__.py, talos/agents/talos_agent/tools/code_interpreter.py, talos/agents/talos_agent/tools/canvas.py, talos/agents/talos_agent/tools/knowledge_base.py, talos/agents/talos_agent/tools/skill_injector.py, talos/agents/talos_agent/thread_name/nodes.py |
@@ -6,9 +6,12 @@ project: TOGa IQ
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-06-29
9
+ updated: 2026-08-04
10
10
  owners: [jcardinal]
11
- files: []
11
+ files:
12
+ - worker2/Worker/Talos/Pricing.php
13
+ - tools/_/app/talos/estimator.php
14
+ - dbchanges2/Team/2026-08-03a - TalosPricingTokenCostModel.sql
12
15
  related:
13
16
  - ../architecture.md
14
17
  - aegra-api.md
@@ -38,7 +41,67 @@ a platform architecture doc captures the cross-framework topology.
38
41
  Treat the numbers below as the **April 2026 baseline**; re-measure before relying
39
42
  on them in a later period.
40
43
 
41
- ## Cost methodology — calibrate Langfuse to AWS (decision, 2026-06-29)
44
+ ## Cost methodology — measured token unit price (decision, 2026-08-03) ← CURRENT
45
+
46
+ **Supersedes the Langfuse calibration-factor method below.** Cost is tokens, priced at the
47
+ real AWS rate:
48
+
49
+ ```
50
+ unitCostPer1kTokens = AWS Bedrock-family actual $ / measured tokens
51
+ clientMonthlyCost = client tokens × unitCostPer1kTokens
52
+ ```
53
+
54
+ **Measured July 2026:** $1,013.76 / 258.3M tokens = **$0.00392447 per 1k tokens**.
55
+
56
+ - **Why not cost-per-conversation.** Measured on True, questions per conversation range
57
+ **1.0–61.0** (median 2.1, p90 6.5) — a 60× spread. A conversation cannot anchor a price.
58
+ - **Why not usage-API dollars.** The usage API reports cost **~2.5× below** the real AWS bill
59
+ because it undercounts prompt caching (cache reads are 47% of True's tokens). Its **token
60
+ counts** are a real measurement and are used; **its dollars never are.**
61
+ - The per-client **calibration factor** is retired.
62
+
63
+ ### Workload profiles replace the feature checklist (decision, 2026-08-03)
64
+
65
+ Service offering (CHAT / VOICE_TO_VOICE / NATURAL_VOICE) describes **modality** and says
66
+ nothing about cost. Cost is driven by tool-call **intensity**, which varies by what the client
67
+ uses Talos for. Measured on True, cost is **42% `mcp_or_other`** (app integrations), **26%
68
+ `code_interpreter`**, only **19% `knowledge_base`** — the opposite of what was assumed.
69
+
70
+ Cost per tool call is near flat across categories ($0.046–$0.062; `canvas` the outlier at
71
+ $0.122), so **a single unit price × an intensity figure** models this and a per-tool price
72
+ list is unnecessary. Three seeded profiles in `TalosWorkloadProfiles`:
73
+ **retrieval** / **general** (measured from True) / **analytics** (estimated).
74
+
75
+ ### Model mix is a bigger lever than any contracted feature
76
+
77
+ Measured on True: `amazon.nova-pro` serves **70%** of LLM calls at $0.00092/1k while
78
+ `claude-sonnet-4-5` serves **25%** at $0.00142/1k (76.3% cache). A **routing change moves
79
+ COGS more than any feature flag**, so `TalosUsageModelMonthly` records model mix per
80
+ client-month — cheap now, expensive to backfill, and the most likely explanation for a future
81
+ margin swing.
82
+
83
+ ### App integrations are recorded but NOT yet priced
84
+
85
+ `tokensPerIntegrationPerUser` is seeded **0**, `isValidated 0`. Integrations are almost
86
+ certainly the largest cost driver (`mcp_or_other` = 42% of True's cost), but a slope needs
87
+ **≥2 clients** with a known integration count and real usage, and there is exactly one.
88
+ Inventing a coefficient repeats the mistake of the old $2.00/user default. The plumbing is
89
+ wired so the estimate, band recommendations, and tool-mix chart all respond the moment a real
90
+ figure is set. Method recorded in the migration: **regress each client's `mcp_or_other`
91
+ tokens-per-user against its `appIntegrationCount`.**
92
+
93
+ ### orgFeeShareOfRevenue (decision, 2026-08-03)
94
+
95
+ Default **0.25**. Fixes a double-count: the per-user fee was priced to hit the full target
96
+ margin on its own, so the org-fee recommendation collapsed to ~$0.07 on a $1,036 contract,
97
+ making the one adjustable lever useless. The seat fee now covers `(1 − share)` of target
98
+ revenue and the flat fee covers the rest — **effective price per user is identical, only the
99
+ split changes**. `share = 0` reduces exactly to the old formula. Verified to reconcile to the
100
+ target margin to the cent.
101
+
102
+ ## Cost methodology — calibrate Langfuse to AWS (2026-06-29) — SUPERSEDED
103
+
104
+ > Retired 2026-08-03 by the token unit price above. Kept for context on pre-August figures.
42
105
 
43
106
  Langfuse provides the **structure** (granular per-feature / per-user breakdown);
44
107
  AWS provides the **absolute dollars**. Each month, per client:
@@ -181,9 +244,16 @@ Technical / Actuals / Engine tabs, per-client file under the shared AI drive) is
181
244
  hack, not a bug to silently correct.
182
245
  - **OpenSearch +$350/mo is conditional** — only counts when Document Search is
183
246
  enabled; do not bake it into every quote.
247
+ - **Voice multipliers 0.25 / 0.50 are UNVALIDATED** — supplied second-hand, never measured,
248
+ and may be **inverted**. Flagged in the UI. Do not quote voice from them.
249
+ - **`infraFixedMonthly` is 0** — shared platform cost has never been measured, so band
250
+ recommendations come out flat. That flat table is the **honest output, not a bug**.
251
+ - **Internal tenants are costed but not quoted** — True (TOGA Technology) feeds the platform
252
+ unit price and is excluded from fee recommendations; see `talos-pricing-automation`.
184
253
  - **Do not embed the absolute drive path as canonical** — the calculator lives
185
254
  under the team shared AI drive; the path can move.
186
255
 
187
256
  ## Change history
257
+ - 2026-08-04 — **Cost model replaced**: measured **token unit price** (AWS Bedrock-family actual ÷ measured tokens; July 2026 = $0.00392447/1k) retires the per-client Langfuse calibration factor. Rejected cost-per-conversation (1.0–61.0 questions/conversation, 60× spread) and usage-API dollars (~2.5× below the AWS bill; undercounts caching — token counts used, dollars never). **Workload profiles** (retrieval/general/analytics) replace the feature checklist: offering = modality only; cost = tool-call intensity, measured 42% mcp_or_other / 26% code_interpreter / 19% knowledge_base with near-flat cost per tool call. Added model-mix tracking (nova-pro 70% of calls at $0.00092/1k vs sonnet-4-5 25% at $0.00142/1k — routing beats any feature flag), **orgFeeShareOfRevenue** (default 0.25) to stop the seat fee double-counting the whole target margin, and integrations recorded-but-unpriced pending a second client. (jcardinal)
188
258
  - 2026-06-29 — Pricing **delivery pivoted** from the Excel calculator to a DB platform (Team DB 9 `Talos*` tables + tools 1.0 UI + worker2 crons). Cost methodology recorded as **calibrate Langfuse→AWS** (per-client factor = AWS/Langfuse_corrected; global-blended fallback for new clients; always use cache-corrected Langfuse). Methodology refined: per-user fee is now a **locked band schedule** (steps with headcount) with the **org fee** as the margin lever (was fixed per-user + midpoint-solved flat fee). COGS token economics unchanged. (jcardinal)
189
259
  - 2026-06-29 — Initial pricing/COGS model doc: chat token + feature drivers, voice per-minute drivers, two-part flat+per-user methodology with mid-band solve and consecutive-month smoothing. Captured from TALOS Pricing Calculator v9 (replaces v8). v9 verified to reproduce v8 exactly ($0.811182/conversation, $2,071.18/mo for 50 users × 20 conversations, Document Search only). History ×7 vs ×15-exchanges quirk preserved for parity and flagged for technical review. (jcardinal)
@@ -31,7 +31,7 @@
31
31
  | [Platform Cache Cleanup (_Worker_Platform_Cache — Clean + Truncate)](features/platform-cache-cleanup.md) | `_Worker_Platform_Cache` owns maintenance of the shared **Cache** cluster that backs api2's [multi-client data retrieval](../../api2/features/cross-client-data- | worker2/Worker/Platform/Cache.php, worker2/Controller/Index.php, worker2/_.php, dbchanges2/Core/2026-07-27a - PlatformCacheCleanCron.sql |
32
32
  | [Startech Webhook Handler (worker2)](features/startech-webhook-handler.md) | Receives inbound webhook events from Startech (Easeedesk) and creates or updates the corresponding ticket in TOGA 2.0. | worker2/Worker/Startech.php |
33
33
  | [Talos (TOGa IQ) Meeting-Notes Integration & Token Auto-Refresh (consumer)](features/talos-meeting-notes-integration.md) | How a **dev tool / agent consumes Talos (TOGa IQ)** to query the team meeting-notes corpus programmatically. | .claude/skills/plan-ticket/scripts/talos.js |
34
- | [Talos Pricing Automation (worker2 Cron — AWS Actuals, Calibration, Monthly Report)](features/talos-pricing-automation.md) | The worker2 half of the **Talos Pricing Platform** (see the talos `pricing-cogs-model` and tools `talos-pricing-ui` docs for the other halves). | worker2/Worker/Talos/Pricing.php, worker2/Database/TalosPricingCrons.sql |
34
+ | [Talos Pricing Automation (worker2 Cron — Usage Import, AWS Actuals, Margins, Profiles)](features/talos-pricing-automation.md) | The worker2 half of the **Talos Pricing Platform** (see the talos `pricing-cogs-model` and tools `talos-pricing-ui` docs for the other halves). | worker2/Worker/Talos/Pricing.php, worker2/Database/TalosPricingCrons.sql, dbchanges2/Team/2026-08-03a - TalosPricingTokenCostModel.sql, dbchanges2/Team/2026-08-03b - TalosInternalTenant.sql, dbchanges2/Team/2026-08-03c - TalosIntegrationCostFactor.sql, dbchanges2/Core/2026-08-03a - Talos pricing cron jobs.sql |
35
35
  | [Talos Transcript Ingestion Pipeline (worker2 → AWS Bedrock KBs)](features/talos-transcript-ingestion.md) | > **DB-DRIVEN AI-MODEL ROUTING (2026-07-29).** Which knowledge base a transcript is cleaned > into is now decided by the **meeting organizer's "home" AI model** | worker2/Worker/Team/Transcripts.php, worker2/bin/sync-knowledge-bases.php, worker2/Config/production.ini, worker2/Database/TeamsTranscriptExports.sql, dbchanges2/Client_True/2026-07-27a - TranscriptAiModelRoutingColumns.sql, dbchanges2/Client_True/2026-07-27b - TranscriptAiModelRoutingData.sql, dbchanges2/Team/2026-07-27a - TranscriptVocabularyAiModelScope.sql, dbchanges2/Team/2026-07-29a - TranscriptVocabularyBackfillAllModels.sql, dbchanges2/Team/2026-06-30a, dbchanges2/Team/2026-06-30b, dbchanges2/Team/2026-06-30c, dbchanges2/Team/2026-06-30d, dbchanges2/Team/2026-06-30e, dbchanges2/Core/2026-06-30a, dbchanges2/Core/2026-07-02a, dbchanges2/Team/2026-07-02a, dbchanges2/Team/2026-07-08a, dbchanges2/Team/2026-07-09a, dbchanges2/Team/2026-07-10a, dbchanges2/Team/2026-07-28a - TranscriptProcessingRetryAttempts.sql, dbchanges2/Team/2026-07-28b - TranscriptPromptTemplateConverseModel.sql, dbchanges2/Core/2026-07-28a - TeamsTranscriptRetryCron.sql |
36
36
  | [Team Sprint Management & Reporting](features/team-sprint-management.md) | `_Worker_Team_Sprint` (file `Worker/Team/Sprint.php`) is the engine behind TOGA's internal **development-sprint process and reporting**. | worker2/Worker/Team/Sprint.php, _underscore/Model/Team/Sprint.php, dbchanges2/Core/CronJobs (SprintLockScheduled seed) |
37
37
  | [Teams Meeting Transcript Export](features/teams-transcript-export.md) | > **SUPERSEDED (2026-07-09) — the S3-staging model below is history.** `Export` is now a thin > **GRAPH-DIRECT** cron poller: it no longer archives raw VTT to ` | worker2/Worker/Team/Transcripts.php, worker2/Config/production.ini, worker2/Database/TeamsTranscriptExports.sql, dbchanges2/Core/2026-06-18a - Teams Transcript Export schedule.sql |
@@ -1,16 +1,20 @@
1
1
  ---
2
- title: Talos Pricing Automation (worker2 Cron — AWS Actuals, Calibration, Monthly Report)
2
+ title: Talos Pricing Automation (worker2 Cron — Usage Import, AWS Actuals, Margins, Profiles)
3
3
  framework: "2.0"
4
4
  repo: worker2
5
5
  project: Worker
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-06-29
9
+ updated: 2026-08-04
10
10
  owners: [jcardinal]
11
11
  files:
12
12
  - worker2/Worker/Talos/Pricing.php
13
13
  - worker2/Database/TalosPricingCrons.sql
14
+ - dbchanges2/Team/2026-08-03a - TalosPricingTokenCostModel.sql
15
+ - dbchanges2/Team/2026-08-03b - TalosInternalTenant.sql
16
+ - dbchanges2/Team/2026-08-03c - TalosIntegrationCostFactor.sql
17
+ - dbchanges2/Core/2026-08-03a - Talos pricing cron jobs.sql
14
18
  related:
15
19
  - ./creating-worker-actions.md
16
20
  - ../architecture.md
@@ -21,64 +25,140 @@ related:
21
25
 
22
26
  ## Summary
23
27
 
24
- The worker2 half of the **Talos Pricing Platform** (see the talos `pricing-cogs-model`
25
- and tools `talos-pricing-ui` docs for the other halves). `_Worker_Talos_Pricing` is an
26
- **abstract** worker class with three monthly cron actions that turn raw usage/cost data
27
- into per-client margin tracking and a leadership report. All state lives in the **Team DB**
28
- (9 `Talos*` tables — schema home is the platform architecture doc); the worker reads/writes
29
- it via `_underscore::DB_TEAM`.
28
+ The worker2 half of the **Talos Pricing Platform** (see the talos `pricing-cogs-model` and
29
+ tools `talos-pricing-ui` docs for the other halves). `_Worker_Talos_Pricing` is an
30
+ **abstract** worker class whose monthly cron actions turn raw usage and AWS cost data into a
31
+ measured platform **unit price per 1k tokens**, per-client cost, and margin tracking. All
32
+ state lives in the **Team DB** (`Talos*` tables), reached via `_underscore::DB_TEAM`.
30
33
 
31
- This replaces the Excel "Actuals" tab as the monthly recompute mechanism. The COGS token
32
- economics are unchanged — only the delivery/automation changed.
34
+ **Switched on and verified in production 2026-08-03** for period `2026-07-01`. Before that
35
+ every `Talos*` table was empty, the crons were never registered as `Core.CronJobs` rows, and
36
+ the estimator ran only on placeholder constants — i.e. the platform was built but had never
37
+ run. It now reconciles to the AWS bill exactly: July 2026 = **$1,013.76** (True-tagged
38
+ $549.18 + untagged $464.58 + Towfoundation $0.0016), measured unit price
39
+ **$0.00392447 / 1k tokens**.
33
40
 
34
41
  ## How it works
35
42
 
36
- `initialize()` registers the Team DB connection via `_underscore::DB_TEAM` (same pattern as
37
- `_Worker_Team_Transcripts`) so every action has it. The three actions are registered as
38
- `Core.CronJobs` rows (no code wiring — see `creating-worker-actions`), fired on the **4th of
39
- the month**, sequenced 06:00 / 07:00 / 08:00 Central so each step's inputs are present
40
- before the next runs.
41
-
42
- ### 1. ImportAwsActuals (06:00)
43
- Calls AWS Cost Explorer `GetCostAndUsage` per client, filtered by `LINKED_ACCOUNT` or a
44
- cost-allocation **tag** (assumed key `Client` — open item, confirm). Upserts one row per
45
- `(clientIdentifier, periodMonth)` into `TalosAwsActualsMonthly`. The AWS Cost Explorer SDK
46
- is vendored in `worker2/vendor`.
47
-
48
- ### 2. RecomputeMargins (07:00)
49
- The core calibration step. For each client/month:
50
- - **Calibration factor** = `AWS_actual / Langfuse_costCorrected` (write to
51
- `TalosCalibrationMonthly`, `DECIMAL(14,8)`). Always use Langfuse's **cache-corrected**
52
- cost — Langfuse badly undercounts cache cost (sample: $201 recorded vs $1,088 corrected).
53
- - **New clients** (no AWS history) use a **global blended factor** = `SUM(aws) / SUM(langfuse)`
54
- across all clients, until they have their own rolling-3-month factor.
55
- - Apply the factor to Langfuse's granular per-feature/per-user structure so **structure comes
56
- from Langfuse, absolute dollars from AWS**.
57
- - Compute per-client margin vs. the client's min/max band, update the consecutive out-of-band
58
- **streak**, and only emit a `TalosFeeRecommendations` row once the streak ≥ the client's
59
- configured `consecutiveMonths`.
60
-
61
- ### 3. MonthlyReport (08:00)
62
- Builds an `.xlsx` with **PhpSpreadsheet** (vendored at
63
- `_underscore/Component/Library/PhpOffice` — first use in worker2) and sends a templated
64
- leadership email via `_Model_Client_EmailTemplate::send(...)` to the `True` client,
65
- rendering `{var}` placeholders through AWS SES.
43
+ `initialize()` registers the Team DB connection via `_underscore::DB_TEAM`. The four actions
44
+ are `Core.CronJobs` rows (no code wiring — see `creating-worker-actions`), fired on the
45
+ **4th of the month** at 06:00 / 07:00 / 08:00 / 09:00 Central.
46
+
47
+ **The order is load-bearing:** `ImportUsage` → `ImportAwsActuals` → `RecomputeMargins` →
48
+ `RecomputeProfiles`. Each step's inputs are the prior step's outputs; running them out of
49
+ order produces wrong prices rather than an error.
50
+
51
+ **Why the 4th, not the 1st:** the usage API's `token_data_as_of` lagged ~5 days. Reading a
52
+ partial month understates the token denominator and therefore **inflates** the unit price.
53
+
54
+ ### 1. ImportUsage (06:00)
55
+ Pulls token/activity data from the Talos usage API into `TalosUsageMonthly` (now split by
56
+ token class) and `TalosUsageModelMonthly` (model mix per client-month).
57
+
58
+ **The API cannot return an arbitrary past calendar month.** It answers only `7d` / `30d` /
59
+ `mtd` / `ytd`, and its xlsx export carries only MTD and YTD sheets. A calendar month is
60
+ therefore derived by **differencing two year-to-date snapshots**, persisted in
61
+ `TalosUsageSnapshots`. Three edge cases are handled explicitly:
62
+ - **First-ever run** — no prior snapshot, so it falls back to the `30d` window and flags the
63
+ row `API_30D_APPROX`.
64
+ - **January year-rollover** — detected, so YTD resetting to zero is not read as negative usage.
65
+ - **Multi-month gap** — flagged `API_YTD_ROLLOVER_GAP` rather than passed off as a clean month.
66
+
67
+ The proper fix is a `from_date`/`to_date` parameter on `/api/usage/overview`; the refresh
68
+ endpoint already accepts `from_date`, so the backend plumbing exists. Open with the Talos
69
+ backend developer.
70
+
71
+ ### 2. ImportAwsActuals (07:00)
72
+ AWS Cost Explorer `GetCostAndUsage`, upserted per `(clientIdentifier, periodMonth)` into
73
+ `TalosAwsActualsMonthly`, which now records `unitCostPer1kTokens`, `serviceScope`, and the
74
+ tagged/untagged cost split. Three defects found and fixed here — see Gotchas; each one alone
75
+ made every quote wrong.
76
+
77
+ Untagged spend is attributed to the **defaultTenant**, and every row records
78
+ `isDefaultTenantApplied` so the day a second tenant makes that attribution wrong is visible.
79
+
80
+ ### 3. RecomputeMargins (08:00)
81
+ Computes `clientMonthlyCost = client tokens × unitCostPer1kTokens`, margin vs. the client's
82
+ band, the consecutive out-of-band streak, and emits a `TalosFeeRecommendations` row only once
83
+ the streak ≥ the client's `consecutiveMonths`. **Internal tenants are excluded from fee
84
+ recommendations** (see below). The old per-client "calibration factor" is gone.
85
+
86
+ ### 4. RecomputeProfiles (09:00)
87
+ Recomputes the measured workload profiles (`TalosWorkloadProfiles`) and the measured cost
88
+ factors from actual tool-mix data.
89
+
90
+ ### Measured vs. policy cost factors
91
+ `TalosCostFactors` is now split by `isDerived` / `isValidated` (plus `name`, `description`).
92
+ **Derived rows are worker-owned and must never be hand-edited** — the tools Settings page
93
+ enforces this server-side with `UPDATE ... AND isDerived = 0`.
94
+
95
+ ### Internal tenants
96
+ `TalosClients.isInternal` (migration `2026-08-03b`). True is TOGA Technology, not a paying
97
+ client, but it holds nearly all usage and — via `defaultTenant` — all untagged AWS spend, so
98
+ it **must** exist as a row or there is no unit price at all. Modelling it as a zero-revenue
99
+ contract made every margin figure lie (margin computes as 0%, so it sits permanently in
100
+ "Needs attention" and drags blended portfolio margin negative). Internal tenants are
101
+ **costed and do feed the platform unit price** (our own usage consumes real Bedrock capacity)
102
+ but are **excluded from `TalosFeeRecommendations`**.
103
+
104
+ ### Schema (dbchanges2 migrations, 2026-08-03)
105
+ - **Team `2026-08-03a` TalosPricingTokenCostModel** — token split on `TalosUsageMonthly`;
106
+ `unitCostPer1kTokens` / `serviceScope` / tagged+untagged cost on `TalosAwsActualsMonthly`;
107
+ measured-vs-policy split on `TalosCostFactors`; new `TalosWorkloadProfiles`,
108
+ `TalosUsageModelMonthly`, `TalosUsageSnapshots`, `TalosContractAmendments`; seeds 13 cost
109
+ factors and 3 workload profiles.
110
+ - **Team `2026-08-03b` TalosInternalTenant** — `isInternal` on `TalosClients`.
111
+ - **Team `2026-08-03c` TalosIntegrationCostFactor** — `tokensPerIntegrationPerUser`.
112
+ - **Core `2026-08-03a` Talos pricing cron jobs** — registers the 4 crons.
113
+
114
+ ### Configuration
115
+ The existing `[talos]` config group gains **`usage_url`** and **`usage_api_key`** (the same
116
+ values the tools app holds as `[api] talos_backend_url` / `talos_backend_key`). Keys are
117
+ referenced by name only.
66
118
 
67
119
  ## Gotchas / open items
120
+
121
+ - **AWS cost query — three defects that all produced badly wrong prices** (found 2026-08-03):
122
+ 1. **No service filter.** The query summed every dollar in the linked account (RDS alone is
123
+ ~$9,917/mo), so one client would have been charged ~$18k instead of ~$1k.
124
+ 2. **Wrong tag key.** It filtered `Tags.Key='Client'`; no such tag exists. The activated
125
+ cost-allocation tag is **`tenant`** (activated alongside `model` and `model_role`).
126
+ 3. **Service-name trap.** AWS bills **each Claude model as its own service**
127
+ ("Claude Sonnet 4.5 (Amazon Bedrock Edition)", etc.). Filtering the literal
128
+ `"Amazon Bedrock"` captured **3.3%** of real model spend — $31.49 of $1,013.76 for July
129
+ 2026. The family had 8 members in July and grows with every model launch, so the member
130
+ list must be resolved **at run time** via `ce:GetDimensionValues --search-string "Bedrock"`
131
+ and **snapshotted per row**. Never hardcode the service list.
132
+ - **IAM:** the EB instance role now needs **`ce:GetDimensionValues`** in addition to
133
+ `ce:GetCostAndUsage`.
134
+ - **Cost-allocation tagging went live 2026-07-16.** Before that, 100% of Bedrock spend is
135
+ untagged (June 2026: $798.44) and is **not recoverable per-tenant**. After, untagged fell to
136
+ ~8% for the rest of July and 0.8% in August. The gap is **temporal and self-correcting**,
137
+ not structural: `defaultTenant` is a backfill mechanism with a shelf life.
138
+ - **July's unit price is ~8% conservative** — the cost numerator is a full calendar month
139
+ while the token denominator was a 30-day rolling window (`API_30D_APPROX`). August
140
+ differences two snapshots and the windows align.
141
+ - **Never use the usage API's dollar figures.** It reports cost ~2.5× **below** the real AWS
142
+ bill because it undercounts prompt caching (cache reads are 47% of True's tokens). Its
143
+ **token counts** are a real measurement and are used; its dollars never are.
68
144
  - **Idempotent upsert key** — every fact table is keyed `(clientIdentifier, periodMonth)`
69
- (usage-by-feature adds `toolCategory`), with a UNIQUE on those columns, so re-running a
70
- cron is safe.
71
- - **`REPORT_EMAIL_TEMPLATE` is a placeholder UUID** — needs a real `EmailTemplates` record in
72
- `Client_True` before MonthlyReport sends.
73
- - **`_Email` attachment support unconfirmed** — verify before relying on the xlsx attachment.
74
- - **AWS cost-tag key assumed `Client`** — confirm against the actual cost-allocation tag.
75
- - **Importer contract (other dev):** `TalosUsageMonthly` + `TalosUsageFeatureMonthly` are the
76
- Langfuse → MySQL targets. Map the Langfuse org tag `org:True` → `clientIdentifier` `"True"`;
77
- upsert on `(clientIdentifier, periodMonth[, toolCategory])`.
145
+ (usage-by-feature adds `toolCategory`) with a UNIQUE, so re-running a cron is safe.
146
+ - **Tow Foundation has no token extract** — `/api/usage/overview` returns 83 messages /
147
+ 10 conversations / 2 users for ytd but `tokens=0`, `cost=$0`, and nothing in the last 30
148
+ days; their tagged AWS spend was $0.0016 for July, far too low for 83 real questions. The
149
+ activity counters and the token/cost extract are **separate sources with their own
150
+ `token_data_as_of` high-water mark**, and the extract appears never to have run for that
151
+ org. "Refresh token data" does not populate it. Note the Talos Postgres DB the weekly
152
+ report queries is named **`tenant_true`**, hinting at per-tenant databases — if the extract
153
+ job points at that one DB, no refresh will ever produce Tow Foundation tokens. With the
154
+ Talos backend developer.
78
155
 
79
156
  ## Security
80
- - Hardcoded AWS SES SMTP credentials live in `_underscore/Email.php` (pre-existing, not
81
- introduced here) — flagged for rotation. Location only; no values recorded.
157
+ - Config keys referenced by name only (`[talos] usage_url` / `usage_api_key`); no values are
158
+ recorded anywhere in the knowledge base.
159
+ - Hardcoded AWS SES SMTP credentials live in `_underscore/Email.php` (pre-existing) — flagged
160
+ for rotation. Location only.
82
161
 
83
162
  ## Change history
163
+ - 2026-08-04 — **Platform switched on and verified in production** for 2026-07. Cost model replaced: per-client calibration factor → measured **unit cost per 1k tokens** from the Bedrock-family AWS actual. Fixed three AWS cost-query defects (no service filter; wrong tag key `Client` → `tenant`; per-model service names resolved at run time via `ce:GetDimensionValues` and snapshotted — the literal "Amazon Bedrock" captured only 3.3% of spend). New actions `ImportUsage` + `RecomputeProfiles`; `ImportAwsActuals`/`RecomputeMargins` rewritten; crons on the 4th at 06/07/08/09:00 in a load-bearing order. Calendar months derived by differencing YTD snapshots (`API_30D_APPROX` / `API_YTD_ROLLOVER_GAP` flags). Added `isInternal` tenants (costed, feed the unit price, excluded from fee recommendations). New `[talos] usage_url`/`usage_api_key` config keys and `ce:GetDimensionValues` IAM permission. (jcardinal)
84
164
  - 2026-06-29 — Built `_Worker_Talos_Pricing` (abstract) with 3 monthly crons — ImportAwsActuals (Cost Explorer), RecomputeMargins (calibrate Langfuse→AWS, rolling-3mo + global-blended fallback, margin/streak/recommendation), MonthlyReport (PhpSpreadsheet xlsx + templated SES email to True). Registers Team DB via `_underscore::DB_TEAM`; crons are `Core.CronJobs` rows on the 4th, 06/07/08:00 CT. Replaces the Excel "Actuals" recompute. (jcardinal)
@@ -3,12 +3,14 @@ title: "Tow Foundation"
3
3
  framework: "2.0"
4
4
  apps:
5
5
  - worker2
6
+ - tools
7
+ - dbchanges2
6
8
  project: Worker
7
9
  client: tow-foundation
8
10
  type: profile
9
11
  status: active
10
- updated: 2026-06-11
11
- owners: ["rgirish"]
12
+ updated: 2026-08-04
13
+ owners: ["rgirish", "jcardinal"]
12
14
  files: []
13
15
  related:
14
16
  - clients/tow-foundation/features/receipt-processing.md
@@ -23,6 +25,23 @@ and exported as QuickBooks-ready Excel files.
23
25
 
24
26
  No client database is used (no persistence beyond SharePoint and email).
25
27
 
28
+ ## Talos Pricing — first external client
29
+
30
+ Tow Foundation is the **first real external Talos client** (`clientIdentifier` `Towfoundation`).
31
+ A contract was created and signed through the tools Contracts page on 2026-08-03.
32
+
33
+ **Open issue — no token extract exists for this org.** `/api/usage/overview` returns 83
34
+ messages / 10 conversations / 2 users for `ytd` but `tokens = 0` and `cost = $0`, and nothing
35
+ at all in the last 30 days; their tagged AWS spend was **$0.0016** for July, far too low for
36
+ 83 real questions. The activity counters and the token/cost extract are separate sources with
37
+ their own `token_data_as_of` high-water mark, and the extract appears never to have run for
38
+ this org — "Refresh token data" does not populate it. The Talos Postgres DB the weekly report
39
+ queries is named `tenant_true`, hinting at per-tenant databases; if the extract job points at
40
+ that one DB, no refresh will ever produce Tow Foundation tokens. With the Talos backend
41
+ developer. Until it is fixed, this client has **no measurable usage and no real margin
42
+ figure**. See
43
+ [talos-pricing-automation](../../2.0/apps/worker2/features/talos-pricing-automation.md).
44
+
26
45
  ## Contacts
27
46
 
28
47
  - **Jheanelle Gordon** — primary contact; receives the processing completion email
@@ -11,7 +11,7 @@ project: _Underscore
11
11
  client: true
12
12
  type: profile
13
13
  status: active
14
- updated: 2026-07-24
14
+ updated: 2026-08-04
15
15
  owners: [jcardinal, kyalamarthi]
16
16
  files: []
17
17
  related:
@@ -39,3 +39,15 @@ The **Tools** app (1.0; repo `tools`) authenticates True users via **SSO** throu
39
39
  staff persona (see `1.0/apps/tools/`). Its gateway return domain is registered in `Core.Domains`
40
40
  (`uuid 2927bc15-e347-4358-a430-fb28f9446d27`, `clientId 1`, `appId 30`, env 1,
41
41
  `https://tools.togatech.com/sso`).
42
+
43
+ ### Talos Pricing — the internal tenant
44
+
45
+ True is an **internal tenant** in the Talos Pricing platform (`TalosClients.isInternal = 1`,
46
+ formal name **TOGA Technology**), not a paying client. It holds nearly all Talos usage and,
47
+ via `defaultTenant`, all untagged AWS Bedrock spend, so it **must** exist as a contract row
48
+ or there is no platform unit price at all. It is **costed and feeds the unit price** but is
49
+ **excluded from fee recommendations** — modelling it as a zero-revenue contract made margin
50
+ compute as 0%, parking it permanently in "Needs attention" and dragging blended portfolio
51
+ margin negative. A contract row was created and signed 2026-08-03. Measured July 2026:
52
+ $549.18 tagged of a $1,013.76 total. See
53
+ [talos-pricing-automation](../../2.0/apps/worker2/features/talos-pricing-automation.md).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.507",
3
+ "version": "1.0.508",
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",