roadmodel 0.2.67__tar.gz → 0.2.69__tar.gz

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.
Files changed (55) hide show
  1. {roadmodel-0.2.67 → roadmodel-0.2.69}/PKG-INFO +1 -1
  2. {roadmodel-0.2.67 → roadmodel-0.2.69}/docs/benchmarks.json +48 -48
  3. {roadmodel-0.2.67 → roadmodel-0.2.69}/docs/catalog.json +4 -4
  4. {roadmodel-0.2.67 → roadmodel-0.2.69}/docs/model-selector.txt +4 -3
  5. {roadmodel-0.2.67 → roadmodel-0.2.69}/pyproject.toml +1 -1
  6. {roadmodel-0.2.67 → roadmodel-0.2.69}/roadmodel/data/benchmarks.json +48 -48
  7. {roadmodel-0.2.67 → roadmodel-0.2.69}/roadmodel/data/catalog.json +4 -4
  8. {roadmodel-0.2.67 → roadmodel-0.2.69}/roadmodel/data/model-selector.txt +4 -3
  9. {roadmodel-0.2.67 → roadmodel-0.2.69}/scripts/updater_lock.py +70 -8
  10. {roadmodel-0.2.67 → roadmodel-0.2.69}/src/roadmodel/__init__.py +1 -1
  11. {roadmodel-0.2.67 → roadmodel-0.2.69}/src/roadmodel/scoring.py +27 -10
  12. {roadmodel-0.2.67 → roadmodel-0.2.69}/.gitignore +0 -0
  13. {roadmodel-0.2.67 → roadmodel-0.2.69}/LICENSE +0 -0
  14. {roadmodel-0.2.67 → roadmodel-0.2.69}/NOTICE +0 -0
  15. {roadmodel-0.2.67 → roadmodel-0.2.69}/README.md +0 -0
  16. {roadmodel-0.2.67 → roadmodel-0.2.69}/docs/model-tier-cost-scale.md +0 -0
  17. {roadmodel-0.2.67 → roadmodel-0.2.69}/docs/settings-display.md +0 -0
  18. {roadmodel-0.2.67 → roadmodel-0.2.69}/docs/templates/phase-roadmap-template.md +0 -0
  19. {roadmodel-0.2.67 → roadmodel-0.2.69}/docs/templates/planning-kit-how-to-use.md +0 -0
  20. {roadmodel-0.2.67 → roadmodel-0.2.69}/docs/templates/project-roadmap-template.md +0 -0
  21. {roadmodel-0.2.67 → roadmodel-0.2.69}/docs/templates/prompt-phase-roadmap.md +0 -0
  22. {roadmodel-0.2.67 → roadmodel-0.2.69}/docs/templates/prompt-project-roadmap.md +0 -0
  23. {roadmodel-0.2.67 → roadmodel-0.2.69}/docs/user-context.example.md +0 -0
  24. {roadmodel-0.2.67 → roadmodel-0.2.69}/hatch_build.py +0 -0
  25. {roadmodel-0.2.67 → roadmodel-0.2.69}/infra/README.md +0 -0
  26. {roadmodel-0.2.67 → roadmodel-0.2.69}/infra/gcp-killswitch/README.md +0 -0
  27. {roadmodel-0.2.67 → roadmodel-0.2.69}/infra/supabase/README.md +0 -0
  28. {roadmodel-0.2.67 → roadmodel-0.2.69}/roadmodel/data/model-tier-cost-scale.md +0 -0
  29. {roadmodel-0.2.67 → roadmodel-0.2.69}/roadmodel/data/phase-roadmap-template.md +0 -0
  30. {roadmodel-0.2.67 → roadmodel-0.2.69}/roadmodel/data/planning-kit-how-to-use.md +0 -0
  31. {roadmodel-0.2.67 → roadmodel-0.2.69}/roadmodel/data/project-roadmap-template.md +0 -0
  32. {roadmodel-0.2.67 → roadmodel-0.2.69}/roadmodel/data/prompt-phase-roadmap.md +0 -0
  33. {roadmodel-0.2.67 → roadmodel-0.2.69}/roadmodel/data/prompt-project-roadmap.md +0 -0
  34. {roadmodel-0.2.67 → roadmodel-0.2.69}/roadmodel/data/settings-display.md +0 -0
  35. {roadmodel-0.2.67 → roadmodel-0.2.69}/roadmodel/data/user-context.example.md +0 -0
  36. {roadmodel-0.2.67 → roadmodel-0.2.69}/scripts/agent_context.py +0 -0
  37. {roadmodel-0.2.67 → roadmodel-0.2.69}/scripts/agent_rules.py +0 -0
  38. {roadmodel-0.2.67 → roadmodel-0.2.69}/scripts/update_projects.py +0 -0
  39. {roadmodel-0.2.67 → roadmodel-0.2.69}/scripts/upgrade_fleet.py +0 -0
  40. {roadmodel-0.2.67 → roadmodel-0.2.69}/scripts/worktree_memory.py +0 -0
  41. {roadmodel-0.2.67 → roadmodel-0.2.69}/src/roadmodel/__main__.py +0 -0
  42. {roadmodel-0.2.67 → roadmodel-0.2.69}/src/roadmodel/cli.py +0 -0
  43. {roadmodel-0.2.67 → roadmodel-0.2.69}/src/roadmodel/config.py +0 -0
  44. {roadmodel-0.2.67 → roadmodel-0.2.69}/src/roadmodel/cost.py +0 -0
  45. {roadmodel-0.2.67 → roadmodel-0.2.69}/src/roadmodel/errors.py +0 -0
  46. {roadmodel-0.2.67 → roadmodel-0.2.69}/src/roadmodel/mcp_server.py +0 -0
  47. {roadmodel-0.2.67 → roadmodel-0.2.69}/src/roadmodel/providers/__init__.py +0 -0
  48. {roadmodel-0.2.67 → roadmodel-0.2.69}/src/roadmodel/providers/anthropic.py +0 -0
  49. {roadmodel-0.2.67 → roadmodel-0.2.69}/src/roadmodel/providers/google.py +0 -0
  50. {roadmodel-0.2.67 → roadmodel-0.2.69}/src/roadmodel/providers/openai.py +0 -0
  51. {roadmodel-0.2.67 → roadmodel-0.2.69}/src/roadmodel/providers/openai_compatible.py +0 -0
  52. {roadmodel-0.2.67 → roadmodel-0.2.69}/src/roadmodel/providers/registry.py +0 -0
  53. {roadmodel-0.2.67 → roadmodel-0.2.69}/src/roadmodel/recommend.py +0 -0
  54. {roadmodel-0.2.67 → roadmodel-0.2.69}/src/roadmodel/usage.py +0 -0
  55. {roadmodel-0.2.67 → roadmodel-0.2.69}/src/roadmodel/user_context.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: roadmodel
