cctally 1.114.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 (64) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/bin/_cctally_account.py +32 -8
  3. package/bin/_cctally_cache.py +4394 -279
  4. package/bin/_cctally_completion.py +1287 -0
  5. package/bin/_cctally_config.py +37 -0
  6. package/bin/_cctally_core.py +178 -2
  7. package/bin/_cctally_dashboard.py +2 -2
  8. package/bin/_cctally_dashboard_conversation.py +292 -23
  9. package/bin/_cctally_dashboard_envelope.py +16 -3
  10. package/bin/_cctally_dashboard_sources.py +18 -9
  11. package/bin/_cctally_db.py +316 -5
  12. package/bin/_cctally_doctor.py +436 -27
  13. package/bin/_cctally_five_hour.py +82 -31
  14. package/bin/_cctally_forecast.py +81 -9
  15. package/bin/_cctally_journal.py +3884 -112
  16. package/bin/_cctally_journal_repair.py +101 -12
  17. package/bin/_cctally_parser.py +42 -0
  18. package/bin/_cctally_project.py +8 -2
  19. package/bin/_cctally_quarantine.py +652 -0
  20. package/bin/_cctally_quota.py +26 -4
  21. package/bin/_cctally_quota_model.py +360 -83
  22. package/bin/_cctally_record.py +677 -149
  23. package/bin/_cctally_rederive.py +297 -32
  24. package/bin/_cctally_refresh.py +84 -13
  25. package/bin/_cctally_source_analytics.py +23 -2
  26. package/bin/_cctally_statusline.py +6137 -517
  27. package/bin/_cctally_store.py +287 -48
  28. package/bin/_cctally_transcript.py +8 -7
  29. package/bin/_cctally_tui.py +57 -53
  30. package/bin/_lib_account_binding.py +152 -0
  31. package/bin/_lib_account_protocol.py +386 -0
  32. package/bin/_lib_aggregators.py +4 -0
  33. package/bin/_lib_cache_coverage.py +13 -1
  34. package/bin/_lib_cache_writer_lock.py +19 -3
  35. package/bin/_lib_clone_copy.py +142 -0
  36. package/bin/_lib_codex_conversation_query.py +133 -19
  37. package/bin/_lib_codex_conversation_watch.py +59 -14
  38. package/bin/_lib_codex_drain_admission.py +214 -0
  39. package/bin/_lib_codex_metadata.py +18 -1
  40. package/bin/_lib_codex_publication_barrier.py +277 -0
  41. package/bin/_lib_codex_rollout_container.py +502 -0
  42. package/bin/_lib_conversation_dispatch.py +3 -0
  43. package/bin/_lib_conversation_query.py +11 -3
  44. package/bin/_lib_detector_access_registry.py +3817 -0
  45. package/bin/_lib_doctor.py +452 -1
  46. package/bin/_lib_five_hour.py +126 -0
  47. package/bin/_lib_ingest_frontier.py +414 -20
  48. package/bin/_lib_journal.py +141 -10
  49. package/bin/_lib_jsonl.py +5 -4
  50. package/bin/_lib_legacy_spool.py +126 -0
  51. package/bin/_lib_legacy_writer_evidence.py +136 -0
  52. package/bin/_lib_merge_gate.py +29 -302
  53. package/bin/_lib_meter_rate_change.py +10 -0
  54. package/bin/_lib_outcome_quarantine.py +690 -0
  55. package/bin/_lib_pricing.py +7 -2
  56. package/bin/_lib_quarantine.py +154 -0
  57. package/bin/_lib_quota_calibration.py +53 -8
  58. package/bin/_lib_quota_copy.py +2 -1
  59. package/bin/_lib_quota_model.py +288 -46
  60. package/bin/_lib_rederive.py +94 -5
  61. package/bin/_lib_segment_summary.py +35 -2
  62. package/bin/_lib_statusline_candidates.py +292 -23
  63. package/bin/cctally +23 -1
  64. package/package.json +14 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,30 @@ based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [1.115.0] - 2026-10-21
