You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Bootstrap the relayburn-analyze crate. This lands the scaffolding plus the three foundational modules that nearly every other analyze submodule consumes: pricing tables, per-record cost derivation, and the fidelity summary used to gate aggregations on input quality.
Scope
Crate scaffold
Set up crates/relayburn-analyze/src/lib.rs with module declarations and the public re-export surface mirroring packages/analyze/src/index.ts (modules will be filled in by the follow-up sub-issues — for this PR, only pricing, cost, and fidelity are wired up).
Add relayburn-reader as a path dep (already in workspace).
Decide on the canonical numeric type for USD cost. TS uses number (f64); use f64 in Rust to keep arithmetic equivalent, but document the 1e-9 USD precision contract that the overhead sub-issue will need to honor.
pricing.rs (port of packages/analyze/src/pricing.ts, ~100 LoC)
Port ModelCost, PricingTable, ReasoningMode types with serde::Deserialize.
Port flatten(), loadBuiltinPricing(), loadPricing(override_path). The vendored models.dev.json snapshot from packages/analyze/data/ ships embedded via include_str! so the binary stays self-contained.
loadPricing should accept an optional override path, falling back to the bundled snapshot.
cost.rs (port of packages/analyze/src/cost.ts, ~136 LoC)
Port CostBreakdown, CostForUsageOptions types.
Port costForUsage(), costForTurn(turn, pricing), lookupModelRate(model, pricing), sumCosts(costs).
The costForTurn math (per-token rate × token count, with cache-read / cache-create / reasoning splits) is the precision-sensitive core — keep f64 ordering identical to TS so accumulation drift stays bounded.
fidelity.rs (port of packages/analyze/src/fidelity.ts, ~107 LoC)
Port FidelitySummary struct, emptyFidelitySummary(), summarizeFidelity(), hasMinimumFidelity().
This is small but it's the predicate the higher-level aggregators (compare, hotspots) use to refuse stats on undersized fixtures, so it needs to land before them.
Conformance gate
Port these test fixtures with equivalent Rust tests:
packages/analyze/src/cost.test.ts (289 lines)
packages/analyze/src/fidelity.test.ts (146 lines)
Pricing has no dedicated *.test.ts (it's exercised transitively by cost). The bundled models.dev.json snapshot must produce identical PricingTable lookups vs the TS path.
Parent: #244
Depends on: #242 (reader types)
Context
Bootstrap the
relayburn-analyzecrate. This lands the scaffolding plus the three foundational modules that nearly every other analyze submodule consumes: pricing tables, per-record cost derivation, and the fidelity summary used to gate aggregations on input quality.Scope
Crate scaffold
crates/relayburn-analyze/src/lib.rswith module declarations and the public re-export surface mirroringpackages/analyze/src/index.ts(modules will be filled in by the follow-up sub-issues — for this PR, onlypricing,cost, andfidelityare wired up).relayburn-readeras a path dep (already in workspace).number(f64); usef64in Rust to keep arithmetic equivalent, but document the 1e-9 USD precision contract that the overhead sub-issue will need to honor.pricing.rs(port ofpackages/analyze/src/pricing.ts, ~100 LoC)ModelCost,PricingTable,ReasoningModetypes withserde::Deserialize.flatten(),loadBuiltinPricing(),loadPricing(override_path). The vendoredmodels.dev.jsonsnapshot frompackages/analyze/data/ships embedded viainclude_str!so the binary stays self-contained.loadPricingshould accept an optional override path, falling back to the bundled snapshot.cost.rs(port ofpackages/analyze/src/cost.ts, ~136 LoC)CostBreakdown,CostForUsageOptionstypes.costForUsage(),costForTurn(turn, pricing),lookupModelRate(model, pricing),sumCosts(costs).costForTurnmath (per-token rate × token count, with cache-read / cache-create / reasoning splits) is the precision-sensitive core — keep f64 ordering identical to TS so accumulation drift stays bounded.fidelity.rs(port ofpackages/analyze/src/fidelity.ts, ~107 LoC)FidelitySummarystruct,emptyFidelitySummary(),summarizeFidelity(),hasMinimumFidelity().Conformance gate
Port these test fixtures with equivalent Rust tests:
packages/analyze/src/cost.test.ts(289 lines)packages/analyze/src/fidelity.test.ts(146 lines)Pricing has no dedicated
*.test.ts(it's exercised transitively by cost). The bundledmodels.dev.jsonsnapshot must produce identicalPricingTablelookups vs the TS path.Acceptance
cargo build -p relayburn-analyzegreen; crate exportspricing,cost,fidelitymodules.cargo test -p relayburn-analyzegreen for the cost + fidelity test ports.costForTurnoutput matches TS to within 1e-12 USD on the cost-test fixture corpus (the headroom for the 1e-9 overhead gate later).models.dev.jsonsnapshot is embedded; no runtime file dep.loadBuiltinPricing,loadPricing,flatten,costForTurn,costForUsage,sumCosts,lookupModelRate,emptyFidelitySummary,summarizeFidelity,hasMinimumFidelityplus the listed types.Files (TS source-of-truth)
packages/analyze/src/pricing.tspackages/analyze/src/cost.ts+cost.test.tspackages/analyze/src/fidelity.ts+fidelity.test.tspackages/analyze/data/models.dev.json(bundled)