3
- Version: 0.2.67
3
+ Version: 0.2.69
4
4
  Summary: BYO-key CLI that recommends the right AI model, platform, and settings for a prompt.
5
5
  Project-URL: Homepage, https://roadmodel.ai
6
6
  Project-URL: Repository, https://github.com/nathanramoscfa/roadmodel
@@ -6,7 +6,7 @@
6
6
  "endpoint": "https://artificialanalysis.ai/api/v2/data/llms/models",
7
7
  "attribution": "Benchmark data © Artificial Analysis, used under its API terms with attribution."
8
8
  },
9
- "generated_at_utc": "2026-10-05T22:11:00Z",
9
+ "generated_at_utc": "2026-10-06T22:11:12Z",
10
10
  "model_count": 54,
11
11
  "unmapped": [],
12
12
  "missing_slugs": [],
@@ -38,8 +38,8 @@
38
38
  "tau2": 0.546783625730994,
39
39
  "tau_banking": 0.0927835051546392
40
40
  },
41
- "median_output_tokens_per_second": 107.429,
42
- "median_time_to_first_token_seconds": 7.79
41
+ "median_output_tokens_per_second": 98.659,
42
+ "median_time_to_first_token_seconds": 7.086
43
43
  },
44
44
  "claude-fable-5": {
45
45
  "aa_id": "cd55210d-358e-4df1-ba9c-9acb5f186cc9",
@@ -96,8 +96,8 @@
96
96
  "tau2": null,
97
97
  "tau_banking": 0.472164948453608
98
98
  },
99
- "median_output_tokens_per_second": 68.612,
100
- "median_time_to_first_token_seconds": 145.612
99
+ "median_output_tokens_per_second": 69.251,
100
+ "median_time_to_first_token_seconds": 140.452
101
101
  },
102
102
  "claude-opus-5": {
103
103
  "aa_id": "b8fc61f7-5e9a-49e6-8547-6ac56db24627",
@@ -154,8 +154,8 @@
154
154
  "tau2": null,
155
155
  "tau_banking": null
156
156
  },
157
- "median_output_tokens_per_second": 96.593,
158
- "median_time_to_first_token_seconds": 489.353
157
+ "median_output_tokens_per_second": 96.823,
158
+ "median_time_to_first_token_seconds": 470.118
159
159
  },
160
160
  "claude-sonnet-5": {
161
161
  "aa_id": "23c86e4a-c769-43c0-a056-79e3cd15834f",
@@ -212,7 +212,7 @@
212
212
  "tau2": null,
213
213
  "tau_banking": null
214
214
  },
215
- "median_output_tokens_per_second": 137.507,
215
+ "median_output_tokens_per_second": 137.452,
216
216
  "median_time_to_first_token_seconds": 269.765
217
217
  },
218
218
  "deepseek-flash": {
@@ -241,8 +241,8 @@
241
241
  "tau2": null,
242
242
  "tau_banking": null
243
243
  },
244
- "median_output_tokens_per_second": 214.176,
245
- "median_time_to_first_token_seconds": 0.802
244
+ "median_output_tokens_per_second": 211.532,
245
+ "median_time_to_first_token_seconds": 0.838
246
246
  },
247
247
  "deepseek-v4-pro": {
248
248
  "aa_id": "83173329-c09a-41f1-a028-a282a5f908d7",
@@ -270,8 +270,8 @@
270
270
  "tau2": null,
271
271
  "tau_banking": 0.395876288659794
272
272
  },
273
- "median_output_tokens_per_second": 103.076,
274
- "median_time_to_first_token_seconds": 1.112
273
+ "median_output_tokens_per_second": 94.405,
274
+ "median_time_to_first_token_seconds": 1.116
275
275
  },
276
276
  "gemini-2.5-flash": {
277
277
  "aa_id": "219ed587-60c5-4a48-9517-8480e08d0ca1",
@@ -386,8 +386,8 @@
386
386
  "tau2": 0.956140350877193,
387
387
  "tau_banking": 0.214432989690722
388
388
  },
389
- "median_output_tokens_per_second": 123.821,
390
- "median_time_to_first_token_seconds": 15.32
389
+ "median_output_tokens_per_second": 120.916,
390
+ "median_time_to_first_token_seconds": 16.499
391
391
  },
392
392
  "gemini-3.5-flash": {
393
393
  "aa_id": "0097ebf5-124f-42f6-9463-33b00e711f03",
@@ -502,8 +502,8 @@
502
502
  "tau2": null,
503
503
  "tau_banking": 0.449484536082474
504
504
  },
505
- "median_output_tokens_per_second": 223.213,
506
- "median_time_to_first_token_seconds": 9.822
505
+ "median_output_tokens_per_second": 193.352,
506
+ "median_time_to_first_token_seconds": 11.478
507
507
  },
508
508
  "glm-4.5-air": {
509
509
  "aa_id": "5d303dc9-c027-401f-9803-4e9aa3331007",
@@ -618,8 +618,8 @@
618
618
  "tau2": null,
619
619
  "tau_banking": 0.503092783505155
620
620
  },
621
- "median_output_tokens_per_second": 75.232,
622
- "median_time_to_first_token_seconds": 3.1
621
+ "median_output_tokens_per_second": 74.56,
622
+ "median_time_to_first_token_seconds": 2.696
623
623
  },
624
624
  "glm-5.3-flash": {
625
625
  "aa_id": "19496b81-9f41-4214-a77a-1df803b3c5ae",
@@ -647,8 +647,8 @@
647
647
  "tau2": null,
648
648
  "tau_banking": 0.472164948453608
649
649
  },
650
- "median_output_tokens_per_second": 49.967,
651
- "median_time_to_first_token_seconds": 2.638
650
+ "median_output_tokens_per_second": 48.776,
651
+ "median_time_to_first_token_seconds": 2.773
652
652
  },
653
653
  "gpt-5": {
654
654
  "aa_id": "48e50f00-1fd1-4acc-b337-61078aa341e6",
@@ -850,8 +850,8 @@
850
850
  "tau2": 0.859649122807018,
851
851
  "tau_banking": null
852
852
  },
853
- "median_output_tokens_per_second": 102.301,
854
- "median_time_to_first_token_seconds": 34.347
853
+ "median_output_tokens_per_second": 94.067,
854
+ "median_time_to_first_token_seconds": 34.541
855
855
  },
856
856
  "gpt-5.4": {
857
857
  "aa_id": "a89c4b28-2d8c-456e-88ea-255fb51fd2b6",
@@ -1053,8 +1053,8 @@
1053
1053
  "tau2": 0.862573099415205,
1054
1054
  "tau_banking": 0.402061855670103
1055
1055
  },
1056
- "median_output_tokens_per_second": 116.052,
1057
- "median_time_to_first_token_seconds": 82.187
1056
+ "median_output_tokens_per_second": 103.757,
1057
+ "median_time_to_first_token_seconds": 83.831
1058
1058
  },
1059
1059
  "gpt-6-astra": {
1060
1060
  "aa_id": "2f339a97-9a0d-499a-9cb5-e0db665bfa25",
@@ -1082,8 +1082,8 @@
1082
1082
  "tau2": null,
1083
1083
  "tau_banking": 0.414432989690722
1084
1084
  },
1085
- "median_output_tokens_per_second": 64.764,
1086
- "median_time_to_first_token_seconds": 191.318
1085
+ "median_output_tokens_per_second": 50.735,
1086
+ "median_time_to_first_token_seconds": 205.366
1087
1087
  },
1088
1088
  "gpt-6-luna": {
1089
1089
  "aa_id": "6fb13851-40ce-4bda-ad3f-6b38e0c5daa7",
@@ -1111,8 +1111,8 @@
1111
1111
  "tau2": null,
1112
1112
  "tau_banking": null
1113
1113
  },
1114
- "median_output_tokens_per_second": 135.654,
1115
- "median_time_to_first_token_seconds": 75.426
1114
+ "median_output_tokens_per_second": 133.905,
1115
+ "median_time_to_first_token_seconds": 68.659
1116
1116
  },
1117
1117
  "gpt-6-sol": {
1118
1118
  "aa_id": "c50ea08c-88c0-4eb7-85b8-27f2bbf6d527",
@@ -1169,8 +1169,8 @@
1169
1169
  "tau2": null,
1170
1170
  "tau_banking": null
1171
1171
  },
1172
- "median_output_tokens_per_second": 60.455,
1173
- "median_time_to_first_token_seconds": 157.396
1172
+ "median_output_tokens_per_second": 57.423,
1173
+ "median_time_to_first_token_seconds": 179.839
1174
1174
  },
1175
1175
  "gpt-oss-120b": {
1176
1176
  "aa_id": "f0083258-8646-45b8-8082-7aaf6c2ea82a",
@@ -1198,8 +1198,8 @@
1198
1198
  "tau2": 0.657894736842105,
1199
1199
  "tau_banking": 0.127835051546392
1200
1200
  },
1201
- "median_output_tokens_per_second": 199.818,
1202
- "median_time_to_first_token_seconds": 0.501
1201
+ "median_output_tokens_per_second": 186.012,
1202
+ "median_time_to_first_token_seconds": 0.502
1203
1203
  },
1204
1204
  "gpt-oss-20b": {
1205
1205
  "aa_id": "36f73aaf-d38a-4b56-a2b3-d04d17186910",
@@ -1227,8 +1227,8 @@
1227
1227
  "tau2": 0.60233918128655,
1228
1228
  "tau_banking": 0.0701030927835052
1229
1229
  },
1230
- "median_output_tokens_per_second": 227.873,
1231
- "median_time_to_first_token_seconds": 0.427
1230
+ "median_output_tokens_per_second": 231.256,
1231
+ "median_time_to_first_token_seconds": 0.412
1232
1232
  },
1233
1233
  "grok-4.3": {
1234
1234
  "aa_id": "948892b5-db03-4118-a4a8-ccd51ed871ea",
@@ -1314,8 +1314,8 @@
1314
1314
  "tau2": null,
1315
1315
  "tau_banking": null
1316
1316
  },
1317
- "median_output_tokens_per_second": 72.511,
1318
- "median_time_to_first_token_seconds": 9.66
1317
+ "median_output_tokens_per_second": 69.431,
1318
+ "median_time_to_first_token_seconds": 8.037
1319
1319
  },
1320
1320
  "kimi-k2.7-code": {
1321
1321
  "aa_id": "8d0cb231-7303-452c-9923-a9620b948475",
@@ -1343,8 +1343,8 @@
1343
1343
  "tau2": 0.900584795321637,
1344
1344
  "tau_banking": 0.202061855670103
1345
1345
  },
1346
- "median_output_tokens_per_second": 105.681,
1347
- "median_time_to_first_token_seconds": 1.142
1346
+ "median_output_tokens_per_second": 83.243,
1347
+ "median_time_to_first_token_seconds": 1.298
1348
1348
  },
1349
1349
  "kimi-k3": {
1350
1350
  "aa_id": "f7d2fc3e-1f7b-405f-818c-07952a4af78f",
@@ -1372,8 +1372,8 @@
1372
1372
  "tau2": null,
1373
1373
  "tau_banking": 0.45979381443299
1374
1374
  },
1375
- "median_output_tokens_per_second": 45.199,
1376
- "median_time_to_first_token_seconds": 2.455
1375
+ "median_output_tokens_per_second": 45.073,
1376
+ "median_time_to_first_token_seconds": 2.953
1377
1377
  },
1378
1378
  "mistral-large-3": {
1379
1379
  "aa_id": "4928e950-7f37-4475-b0dc-c5bad781a321",
@@ -1401,8 +1401,8 @@
1401
1401
  "tau2": 0.245614035087719,
1402
1402
  "tau_banking": 0.0577319587628866
1403
1403
  },
1404
- "median_output_tokens_per_second": 79.265,
1405
- "median_time_to_first_token_seconds": 0.692
1404
+ "median_output_tokens_per_second": 79.072,
1405
+ "median_time_to_first_token_seconds": 0.688
1406
1406
  },
1407
1407
  "mistral-medium-3.5": {
1408
1408
  "aa_id": "dd059b25-d82a-4ead-82a4-4adceaaec48b",
@@ -1430,8 +1430,8 @@
1430
1430
  "tau2": 0.941520467836257,
1431
1431
  "tau_banking": 0.150515463917526
1432
1432
  },
1433
- "median_output_tokens_per_second": 168.037,
1434
- "median_time_to_first_token_seconds": 0.6
1433
+ "median_output_tokens_per_second": 162.625,
1434
+ "median_time_to_first_token_seconds": 0.595
1435
1435
  },
1436
1436
  "mistral-small-4": {
1437
1437
  "aa_id": "3fd96175-4ef1-434c-8795-f873aec2abc1",
@@ -1459,8 +1459,8 @@
1459
1459
  "tau2": 0.412280701754386,
1460
1460
  "tau_banking": 0.0494845360824742
1461
1461
  },
1462
- "median_output_tokens_per_second": 171.598,
1463
- "median_time_to_first_token_seconds": 0.559
1462
+ "median_output_tokens_per_second": 163.865,
1463
+ "median_time_to_first_token_seconds": 0.542
1464
1464
  },
1465
1465
  "muse-spark-1.3": {
1466
1466
  "aa_id": "9999672c-b687-4026-9c15-5cef02ff53bb",
@@ -1488,8 +1488,8 @@
1488
1488
  "tau2": null,
1489
1489
  "tau_banking": 0.505154639175258
1490
1490
  },
1491
- "median_output_tokens_per_second": 122.652,
1492
- "median_time_to_first_token_seconds": 28.442
1491
+ "median_output_tokens_per_second": 115.306,
1492
+ "median_time_to_first_token_seconds": 26.027
1493
1493
  },
