2222from decimal import ROUND_HALF_UP , Decimal
2323from pathlib import Path
2424
25+ from rle .tracking .cost_tracker import is_pareto_cost_source
26+
2527# Display name / family / family swatch per model slug, mirroring the palette
2628# in AppSprout-Site client/src/rle/data.ts. Unknown slugs fall back to a
2729# derived family + neutral color with a warning, so a new model never blocks
4345}
4446FALLBACK_COLOR = "#B7AC8B"
4547
48+ # Optional published-pack backfill (Site may apply later). Not live-metered
49+ # here and not fetched from any API — values from the n1-final pack review:
50+ # CLI coding-agent harness estimated $1.594858 from 796917 tokens; Felix keep
51+ # billed $0.857296; ACP console ~$7; raw = unknown / omit from cost Pareto.
52+ PACK_COST_BACKFILL : dict [str , dict [str , object ]] = {
53+ "cli-agent" : {
54+ "cost_usd" : 1.594858 ,
55+ "cost_source" : "estimated" ,
56+ "note" : "796917 tokens; pricing slug was openrouter/x-ai/grok-4.6" ,
57+ },
58+ "felix" : {
59+ "cost_usd" : 0.857296 ,
60+ "cost_source" : "billed" ,
61+ },
62+ "acp" : {
63+ "cost_usd" : 7.0 ,
64+ "cost_source" : "console" ,
65+ "note" : "n1-final console ~$7" ,
66+ },
67+ "raw-grok" : {
68+ "cost_usd" : None ,
69+ "cost_source" : "unknown" ,
70+ "note" : "omit from cost Pareto" ,
71+ },
72+ }
73+
4674GITHUB_URL = "https://github.com/AppSprout-dev/RLE"
4775GITHUB_REPO = "AppSprout-dev/RLE"
4876DISCORD_URL = "https://discord.gg/vKuyjqNEea"
@@ -69,11 +97,30 @@ def registry_entry(slug: str) -> tuple[str, str, str]:
6997 return slug , family , FALLBACK_COLOR
7098
7199
100+ def _row_cost_source (row : dict ) -> str :
101+ raw = row .get ("cost_source" )
102+ return str (raw ) if raw else "unknown"
103+
104+
72105def build_model (row : dict ) -> dict :
73106 slug = row ["model" ]
74107 display , family , color = registry_entry (slug )
75- real = row .get ("real_cost_usd" )
76- cost = real if real is not None else row ["est_cost_usd" ]
108+ source = _row_cost_source (row )
109+ eligible = bool (row .get ("pareto_eligible" , is_pareto_cost_source (source )))
110+ # Prefer the analyze-spread authoritative figure; never fall back to
111+ # unknown $0 (that used to land CLI/ACP/raw rows on the Site Pareto).
112+ display_cost = row .get ("display_cost_usd" )
113+ if display_cost is None and eligible :
114+ real = row .get ("real_cost_usd" )
115+ console = row .get ("console_cost_usd" )
116+ if source == "billed" and real is not None :
117+ display_cost = real
118+ elif source == "console" and console is not None :
119+ display_cost = console
120+ elif source == "estimated" :
121+ display_cost = row .get ("est_cost_usd" )
122+ if not eligible :
123+ display_cost = None
77124 return {
78125 "slug" : slug ,
79126 "key" : row ["name" ],
@@ -89,13 +136,24 @@ def build_model(row: dict) -> dict:
89136 "exArtifactSuccess" : rnd (row ["ex_artifact_success" ], 2 ),
90137 "avgLatencyS" : rnd (row ["avg_latency_s" ], 1 ),
91138 "wallMin" : rnd (row ["wall_min" ], 1 ),
92- "costUsd" : rnd (cost , 2 ),
93- "costEstimated" : real is None ,
139+ "costUsd" : rnd (display_cost , 2 ) if display_cost is not None else None ,
140+ "costEstimated" : source == "estimated" ,
141+ "costSource" : source ,
142+ "paretoEligible" : eligible and display_cost is not None ,
94143 }
95144
96145
97146def build_meta (board : dict , rows : list [dict ], args : argparse .Namespace ) -> dict :
98- metered = [r ["real_cost_usd" ] for r in board ["rows" ] if r .get ("real_cost_usd" ) is not None ]
147+ metered : list [float ] = []
148+ for r in board ["rows" ]:
149+ source = _row_cost_source (r )
150+ if source not in ("billed" , "console" ):
151+ continue
152+ amount = r .get ("real_cost_usd" ) if source == "billed" else r .get ("console_cost_usd" )
153+ if amount is None :
154+ amount = r .get ("display_cost_usd" )
155+ if amount is not None :
156+ metered .append (float (amount ))
99157 ticks = max ((len (r .get ("trajectory" , [])) for r in board ["rows" ]), default = 0 )
100158 return {
101159 "scenario" : args .scenario ,
@@ -127,8 +185,8 @@ def emit_ts(meta: dict, models: list[dict], spread_dir: Path) -> str:
127185 f" ticks: { meta ['ticks' ]} ," ,
128186 f" nRuns: { meta ['nRuns' ]} ," ,
129187 f' date: "{ meta ["date" ]} ",' ,
130- " // OpenRouter spend for the metered models; subscription-billed models " ,
131- " // (costEstimated: true) are not included ." ,
188+ " // Billed + console spend; estimated/unknown rows are not included. " ,
189+ " // Plot Pareto only when costSource is billed|estimated|console ." ,
132190 f" totalSpendUsd: { fmt (meta ['totalSpendUsd' ], 2 )} ," ,
133191 f" baselineMeanTteDays: { meta ['baselineMeanTteDays' ]} ," ,
134192 f' githubUrl: "{ meta ["githubUrl" ]} ",' ,
@@ -151,8 +209,10 @@ def emit_ts(meta: dict, models: list[dict], spread_dir: Path) -> str:
151209 f" endDay: { m ['endDay' ]} , rawActionSuccess: { fmt (m ['rawActionSuccess' ], 2 )} ,"
152210 f" exArtifactSuccess: { fmt (m ['exArtifactSuccess' ], 2 )} ,"
153211 f" avgLatencyS: { fmt (m ['avgLatencyS' ], 1 )} , wallMin: { fmt (m ['wallMin' ], 1 )} ," ,
154- f" costUsd: { fmt (m ['costUsd' ], 2 )} ,"
155- f" costEstimated: { 'true' if m ['costEstimated' ] else 'false' } ," ,
212+ f" costUsd: { fmt (m ['costUsd' ], 2 ) if m ['costUsd' ] is not None else 'null' } ,"
213+ f" costEstimated: { 'true' if m ['costEstimated' ] else 'false' } ,"
214+ f" costSource: \" { m ['costSource' ]} \" ,"
215+ f" paretoEligible: { 'true' if m ['paretoEligible' ] else 'false' } ," ,
156216 " }," ,
157217 ]
158218 lines += ["];" , "" ]
@@ -185,7 +245,10 @@ def main() -> None:
185245
186246 json_path = out / "site_data.json"
187247 json_path .write_text (
188- json .dumps ({"meta" : meta , "models" : models }, indent = 2 ) + "\n " ,
248+ json .dumps (
249+ {"meta" : meta , "models" : models , "costBackfill" : PACK_COST_BACKFILL },
250+ indent = 2 ,
251+ ) + "\n " ,
189252 encoding = "utf-8" )
190253
191254 print (f"Wrote { ts_path } " )
0 commit comments