cctally 1.113.0 → 1.115.0

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 (97) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.md +4 -6
  3. package/bin/_cctally_account.py +32 -8
  4. package/bin/_cctally_cache.py +6035 -722
  5. package/bin/_cctally_completion.py +1287 -0
  6. package/bin/_cctally_config.py +37 -0
  7. package/bin/_cctally_core.py +400 -2
  8. package/bin/_cctally_dashboard.py +98 -20
  9. package/bin/_cctally_dashboard_conversation.py +292 -23
  10. package/bin/_cctally_dashboard_envelope.py +16 -3
  11. package/bin/_cctally_dashboard_perf.py +128 -9
  12. package/bin/_cctally_dashboard_sources.py +285 -213
  13. package/bin/_cctally_db.py +1177 -23
  14. package/bin/_cctally_diagnosis_sources.py +22 -4
  15. package/bin/_cctally_doctor.py +572 -45
  16. package/bin/_cctally_five_hour.py +84 -33
  17. package/bin/_cctally_forecast.py +108 -15
  18. package/bin/_cctally_journal.py +3950 -116
  19. package/bin/_cctally_journal_repair.py +101 -12
  20. package/bin/_cctally_milestone_history.py +82 -9
  21. package/bin/_cctally_parser.py +42 -0
  22. package/bin/_cctally_percent_breakdown.py +3 -2
  23. package/bin/_cctally_project.py +8 -2
  24. package/bin/_cctally_quarantine.py +652 -0
  25. package/bin/_cctally_quota.py +227 -37
  26. package/bin/_cctally_quota_model.py +360 -83
  27. package/bin/_cctally_record.py +691 -149
  28. package/bin/_cctally_rederive.py +320 -41
  29. package/bin/_cctally_refresh.py +84 -13
  30. package/bin/_cctally_source_analytics.py +83 -17
  31. package/bin/_cctally_statusline.py +6154 -517
  32. package/bin/_cctally_store.py +367 -53
  33. package/bin/_cctally_transcript.py +8 -7
  34. package/bin/_cctally_tui.py +61 -56
  35. package/bin/_cctally_weekrefs.py +128 -21
  36. package/bin/_lib_account_binding.py +152 -0
  37. package/bin/_lib_account_protocol.py +386 -0
  38. package/bin/_lib_aggregators.py +4 -0
  39. package/bin/_lib_cache_coverage.py +13 -1
  40. package/bin/_lib_cache_report.py +35 -6
  41. package/bin/_lib_cache_writer_lock.py +19 -3
  42. package/bin/_lib_clone_copy.py +142 -0
  43. package/bin/_lib_codex_conversation.py +32 -0
  44. package/bin/_lib_codex_conversation_query.py +297 -49
  45. package/bin/_lib_codex_conversation_watch.py +59 -14
  46. package/bin/_lib_codex_drain_admission.py +214 -0
  47. package/bin/_lib_codex_metadata.py +18 -1
  48. package/bin/_lib_codex_publication_barrier.py +277 -0
  49. package/bin/_lib_codex_rollout_container.py +502 -0
  50. package/bin/_lib_conversation_dispatch.py +3 -0
  51. package/bin/_lib_conversation_query.py +106 -59
  52. package/bin/_lib_conversation_retention.py +1605 -640
  53. package/bin/_lib_cost_provenance.py +53 -2
  54. package/bin/_lib_detector_access_registry.py +3817 -0
  55. package/bin/_lib_doctor.py +714 -69
  56. package/bin/_lib_five_hour.py +126 -0
  57. package/bin/_lib_fmt.py +11 -0
  58. package/bin/_lib_ingest_frontier.py +414 -20
  59. package/bin/_lib_journal.py +141 -10
  60. package/bin/_lib_jsonl.py +5 -4
  61. package/bin/_lib_legacy_spool.py +126 -0
  62. package/bin/_lib_legacy_writer_evidence.py +136 -0
  63. package/bin/_lib_merge_gate.py +231 -86
  64. package/bin/_lib_meter_rate_change.py +10 -0
  65. package/bin/_lib_outcome_quarantine.py +690 -0
  66. package/bin/_lib_perf.py +27 -1
  67. package/bin/_lib_pricing.py +199 -9
  68. package/bin/_lib_pricing_check.py +20 -4
  69. package/bin/_lib_quarantine.py +154 -0
  70. package/bin/_lib_quota_calibration.py +53 -8
  71. package/bin/_lib_quota_copy.py +2 -1
  72. package/bin/_lib_quota_model.py +288 -46
  73. package/bin/_lib_reclaim_planner.py +792 -0
  74. package/bin/_lib_rederive.py +319 -82
  75. package/bin/_lib_segment_summary.py +35 -2
  76. package/bin/_lib_snapshot_cache.py +21 -0
  77. package/bin/_lib_sqlite_close.py +81 -0
  78. package/bin/_lib_statusline_candidates.py +292 -23
  79. package/bin/_lib_subscription_weeks.py +100 -17
  80. package/bin/_lib_tick_stats.py +217 -17
  81. package/bin/_lib_wal_checkpoint.py +1077 -0
  82. package/bin/_lib_write_budget.py +483 -0
  83. package/bin/_lib_write_io.py +703 -0
  84. package/bin/cctally +31 -1
  85. package/dashboard/static/assets/{ConversationsView-CEZ-BUyi.js → ConversationsView-Bc8LCOAZ.js} +1 -1
  86. package/dashboard/static/assets/{DoctorModal-CE1oH_Zy.js → DoctorModal-D--qVBwe.js} +1 -1
  87. package/dashboard/static/assets/ModalRoot-DLPgyAM_.js +1 -0
  88. package/dashboard/static/assets/{ProjectsDrillPanel-B3DZoCeD.js → ProjectsDrillPanel-z53a4v4M.js} +1 -1
  89. package/dashboard/static/assets/{SourceDetailModal-CHp9EgLP.js → SourceDetailModal-Bw0T8W-W.js} +1 -1
  90. package/dashboard/static/assets/{UpdateModal-5iKST6jo.js → UpdateModal-D5AKx4Yw.js} +1 -1
  91. package/dashboard/static/assets/index-BKITk1CT.css +1 -0
  92. package/dashboard/static/assets/{index-Cm0VTxJC.js → index-BXDOzSng.js} +3 -3
  93. package/dashboard/static/assets/{outlineNavigation-DkXGL8J6.js → outlineNavigation-JObY7cUY.js} +1 -1
  94. package/dashboard/static/dashboard.html +2 -2
  95. package/package.json +19 -1
  96. package/dashboard/static/assets/ModalRoot-D5Y8IFUG.js +0 -1
  97. package/dashboard/static/assets/index-Dt4tqf43.css +0 -1