1494
1494
  "opus-4.7": {
1495
1495
  "aa_id": "e9a09db3-8fd6-41dd-ba2f-20e0a2bff7f2",
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "schema_version": "4",
3
3
  "output_contract_version": 2,
4
- "generated_at_utc": "2026-10-06T20:14:04Z",
4
+ "generated_at_utc": "2026-10-06T22:11:12Z",
5
5
  "source_doc_sha256": {
6
- "model-selector.txt": "b7abeb92fb4d9b85b70a4544369a49de103d5695bf6dd77ea996dc4e85db0a31",
6
+ "model-selector.txt": "c18d9168548b6079ffe7e75cf891691b7ef3a2bfaa296dcd9a596f1e0a69e1ed",
7
7
  "model-tier-cost-scale.md": "2b3b0eb82237eb5cb5bf468a3fe971bcaf0160ad7d0bc700698d2c16640bc41d"
8
8
  },
9
9
  "models": [
@@ -24,7 +24,7 @@
24
24
  "speed": "S"
25
25
  },
26
26
  "jurisdiction": "us",
27
- "headline_benchmarks": "AA Intelligence Index 16.9 (reasoning); Output Speed 122.5 tokens/s; AA-Omniscience -4.2; latency leader among Claude family",
27
+ "headline_benchmarks": "AA Intelligence Index 16.9 (reasoning); HLE 10.4%; SciCode 42.2; Terminal-Bench 4.0 0.0; AA-LCR 0.743; Output Speed 98.7 tokens/s; AA-Omniscience -4.2; latency leader among Claude family",
28
28
  "pricing_notes": "Hidden by default; Bedrock/Vertex: regional endpoints +10% surcharge; Cache: writes 1.25x, reads 0.1x",
29
29
  "best_for": "Speed-optimized lowest-cost Claude model, ideal for simple completions, high-volume repetitive tasks, and latency-sensitive workflows where a lightweight capable response matters more than deep reasoning",
30
30
  "superseded_by": null,
@@ -474,7 +474,7 @@
474
474
  "speed": "S"
475
475
  },
476
476
  "jurisdiction": "us",
477
- "headline_benchmarks": "AA Intelligence Index 40.9 (high); HLE 47.8% (high); Terminal-Bench 2.1 87.6; Output Speed 237.7 tokens/s",
477
+ "headline_benchmarks": "AA Intelligence Index 40.9 (high); HLE 47.8%; SciCode 56.6; Terminal-Bench 4.0 19.7; AA-LCR 0.813; Terminal-Bench 2.1 87.6; Output Speed 193.4 tokens/s",
478
478
  "pricing_notes": "-",
479
479
  "best_for": "Frontier-class multimodal input, plus strong coding, planning, agentic work, long context and knowledge, with very fast output, at a low price. Its AA Intelligence Index of 40.9 ranks 18th of 54 measured models.",
480
480
  "superseded_by": null,
@@ -1252,9 +1252,9 @@
1252
1252
  tier-coding="A" tier-planning="A" tier-agentic="A"
1253
1253
  tier-multimodal="S" tier-long-context="A" tier-knowledge="A"
1254
1254
  tier-speed="S"
1255
- headline-benchmarks="AA Intelligence Index 40.9 (high); HLE 47.8% (high); Terminal-Bench 2.1 87.6; Output Speed 237.7 tokens/s"
1255
+ headline-benchmarks="AA Intelligence Index 40.9 (high); HLE 47.8%; SciCode 56.6; Terminal-Bench 4.0 19.7; AA-LCR 0.813; Terminal-Bench 2.1 87.6; Output Speed 193.4 tokens/s"
1256
1256
  pricing-notes="-"
1257
- prose-generated="best-for"
1257
+ prose-generated="best-for headline-benchmarks"
1258
1258
  best-for="Frontier-class multimodal input, plus strong coding, planning, agentic work, long context and knowledge, with very fast output, at a low price. Its AA Intelligence Index of 40.9 ranks 18th of 54 measured models." />
1259
1259
  <model id="gpt-5.6-luna" name="GPT-5.6 Luna"
1260
1260
  input-price-per-1m="$0.20" output-price-per-1m="$1.20"
@@ -1281,8 +1281,9 @@
1281
1281
  tier-coding="C" tier-planning="C" tier-agentic="D"
1282
1282
  tier-multimodal="B" tier-long-context="A" tier-knowledge="D"
1283
1283
  tier-speed="S"
1284
- headline-benchmarks="AA Intelligence Index 16.9 (reasoning); Output Speed 122.5 tokens/s; AA-Omniscience -4.2; latency leader among Claude family"
1284
+ headline-benchmarks="AA Intelligence Index 16.9 (reasoning); HLE 10.4%; SciCode 42.2; Terminal-Bench 4.0 0.0; AA-LCR 0.743; Output Speed 98.7 tokens/s; AA-Omniscience -4.2; latency leader among Claude family"
1285
1285
  pricing-notes="Hidden by default; Bedrock/Vertex: regional endpoints +10% surcharge; Cache: writes 1.25x, reads 0.1x"
1286
+ prose-generated="headline-benchmarks"
1286
1287
  best-for="Speed-optimized lowest-cost Claude model, ideal for simple completions, high-volume repetitive tasks, and latency-sensitive workflows where a lightweight capable response matters more than deep reasoning" />
1287
1288
  <model id="muse-spark-1.3" name="Muse Spark 1.3"
1288
1289
  input-price-per-1m="$1.25" output-price-per-1m="$4.25"
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "roadmodel"
7
- version = "0.2.67"
7
+ version = "0.2.69"
8
8
  description = "BYO-key CLI that recommends the right AI model, platform, and settings for a prompt."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -6,7 +6,7 @@
6
6
  "endpoint": "https://artificialanalysis.ai/api/v2/data/llms/models",
7
7
  "attribution": "Benchmark data © Artificial Analysis, used under its API terms with attribution."
8
8
  },
9
- "generated_at_utc": "2026-10-05T22:11:00Z",
9
+ "generated_at_utc": "2026-10-06T22:11:12Z",
10
10
  "model_count": 54,
11
11
  "unmapped": [],
12
12
  "missing_slugs": [],
@@ -38,8 +38,8 @@
38
38
  "tau2": 0.546783625730994,
39
39
  "tau_banking": 0.0927835051546392
40
40
  },
41
- "median_output_tokens_per_second": 107.429,
42
- "median_time_to_first_token_seconds": 7.79
41
+ "median_output_tokens_per_second": 98.659,
42
+ "median_time_to_first_token_seconds": 7.086
43
43
  },
44
44
  "claude-fable-5": {
45
45
  "aa_id": "cd55210d-358e-4df1-ba9c-9acb5f186cc9",
@@ -96,8 +96,8 @@
96
96
  "tau2": null,
97
97
  "tau_banking": 0.472164948453608
98
98
  },
