- Shipped
- July 19, 2026 at 3:54 AM UTC
- Author
- Kamo
- Commit
- 84a3cf0
Cost accounting could never work: AiModel has price columns, AiModelController reads them and ChatOrchestrationService reads them to compute costEstimate - but NOTHING wrote them anywhere. Models are only created by provider discovery, and no provider API returns pricing. 140 models, 0 priced, no path by which that could change. The columns were structurally unreachable. Three parts: - ModelPricingCatalog seeds vendor LIST prices at discovery, matched on a normalized identifier with a hyphen-boundary prefix rule so gpt-4 can never claim gpt-4o. Non-chat models (TTS, embeddings, realtime) are rejected by reusing the existing modality check - they bill off a different sheet. - PATCH endpoint + UI so an org can correct or clear a price. Org-scoped exactly like the existing DELETE. - Backfill fills only NULL columns, per column independently, and never overwrites what an org has set - otherwise making prices editable would be a lie. Idempotent, and wrapped so cost accounting can never block boot. **A model we are not confident about gets NO price rather than a guessed one.** GPT-5, o3, most Mistral, DeepSeek, xAI, Cohere and Meta are deliberately blank; OpenRouter and HuggingFace never match by design, since they bill their own rates and inheriting upstream pricing would be a guess. A wrong price produces an invoice-shaped figure that is confidently wrong - the same reason cost is still not computed on the streaming path, where token counts are fabricated. Conversion to the per-1k column uses RoundingMode.UNNECESSARY on purpose: a price needing more than 6 decimals throws at class-init rather than silently storing a reason and is left blank. Suite is 145 tests, green.