@@ -1984,10 +1984,12 @@ _CODEX_THREADS_BY_NATIVE_SQL = """
1984
1984
  # reading `cache_create_tokens` off `session_entries` carries the split
1985
1985
  # column, because a missed site does not raise and does not move a golden — it
1986
1986
  # silently under-prices — and this map is one keystroke away from feeding a
1987
- # cost fold.
1987
+ # cost fold. `input_tokens` (#929) is appended LAST so the existing row
1988
+ # indexes stay valid: a flagged turn's wasted estimate selects its pricing card
1989
+ # from the request's real prompt, input + creation + read.
1988
1990
  _CLAUDE_TURN_TOKENS_SQL = (
1989
1991
  "SELECT msg_id, req_id, cache_create_tokens, cache_read_tokens, "
1990
- " cache_create_1h_tokens, speed "
1992
+ " cache_create_1h_tokens, speed, input_tokens "
1991
1993
  "FROM session_entries WHERE "
1992
1994
  )
1993
1995
 
@@ -2148,7 +2150,8 @@ def _placeholders(count: int) -> str:
2148
2150
  def _claude_turn_token_map(conn: sqlite3.Connection,
2149
2151
  keys: Sequence[tuple], account_key: str | None
2150
2152
  ) -> dict[tuple, dict]:
2151
- """`{(msg_id, req_id): {"cache_creation", "cache_read", "speed"}}`.
2153
+ """`{(msg_id, req_id): {"cache_creation", "cache_read", "cache_1h",
2154
+ "speed", "input"}}`.
2152
2155
 
2153
2156
  The cache-churn walk begins BEFORE the window, and those turns are state:
2154
2157
  their tokens move the running maximum and they contribute no support,
@@ -2171,6 +2174,7 @@ def _claude_turn_token_map(conn: sqlite3.Connection,
2171
2174
  "cache_read": int(row[3] or 0),
2172
2175
  "cache_1h": row[4],
2173
2176
  "speed": row[5],
2177
+ "input": int(row[6] or 0),
2174
2178
  }
2175
2179
  return usage
2176
2180
 
@@ -2432,8 +2436,13 @@ def _evaluate_cache_churn(scope: DiagnosisScope, bundle: StoreBundle,
2432
2436
  continue
2433
2437
  flagged_keys.add(key)
2434
2438
  flagged_sessions.add(session)
2439
+ # #929: the flagged request's real prompt selects the card.
2440
+ turn = usage.get(key) or {}
2435
2441
  wasted.append(query._cache_failure_wasted_usd(
2436
- model, lost, speed=speed))
2442
+ model, lost, speed=speed,
2443
+ prompt_tokens=(turn.get("input", 0)
2444
+ + turn.get("cache_creation", 0)
2445
+ + turn.get("cache_read", 0))))
2437
2446
 
2438
2447
  known = set(all_sessions)
2439
2448
  seeded = set(streams)
@@ -4412,6 +4421,15 @@ def _start_forked_provider(args) -> tuple[int, int]:
4412
4421
  with os.fdopen(write_fd, "wb") as stream:
4413
4422
  pickle.dump(payload, stream, protocol=5)
4414
4423
  finally:
4424
+ # #901 W9 (Q14): `os._exit` skips `atexit`; a provider task that
4425
+ # synced a store hands its frames to the checkpoint policy's
4426
+ # finalizer. With nothing armed it does nothing.
4427
+ try:
4428
+ import _lib_wal_checkpoint
4429
+
4430
+ _lib_wal_checkpoint.finalize()
4431
+ except BaseException: # noqa: BLE001
4432
+ pass
4415
4433
  os._exit(0)
4416
4434
  os.close(write_fd)
4417
4435
  return pid, read_fd