99
- "median_output_tokens_per_second": 68.612,
100
- "median_time_to_first_token_seconds": 145.612
99
+ "median_output_tokens_per_second": 69.251,
100
+ "median_time_to_first_token_seconds": 140.452
101
101
  },
102
102
  "claude-opus-5": {
103
103
  "aa_id": "b8fc61f7-5e9a-49e6-8547-6ac56db24627",
@@ -154,8 +154,8 @@
154
154
  "tau2": null,
155
155
  "tau_banking": null
156
156
  },
157
- "median_output_tokens_per_second": 96.593,
158
- "median_time_to_first_token_seconds": 489.353
157
+ "median_output_tokens_per_second": 96.823,
158
+ "median_time_to_first_token_seconds": 470.118
159
159
  },
160
160
  "claude-sonnet-5": {
161
161
  "aa_id": "23c86e4a-c769-43c0-a056-79e3cd15834f",
@@ -212,7 +212,7 @@
212
212
  "tau2": null,
213
213
  "tau_banking": null
214
214
  },
215
- "median_output_tokens_per_second": 137.507,
215
+ "median_output_tokens_per_second": 137.452,
216
216
  "median_time_to_first_token_seconds": 269.765
217
217
  },
218
218
  "deepseek-flash": {
@@ -241,8 +241,8 @@
241
241
  "tau2": null,
242
242
  "tau_banking": null
243
243
  },
244
- "median_output_tokens_per_second": 214.176,
245
- "median_time_to_first_token_seconds": 0.802
244
+ "median_output_tokens_per_second": 211.532,
245
+ "median_time_to_first_token_seconds": 0.838
246
246
  },
247
247
  "deepseek-v4-pro": {
248
248
  "aa_id": "83173329-c09a-41f1-a028-a282a5f908d7",
@@ -270,8 +270,8 @@
270
270
  "tau2": null,
271
271
  "tau_banking": 0.395876288659794
272
272
  },
273
- "median_output_tokens_per_second": 103.076,
274
- "median_time_to_first_token_seconds": 1.112
273
+ "median_output_tokens_per_second": 94.405,
274
+ "median_time_to_first_token_seconds": 1.116
275
275
  },
276
276
  "gemini-2.5-flash": {
277
277
  "aa_id": "219ed587-60c5-4a48-9517-8480e08d0ca1",
@@ -386,8 +386,8 @@
386
386
  "tau2": 0.956140350877193,
387
387
  "tau_banking": 0.214432989690722
388
388
  },
389
- "median_output_tokens_per_second": 123.821,
390
- "median_time_to_first_token_seconds": 15.32
389
+ "median_output_tokens_per_second": 120.916,
390
+ "median_time_to_first_token_seconds": 16.499
391
391
  },
392
392
  "gemini-3.5-flash": {
393
393
  "aa_id": "0097ebf5-124f-42f6-9463-33b00e711f03",
@@ -502,8 +502,8 @@
502
502
  "tau2": null,
503
503
  "tau_banking": 0.449484536082474
504
504
  },
505
- "median_output_tokens_per_second": 223.213,
506
- "median_time_to_first_token_seconds": 9.822
505
+ "median_output_tokens_per_second": 193.352,
506
+ "median_time_to_first_token_seconds": 11.478
507
507
  },
508
508
  "glm-4.5-air": {
509
509
  "aa_id": "5d303dc9-c027-401f-9803-4e9aa3331007",
@@ -618,8 +618,8 @@
618
618
  "tau2": null,
619
619
  "tau_banking": 0.503092783505155
620
620
  },
621
- "median_output_tokens_per_second": 75.232,
622
- "median_time_to_first_token_seconds": 3.1
621
+ "median_output_tokens_per_second": 74.56,
622
+ "median_time_to_first_token_seconds": 2.696
623
623
  },
624
624
  "glm-5.3-flash": {
625
625
  "aa_id": "19496b81-9f41-4214-a77a-1df803b3c5ae",
@@ -647,8 +647,8 @@
647
647
  "tau2": null,
648
648
  "tau_banking": 0.472164948453608
649
649
  },
650
- "median_output_tokens_per_second": 49.967,
651
- "median_time_to_first_token_seconds": 2.638
650
+ "median_output_tokens_per_second": 48.776,
651
+ "median_time_to_first_token_seconds": 2.773
652
652
  },
653
653
  "gpt-5": {
654
654
  "aa_id": "48e50f00-1fd1-4acc-b337-61078aa341e6",
@@ -850,8 +850,8 @@
850
850
  "tau2": 0.859649122807018,
851
851
  "tau_banking": null
852
852
  },
853
- "median_output_tokens_per_second": 102.301,
854
- "median_time_to_first_token_seconds": 34.347
853
+ "median_output_tokens_per_second": 94.067,
854
+ "median_time_to_first_token_seconds": 34.541
855
855
  },
856
856
  "gpt-5.4": {
857
857
  "aa_id": "a89c4b28-2d8c-456e-88ea-255fb51fd2b6",
@@ -1053,8 +1053,8 @@
1053
1053
  "tau2": 0.862573099415205,
1054
1054
  "tau_banking": 0.402061855670103
1055
1055
  },
1056
- "median_output_tokens_per_second": 116.052,
1057
- "median_time_to_first_token_seconds": 82.187
1056
+ "median_output_tokens_per_second": 103.757,
1057
+ "median_time_to_first_token_seconds": 83.831
1058
1058
  },
1059
1059
  "gpt-6-astra": {
1060
1060
  "aa_id": "2f339a97-9a0d-499a-9cb5-e0db665bfa25",
@@ -1082,8 +1082,8 @@
1082
1082
  "tau2": null,
1083
1083
  "tau_banking": 0.414432989690722
1084
1084
  },
1085
- "median_output_tokens_per_second": 64.764,
1086
- "median_time_to_first_token_seconds": 191.318
1085
+ "median_output_tokens_per_second": 50.735,
1086
+ "median_time_to_first_token_seconds": 205.366
1087
1087
  },
1088
1088
  "gpt-6-luna": {
1089
1089
  "aa_id": "6fb13851-40ce-4bda-ad3f-6b38e0c5daa7",
@@ -1111,8 +1111,8 @@
1111
1111
  "tau2": null,
1112
1112
  "tau_banking": null
1113
1113
  },
1114
- "median_output_tokens_per_second": 135.654,
1115
- "median_time_to_first_token_seconds": 75.426
1114
+ "median_output_tokens_per_second": 133.905,
1115
+ "median_time_to_first_token_seconds": 68.659
1116
1116
  },
1117
1117
  "gpt-6-sol": {
1118
1118
  "aa_id": "c50ea08c-88c0-4eb7-85b8-27f2bbf6d527",
@@ -1169,8 +1169,8 @@
1169
1169
  "tau2": null,
1170
1170
  "tau_banking": null
1171
1171
  },