9
+
10
+ ### Added
11
+ - `cctally doctor` has two new checks: `Legacy writer` warns while an older cctally process left running across the upgrade is still writing or its status-line files cannot be read, and `Outcome quarantine` names each paused account and why.
12
+ - `cctally quota` recognises Claude Opus 5.5, Sonnet 5.5 and Haiku 5.5 and weights usage from 2026-09-22 with Opus 5.5 coefficients, fitting it when the model-mix checks pass; a week spanning that date is not modelled.
13
+
14
+ ### Changed
15
+ - The status line now records every reading under the Claude account active when it was captured, so switching accounts can no longer file one account's usage under another.
16
+ - Upgrading marks a one-time cutover: anything an older cctally process writes afterwards, including after a downgrade and re-upgrade, is kept out of your usage history. Restart such processes, usually a `cctally dashboard`.
17
+ - After an older process writes post-upgrade, credit and reset detection pauses until each account reads clean, or indefinitely if status-line files changed or are unreadable; usage still records, and `cctally record-credit` records resets.
18
+ - `cctally record-usage` exits 2 and records nothing when the active Claude account cannot be read consistently, instead of recording under a guessed account.
19
+ - Existing `cctally quota` calibrations become incompatible immediately; each account's is replaced on its next successful automatic fit, and a diagnostic run or too little Opus 5.5 history leaves the old one stored and ignored.
20
+
21
+ ### Fixed
22
+ - Codex reports now read compressed rollouts (`.jsonl.zst`) without losing cached history, slow history cleanup no longer runs inside the Codex hook, and `cctally doctor` has a new `Compressed Codex rollouts` check.
23
+ - `daily`, `session` and other Claude cost reports price Sonnet 5.5 cache reads at $0.10 per million tokens instead of $0.20. Recorded snapshots, closed blocks and milestones keep their original amounts.
24
+ - The status line's 5-hour figure no longer changes, or retries a pending drop, when another account's 5-hour reset is recorded.
25
+ - `cctally db rebuild --db stats` no longer drops percent milestones after a 5-hour or manual credit, which also stalled recording afterwards; this upgrade's one-time rebuild restores them.
26
+ - A usage reading recorded right after an upgrade while an older cctally process (such as a dashboard) was still running, or during `cctally db rebuild --db stats` or a stats index repair, no longer goes missing or waits for a later reading.
27
+ - `cctally db rebuild --db stats` keeps the current 5-hour block's first-seen time and pricing details as recorded. It no longer moves that time after a 5-hour credit or when two readings were recorded out of order.
28
+ - The status line, dashboard, TUI, `forecast`, `five-hour-blocks` and `five-hour-breakdown` show the latest 5-hour reading when the newest reading has none, instead of a blank or 0 % 5-hour figure or a closed current block.
29
+ - A 5-hour credit no longer discards a weekly reading recorded alongside the stale 5-hour figure, so the weekly figure no longer falls back to an older value.
30
+ - A weekly credit detected mid-week no longer discards the 5-hour reading recorded with the stale weekly figure, so the status line, 5-hour blocks and 5-hour milestones keep it, and upgrading restores readings already lost.
31
+
8
32
  ## [1.114.0] - 2026-10-08
9
33
 
10
34
  ### Added
@@ -16,6 +40,7 @@ based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
16
40
  - `cctally doctor` no longer warns about modest free space in `conversations.db`; it warns only while a large backlog (over 2 GiB and 20% of the file) is being reclaimed at a paced rate, and says why when reclaim is refused.
17
41
 
18
42
  ### Fixed
43
+ - Statusline and usage recording avoid redundant sorting of retained snapshots and expired blocks, with the same quota readings and publication order.
19
44
  - The `dashboard` block cost chart shows every trajectory sample when it exceeds a retained total.
20
45
  - The `dashboard` Sessions filter and sort icons keep their intended size on phones.
21
46
  - The `dashboard` keeps same-name project suffixes and panel counts readable, contains account status chips on phones, and keeps the swipe cue clear of spend details. Returning to All accounts starts at the first card.
@@ -510,17 +510,32 @@ def _count_scoped(conn, table: str, account_key: str) -> int:
510
510
  return 0
511
511
 
512
512
 
513
+ def _stats_index_not_current():
514
+ import _cctally_store
515
+ return _cctally_store.StatsIndexNotCurrent
516
+
517
+
513
518
  def _cmd_account_label(args: argparse.Namespace) -> int:
514
519
  ref = getattr(args, "ref", None)
515
520
  label = getattr(args, "label", None)
516
521
  conn = _cctally_core.open_db()
517
522
  try:
518
- key = _resolve_ref_or_exit(conn, ref)
519
- if key is None:
523
+ # #825/#832 spec 6: the reference and provider serialized into the op
524
+ # come from one snapshot proven to be the current interpretation.
525
+ try:
526
+ import _cctally_store
527
+ with _cctally_store.current_stats_snapshot(conn):
528
+ key = _resolve_ref_or_exit(conn, ref)
529
+ if key is None:
530
+ return 2
531
+ provider_row = conn.execute(
532
+ "SELECT provider FROM accounts WHERE account_key = ?",
533
+ (key,)
534
+ ).fetchone()
535
+ except _stats_index_not_current() as exc:
536
+ eprint(f"account label: {exc}; another cctally process is "
537
+ "republishing the stats index — restart it and retry")
520
538
  return 2
521
- provider_row = conn.execute(
522
- "SELECT provider FROM accounts WHERE account_key = ?", (key,)
523
- ).fetchone()
524
539
  provider = provider_row[0] if provider_row is not None else None
525
540
  finally:
526
541
  conn.close()
@@ -1390,9 +1405,18 @@ def _cmd_account_attribute(args: argparse.Namespace) -> int:
1390
1405
  "the range is half-open [since, until)")
1391
1406
  conn = _cctally_core.open_db()
1392
1407
  try:
1393
- account_key = _attribute_resolve_account(
1394
- conn, getattr(args, "ref", None))
1395
- label = display_account_label(conn, account_key)
1408
+ # #825/#832 spec 6: resolved on one validated current snapshot.
1409
+ try:
1410
+ import _cctally_store
1411
+ with _cctally_store.current_stats_snapshot(conn):
1412
+ account_key = _attribute_resolve_account(
1413
+ conn, getattr(args, "ref", None))
1414
+ label = display_account_label(conn, account_key)
1415
+ except _stats_index_not_current() as exc:
1416
+ raise _AttributeUsage(
1417
+ f"account attribute: {exc}; another cctally process is "
1418
+ "republishing the stats index — restart it and retry"
1419
+ ) from exc
1396
1420
  finally:
1397
1421
  conn.close()
1398
1422
  except _AttributeUsage as exc: