Repository navigation
ADR 0004 phase 5: unify pricing resolution and offline-first catalogue refresh #10295
Description
Objective and dependencies
Implement ADR 0004 Gate 5. Parent: #10290. Blocked by Phase 3 (#10293). Can develop alongside Phase 4; refresh-triggered harness re-evaluation must integrate with Phase 4 before this phase closes. Use bounded PRs within this phase for static resolution, runtime/overlay migration, then refresh integration.
Scope
Move accounting to the shared provider/channel/deployment-scoped resolver. Resolve per component/tier using overlay → complete fresh provider observation → validated fresh central snapshot → maintained record → governed import → explicit policy fallback, with field-specific applicability rules. Preserve existing credit calculations unless an intentional correction is separately reviewed.
Represent exact decimal accounting, long-context thresholds, units/currency, cache prices, non-token charges where needed, effective dates, promotions/successors, dynamic-selector ceilings, and unpriceable-model policy. Mixed-source tariffs are assembled, with per-component provenance; fill omissions only when scope, token applicability, units, currency, and effective dates are compatible. Missing is not zero. Provider-advertised discounts stay informational and never lower maxAiCredits accounting.
Implement configurable central feed URL or local snapshot, enabled/offline mode, fetch timeout, refresh interval, maximum age, authenticated/approved transport, atomic validation, and source/schema-partitioned last-known-good cache. Source replacement must not contact the default or another unconfigured endpoint. Assume the default feed is blocked: approved operator/workflow/bundled fallback permits startup; never implicitly allowlist or bypass a denial. Pin each request's tariff/time/revision; refresh never reprices past usage. Integrate fresh harness constraints before subsequent dispatch.
Wire governed provider-qualified models.dev fallback for unsupported/custom pricing providers without requiring native adapters or runtime access to models.dev. Imported pricing does not imply execution, availability, or protocol support.
Entry points: containers/api-proxy/{ai-credits-pricing.js,provider-pricing-overlays.js,runtime-model-catalog.js,models-dev-catalog.js,guards/ai-credits-guard.js}, usage/accounting consumers, Phase 2 source config, and Phase 4 eligibility.
Acceptance criteria
- Shadow old/new pricing with old authoritative; sanitize diffs and resolve them through fixtures or explicitly approved corrections before switching.
- Tests cover precedence, incomplete tariffs, incompatible component ranges/dates/units, threshold boundaries, exact arithmetic, expiry/successors, cache estimates, and no discount-driven budget reduction.
- Cross-provider slug collisions are rejected; custom-provider import fallback and higher-priority overrides retain exact provider provenance.
- Deterministic tests cover initial fetch, periodic refresh, malformed/schema/auth failures, atomicity, source-partitioned caches, denial/timeouts, stale-age limits, and fallback/fail-closed outcomes.
- Zero feed requests in offline/local-only mode; blocked-feed startup works with approved bundled prices and no cache; custom-source failure never contacts default.
- Concurrent/in-flight requests retain tariff/revision consistency; new snapshots apply only to subsequent requests and re-evaluate harness eligibility.
- Sanitized active source/revision/age/failure/fallback traces are available for Phase 7 exports; credentials never enter logs/cache metadata.
- Root/proxy accounting and integration regressions preserve policy and budget enforcement.
Non-goals
Do not publish centrally reviewed feeds (Phase 8), infer request-level promotion eligibility, silently use expired data, or add /reflect/v2. Retain legacy adapters until Phase 9's release/parity gates.
Activity