1172
- "median_output_tokens_per_second": 60.455,
1173
- "median_time_to_first_token_seconds": 157.396
1172
+ "median_output_tokens_per_second": 57.423,
1173
+ "median_time_to_first_token_seconds": 179.839
1174
1174
  },
1175
1175
  "gpt-oss-120b": {
1176
1176
  "aa_id": "f0083258-8646-45b8-8082-7aaf6c2ea82a",
@@ -1198,8 +1198,8 @@
1198
1198
  "tau2": 0.657894736842105,
1199
1199
  "tau_banking": 0.127835051546392
1200
1200
  },
1201
- "median_output_tokens_per_second": 199.818,
1202
- "median_time_to_first_token_seconds": 0.501
1201
+ "median_output_tokens_per_second": 186.012,
1202
+ "median_time_to_first_token_seconds": 0.502
1203
1203
  },
1204
1204
  "gpt-oss-20b": {
1205
1205
  "aa_id": "36f73aaf-d38a-4b56-a2b3-d04d17186910",
@@ -1227,8 +1227,8 @@
1227
1227
  "tau2": 0.60233918128655,
1228
1228
  "tau_banking": 0.0701030927835052
1229
1229
  },
1230
- "median_output_tokens_per_second": 227.873,
1231
- "median_time_to_first_token_seconds": 0.427
1230
+ "median_output_tokens_per_second": 231.256,
1231
+ "median_time_to_first_token_seconds": 0.412
1232
1232
  },
1233
1233
  "grok-4.3": {
1234
1234
  "aa_id": "948892b5-db03-4118-a4a8-ccd51ed871ea",
@@ -1314,8 +1314,8 @@
1314
1314
  "tau2": null,
1315
1315
  "tau_banking": null
1316
1316
  },
1317
- "median_output_tokens_per_second": 72.511,
1318
- "median_time_to_first_token_seconds": 9.66
1317
+ "median_output_tokens_per_second": 69.431,
1318
+ "median_time_to_first_token_seconds": 8.037
1319
1319
  },
1320
1320
  "kimi-k2.7-code": {
1321
1321
  "aa_id": "8d0cb231-7303-452c-9923-a9620b948475",
@@ -1343,8 +1343,8 @@
1343
1343
  "tau2": 0.900584795321637,
1344
1344
  "tau_banking": 0.202061855670103
1345
1345
  },
1346
- "median_output_tokens_per_second": 105.681,
1347
- "median_time_to_first_token_seconds": 1.142
1346
+ "median_output_tokens_per_second": 83.243,
1347
+ "median_time_to_first_token_seconds": 1.298
1348
1348
  },
1349
1349
  "kimi-k3": {
1350
1350
  "aa_id": "f7d2fc3e-1f7b-405f-818c-07952a4af78f",
@@ -1372,8 +1372,8 @@
1372
1372
  "tau2": null,
1373
1373
  "tau_banking": 0.45979381443299
1374
1374
  },
1375
- "median_output_tokens_per_second": 45.199,
1376
- "median_time_to_first_token_seconds": 2.455
1375
+ "median_output_tokens_per_second": 45.073,
1376
+ "median_time_to_first_token_seconds": 2.953
1377
1377
  },
1378
1378
  "mistral-large-3": {
1379
1379
  "aa_id": "4928e950-7f37-4475-b0dc-c5bad781a321",
@@ -1401,8 +1401,8 @@
1401
1401
  "tau2": 0.245614035087719,
1402
1402
  "tau_banking": 0.0577319587628866
1403
1403
  },
1404
- "median_output_tokens_per_second": 79.265,
1405
- "median_time_to_first_token_seconds": 0.692
1404
+ "median_output_tokens_per_second": 79.072,
1405
+ "median_time_to_first_token_seconds": 0.688
1406
1406
  },
1407
1407
  "mistral-medium-3.5": {
1408
1408
  "aa_id": "dd059b25-d82a-4ead-82a4-4adceaaec48b",
@@ -1430,8 +1430,8 @@
1430
1430
  "tau2": 0.941520467836257,
1431
1431
  "tau_banking": 0.150515463917526
1432
1432
  },
1433
- "median_output_tokens_per_second": 168.037,
1434
- "median_time_to_first_token_seconds": 0.6
1433
+ "median_output_tokens_per_second": 162.625,
1434
+ "median_time_to_first_token_seconds": 0.595
1435
1435
  },
1436
1436
  "mistral-small-4": {
1437
1437
  "aa_id": "3fd96175-4ef1-434c-8795-f873aec2abc1",
@@ -1459,8 +1459,8 @@
1459
1459
  "tau2": 0.412280701754386,
1460
1460
  "tau_banking": 0.0494845360824742
1461
1461
  },
1462
- "median_output_tokens_per_second": 171.598,
1463
- "median_time_to_first_token_seconds": 0.559
1462
+ "median_output_tokens_per_second": 163.865,
1463
+ "median_time_to_first_token_seconds": 0.542
1464
1464
  },
1465
1465
  "muse-spark-1.3": {
1466
1466
  "aa_id": "9999672c-b687-4026-9c15-5cef02ff53bb",
@@ -1488,8 +1488,8 @@
1488
1488
  "tau2": null,
1489
1489
  "tau_banking": 0.505154639175258
1490
1490
  },
1491
- "median_output_tokens_per_second": 122.652,
1492
- "median_time_to_first_token_seconds": 28.442
1491
+ "median_output_tokens_per_second": 115.306,
1492
+ "median_time_to_first_token_seconds": 26.027
1493
1493
  },
1494
1494
  "opus-4.7": {
1495
1495
  "aa_id": "e9a09db3-8fd6-41dd-ba2f-20e0a2bff7f2",
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "schema_version": "4",
3
3
  "output_contract_version": 2,
4
- "generated_at_utc": "2026-10-06T20:14:04Z",
4
+ "generated_at_utc": "2026-10-06T22:11:12Z",
5
5
  "source_doc_sha256": {
6
- "model-selector.txt": "b7abeb92fb4d9b85b70a4544369a49de103d5695bf6dd77ea996dc4e85db0a31",
6
+ "model-selector.txt": "c18d9168548b6079ffe7e75cf891691b7ef3a2bfaa296dcd9a596f1e0a69e1ed",
7
7
  "model-tier-cost-scale.md": "2b3b0eb82237eb5cb5bf468a3fe971bcaf0160ad7d0bc700698d2c16640bc41d"
8
8
  },
9
9
  "models": [
@@ -24,7 +24,7 @@
24
24
  "speed": "S"
25
25
  },
26
26
  "jurisdiction": "us",
27
- "headline_benchmarks": "AA Intelligence Index 16.9 (reasoning); Output Speed 122.5 tokens/s; AA-Omniscience -4.2; latency leader among Claude family",
27
+ "headline_benchmarks": "AA Intelligence Index 16.9 (reasoning); HLE 10.4%; SciCode 42.2; Terminal-Bench 4.0 0.0; AA-LCR 0.743; Output Speed 98.7 tokens/s; AA-Omniscience -4.2; latency leader among Claude family",
28
28
  "pricing_notes": "Hidden by default; Bedrock/Vertex: regional endpoints +10% surcharge; Cache: writes 1.25x, reads 0.1x",
29
29
  "best_for": "Speed-optimized lowest-cost Claude model, ideal for simple completions, high-volume repetitive tasks, and latency-sensitive workflows where a lightweight capable response matters more than deep reasoning",
30
30
  "superseded_by": null,
@@ -474,7 +474,7 @@
474
474
  "speed": "S"
475
475
  },
476
476
  "jurisdiction": "us",
477
- "headline_benchmarks": "AA Intelligence Index 40.9 (high); HLE 47.8% (high); Terminal-Bench 2.1 87.6; Output Speed 237.7 tokens/s",
477
+ "headline_benchmarks": "AA Intelligence Index 40.9 (high); HLE 47.8%; SciCode 56.6; Terminal-Bench 4.0 19.7; AA-LCR 0.813; Terminal-Bench 2.1 87.6; Output Speed 193.4 tokens/s",
478
478
  "pricing_notes": "-",
479
479
  "best_for": "Frontier-class multimodal input, plus strong coding, planning, agentic work, long context and knowledge, with very fast output, at a low price. Its AA Intelligence Index of 40.9 ranks 18th of 54 measured models.",
480
480
  "superseded_by": null,
@@ -1252,9 +1252,9 @@
1252
1252
  tier-coding="A" tier-planning="A" tier-agentic="A"
1253
1253
  tier-multimodal="S" tier-long-context="A" tier-knowledge="A"
1254
1254
  tier-speed="S"
1255
- headline-benchmarks="AA Intelligence Index 40.9 (high); HLE 47.8% (high); Terminal-Bench 2.1 87.6; Output Speed 237.7 tokens/s"
1255
+ headline-benchmarks="AA Intelligence Index 40.9 (high); HLE 47.8%; SciCode 56.6; Terminal-Bench 4.0 19.7; AA-LCR 0.813; Terminal-Bench 2.1 87.6; Output Speed 193.4 tokens/s"
1256
1256
  pricing-notes="-"
1257
- prose-generated="best-for"
1257
+ prose-generated="best-for headline-benchmarks"
1258
1258
  best-for="Frontier-class multimodal input, plus strong coding, planning, agentic work, long context and knowledge, with very fast output, at a low price. Its AA Intelligence Index of 40.9 ranks 18th of 54 measured models." />
1259
1259
  <model id="gpt-5.6-luna" name="GPT-5.6 Luna"
1260
1260
  input-price-per-1m="$0.20" output-price-per-1m="$1.20"
@@ -1281,8 +1281,9 @@
1281
1281
  tier-coding="C" tier-planning="C" tier-agentic="D"
1282
1282
  tier-multimodal="B" tier-long-context="A" tier-knowledge="D"
1283
1283
  tier-speed="S"
1284
- headline-benchmarks="AA Intelligence Index 16.9 (reasoning); Output Speed 122.5 tokens/s; AA-Omniscience -4.2; latency leader among Claude family"
1284
+ headline-benchmarks="AA Intelligence Index 16.9 (reasoning); HLE 10.4%; SciCode 42.2; Terminal-Bench 4.0 0.0; AA-LCR 0.743; Output Speed 98.7 tokens/s; AA-Omniscience -4.2; latency leader among Claude family"
1285
1285
  pricing-notes="Hidden by default; Bedrock/Vertex: regional endpoints +10% surcharge; Cache: writes 1.25x, reads 0.1x"
1286
+ prose-generated="headline-benchmarks"
1286
1287
  best-for="Speed-optimized lowest-cost Claude model, ideal for simple completions, high-volume repetitive tasks, and latency-sensitive workflows where a lightweight capable response matters more than deep reasoning" />
1287
1288
  <model id="muse-spark-1.3" name="Muse Spark 1.3"
1288
1289
  input-price-per-1m="$1.25" output-price-per-1m="$4.25"
@@ -1,9 +1,9 @@
1
1
  """One advisory updater lock per machine, with explicit child handover.
2
2
 
3
3
  The installed launcher holds the operating-system lock while a synchronously
4
- invoked replacement updater runs. Its direct child can identify that ownership
5
- through a random inherited token and owner PID. No project or rule data is
6
- stored in the persistent, harmless lock file.
4
+ invoked replacement updater runs. Its child can identify that ownership through
5
+ a random inherited token and owner PID, including Windows venv redirectors
6
+ between the processes. No project or rule data is stored in the lock file.
7
7
  """
8
8
 
9
9
  from __future__ import annotations
@@ -52,18 +52,79 @@ def _release(stream: BinaryIO) -> None:
52
52
  fcntl.flock(stream.fileno(), fcntl.LOCK_UN)
53
53
 
54
54
 
55
+ def _windows_process_parents() -> dict[int, int]:
56
+ """Return a native process snapshot without starting another interpreter.
57
+
58
+ A Windows venv's python.exe is a redirector which launches the base Python
59
+ as its child. The updater owner therefore need not be os.getppid().
60
+ """
61
+ import ctypes
62
+ from ctypes import wintypes
63
+
64
+ class ProcessEntry(ctypes.Structure):
65
+ _fields_ = [
66
+ ("dwSize", wintypes.DWORD),
67
+ ("cntUsage", wintypes.DWORD),
68
+ ("th32ProcessID", wintypes.DWORD),
69
+ ("th32DefaultHeapID", ctypes.c_size_t),
70
+ ("th32ModuleID", wintypes.DWORD),
71
+ ("cntThreads", wintypes.DWORD),
72
+ ("th32ParentProcessID", wintypes.DWORD),
73
+ ("pcPriClassBase", wintypes.LONG),
74
+ ("dwFlags", wintypes.DWORD),
75
+ ("szExeFile", wintypes.WCHAR * 260),
76
+ ]
77
+
78
+ kernel = ctypes.WinDLL("kernel32", use_last_error=True)
79
+ kernel.CreateToolhelp32Snapshot.argtypes = [wintypes.DWORD, wintypes.DWORD]
80
+ kernel.CreateToolhelp32Snapshot.restype = wintypes.HANDLE
81
+ for name in ("Process32FirstW", "Process32NextW"):
82
+ function = getattr(kernel, name)
83
+ function.argtypes = [wintypes.HANDLE, ctypes.POINTER(ProcessEntry)]
84
+ function.restype = wintypes.BOOL
85
+ kernel.CloseHandle.argtypes = [wintypes.HANDLE]
86
+ kernel.CloseHandle.restype = wintypes.BOOL
87
+ snapshot = kernel.CreateToolhelp32Snapshot(0x00000002, 0) # TH32CS_SNAPPROCESS
88
+ if snapshot == ctypes.c_void_p(-1).value:
89
+ raise ctypes.WinError(ctypes.get_last_error())
90
+ try:
91
+ entry = ProcessEntry()
92
+ entry.dwSize = ctypes.sizeof(entry)
93
+ parents: dict[int, int] = {}
94
+ found = kernel.Process32FirstW(snapshot, ctypes.byref(entry))
95
+ while found:
96
+ parents[entry.th32ProcessID] = entry.th32ParentProcessID
97
+ found = kernel.Process32NextW(snapshot, ctypes.byref(entry))
98
+ return parents
99
+ finally:
100
+ kernel.CloseHandle(snapshot)
101
+
102
+
103
+ def _owner_is_ancestor(pid: int) -> bool:
104
+ if pid == os.getpid():
105
+ return True
106
+ if not _WINDOWS:
107
+ return pid == os.getppid()
108
+ parents = _windows_process_parents()
109
+ current = os.getpid()
110
+ seen: set[int] = set()
111
+ while current in parents and current not in seen:
112
+ if current == pid:
113
+ return True
114
+ seen.add(current)
115
+ current = parents[current]
116
+ return False
117
+
118
+
55
119
  def _inherited_owner(stream: BinaryIO) -> bool:
56
120
  token = os.environ.get(LOCK_TOKEN_ENV)
57
121
  owner_pid = os.environ.get(LOCK_PID_ENV)
58
122
  if not token or not owner_pid:
59
123
  return False
60
124
  try:
61
- # Handover is deliberately limited to a direct child (or reentrant
62
- # use by the owner). A stale token in an unrelated shell is not proof
63
- # that the lock holder will remain alive throughout this operation.
125
+ # Match the record before checking ancestry. A token copied into an
126
+ # unrelated shell is insufficient, as is a PID for a departed owner.
64
127
  pid = int(owner_pid)
65
- if pid not in (os.getpid(), os.getppid()):
66
- return False
67
128
  stream.seek(1) # Windows locks byte zero; owner metadata is after it.
68
129
  state = json.loads(stream.read().decode("utf-8"))
69
130
  return (
@@ -73,6 +134,7 @@ def _inherited_owner(stream: BinaryIO) -> bool:
73
134
  and state["pid"] == pid
74
135
  and isinstance(state.get("token"), str)
75
136
  and secrets.compare_digest(state["token"], token)
137
+ and _owner_is_ancestor(pid)
76
138
  )
77
139
  except (OSError, ValueError, TypeError):
78
140
  return False
@@ -1,2 +1,2 @@
1
1
  # src/roadmodel/__init__.py
2
- __version__ = "0.2.67"
2
+ __version__ = "0.2.69"
@@ -913,6 +913,10 @@ def rank(
913
913
  pj = str(method.get("provider_jurisdiction", "us")).lower()
914
914
  if pj != "local" and pj not in juris:
915
915
  continue # `local` runs on the operator's hardware: passes every list
916
+ if task.category == "speed" and str(method.get("billing", "")) == "local":
917
+ # Speed evidence is the hosted providers' measured throughput;
918
+ # the operator's own hardware runs at its own, unmeasured pace.
919
+ continue
916
920
  funding, state, scarcity, note = _funding_for(
917
921
  _cost._with_model(method, model_id),
918
922
  cat,
@@ -1210,9 +1214,12 @@ def ladder(
1210
1214
  category stands alone.
1211
1215
  - QUALITY is the adequate point that scores highest in the category (then
1212
1216
  the higher AA Index, then the cheaper). COST is the cheapest adequate
1213
- point. BALANCED is the point strictly between them with the best score
1214
- at the balanced posture; with none between, the COST or QUALITY model at
1215
- the balanced posture's effort, whichever differs from both other rungs.
1217
+ point the operator has already paid for (a subscription with headroom,
1218
+ or local weights); a per-token point takes COST only when no prepaid
1219
+ point is adequate. BALANCED is the point strictly between them, stronger
1220
+ than COST in the task's category, with the best score at the balanced
1221
+ posture; with none, the COST or QUALITY model at the balanced posture's
1222
+ effort, whichever differs from both other rungs.
1216
1223
  - Each rung runs at :func:`effort_for` its posture (cheap / balanced /
1217
1224
  best), set on its platform's own dial (:func:`native_level`) where the
1218
1225
  catalog documents one. A lower rung on the same model and platform as
@@ -1265,24 +1272,34 @@ def ladder(
1265
1272
  def same(a: Rung, b: Rung) -> bool:
1266
1273
  return a.candidate.model_id == b.candidate.model_id and a.level == b.level
1267
1274
 
1268
- cost_rung = rung("cost", span[0])
1275
+ # COST is the cheapest adequate point already paid for: a subscription pool
1276
+ # with headroom or local weights (scarcity below list price) costs the
1277
+ # operator nothing new, while a per-token call is fresh spend.
1278
+ cost_point = next((p for p in span if p.candidate.scarcity < 1.0), span[0])
1279
+ lo = span.index(cost_point)
1280
+ cost_rung = rung("cost", cost_point)
1269
1281
  quality_rung = (
1270
1282
  replace(rung("quality", specialist), specialist=True)
1271
1283
  if specialist is not None
1272
1284
  else rung("quality", top)
1273
1285
  )
1274
1286
  # With a specialist on QUALITY, BALANCED spans every adequate frontier point
1275
- # above COST, the frontier's strongest included.
1276
- between = span[1:] if specialist is not None else span[1:-1]
1287
+ # above COST, the frontier's strongest included. A BALANCED point earns its
1288
+ # higher price only by beating COST in the task's own category: the
1289
+ # frontier is drawn on the AA Index, and a point above COST on that axis
1290
+ # can still trail it in the category the task needs.
1291
+ between = span[lo + 1 :] if specialist is not None else span[lo + 1 : -1]
1292
+ between = [p for p in between if p.candidate.quality > cost_point.candidate.quality]
1277
1293
  if between:
1278
1294
  balanced_rung = rung(
1279
1295
  "balanced", max(between, key=lambda p: (p.candidate.score, -p.price_usd))
1280
1296
  )
1281
1297
  else:
1282
- # Two adequate points or one: BALANCED runs one of them at the balanced
1283
- # posture, whichever differs from both other rungs; it converges only
1284
- # when neither does. Beside a specialist it stays on the frontier.
1285
- options = [rung("balanced", span[0])]
1298
+ # No point between COST and QUALITY beats COST in the category:
1299
+ # BALANCED runs one of those two at the balanced posture, whichever
1300
+ # differs from both other rungs; it converges only when neither does.
1301
+ # Beside a specialist it stays on the frontier.
1302
+ options = [rung("balanced", cost_point)]
1286
1303
  if specialist is None:
1287
1304
  options.append(rung("balanced", top))
1288
1305
  balanced_rung = next(
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes