cctally 1.99.0 → 1.99.1

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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,13 @@ based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [1.99.1] - 2026-08-15
9
+
10
+ ### Fixed
11
+ - The dashboard now recognizes the previous calendar day as `Yesterday` across a fall-back daylight-saving transition instead of falling through to the absolute timestamp (#584).
12
+ - Budget figures no longer depend on which Python version is running cctally. The dashboard's Claude and Codex budget blocks added their spend with the built-in `sum()`, which CPython changed in 3.12 to use compensated summation, so the same spend over the same entries produced `$49.20424485` on Python 3.12 and later and `$49.204244850000016` on Python 3.11. The rendered figure is rounded to cents and never differed to the eye, but the published payload did, which is why the repository's own byte-comparison of that payload failed on 3.11. These four sums now use the exactly-rounded helper the rest of the cost surfaces already use, so every supported interpreter publishes the same number.
13
+ - `cctally account attribute --help` no longer prints `(default: None)` beneath `--since`, which is a required argument and therefore has no default. Python 3.13 already suppressed it and 3.11 and 3.12 did not, so the same command printed two different help texts depending on the interpreter. cctally now applies the 3.13 rule on every supported version, and this covers every required option on every subcommand, not only this one.
14
+
8
15
  ## [1.99.0] - 2026-08-15
9
16
 
10
17
  ### Added
@@ -18,6 +25,7 @@ based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
18
25
  - Complete the Claude/Codex parity certification with current source-aware dashboard, analytics, sharing, conversation, privacy, and scale evidence; the TUI remains explicitly Claude-only under its bugfix-only maintenance policy (#322).
19
26
 
20
27
  ### Fixed
28
+ - Failed authoritative test-gate records now retain the exact `test-remote` case function and source line even when private assertion detail is redacted, and the local record survives the next passing invocation (#579).
21
29
  - Schema tables, views, triggers and indexes in both cache stores now have a structural delivery guard, so a definition added without a migration cannot silently reach only fresh installations (#580).
22
30
  - Claude-active dashboard refreshes now incrementally update the `All` view's shared-range project and daily aggregates instead of rescanning and repricing the full thirty-day Claude history on every new entry. On the 60,000-entry benchmark with one live append before each warm run, the median added source-build time fell from about 404 ms to 2.5 ms while project and daily totals remained byte-identical to a cold rebuild (#567).
23
31
  - A Codex-active dashboard refresh now updates only changed rollout paths, accounts, and day/period/session/project aggregates instead of re-reading and re-aggregating the complete retained Codex history. On a copied production store with 154,600 Codex entries, a caught-up live dirty iteration including ingest completed in 4.77 seconds (9.77-second cooldown-adjusted publish period) while preserving the exact prior dashboard payload (#582).
@@ -2384,7 +2384,12 @@ def _configured_codex_budget_status(
2384
2384
  )
2385
2385
 
2386
2386
  def _sum_cost(start: dt.datetime, end: dt.datetime) -> float:
2387
- return sum(cost for timestamp, cost in resolved_events if start <= timestamp < end)
2387
+ # stable_sum, not sum: this feeds the byte-compared budget wire, and
2388
+ # the built-in sum() switched to Neumaier compensated summation for
2389
+ # floats in CPython 3.12, so 3.11 renders a different figure.
2390
+ return stable_sum(
2391
+ cost for timestamp, cost in resolved_events if start <= timestamp < end
2392
+ )
2388
2393
 
2389
2394
  recent_start = max(start_at, context.now_utc - dt.timedelta(hours=24))
2390
2395
  # #556 S5 §3.1/§3.3: ONE producer of the wire status, shared with Claude.
@@ -2819,7 +2824,9 @@ def _refresh_budget_status_clock(
2819
2824
  str(status["window_end_at"]).replace("Z", "+00:00")
2820
2825
  ).astimezone(UTC)
2821
2826
  recent_start = max(start_at, now_utc - dt.timedelta(hours=24))
2822
- recent_24h_usd = sum(
2827
+ # stable_sum, not sum: same byte-compared budget wire as the producer
2828
+ # above, and the same CPython 3.12 sum() change applies.
2829
+ recent_24h_usd = stable_sum(
2823
2830
  float(cost) for timestamp, cost in cost_events
2824
2831
  if isinstance(timestamp, dt.datetime)
2825
2832
  and start_at <= timestamp.astimezone(UTC) < now_utc
@@ -57,6 +57,22 @@ class CLIHelpFormatter(
57
57
  kwargs.setdefault("max_help_position", 30)
58
58
  super().__init__(prog, **kwargs) # type: ignore[arg-type]
59
59
 
60
+ def _get_help_string(self, action: argparse.Action) -> "str | None":
61
+ """Never state a default for a required argument.
62
+
63
+ CPython 3.13 stopped appending ``(default: ...)`` to a required
64
+ argument's help; 3.11 and 3.12 still append it. Without this the same
65
+ parser prints two different help texts depending on the interpreter,
66
+ so `cctally account attribute --help` renders a meaningless
67
+ ``(default: None)`` under `--since` on the two older versions and the
68
+ goldened help diverges on every lane that is not 3.13. Pinning the
69
+ 3.13 rule for every supported version is what makes `--help` a
70
+ property of this program rather than of the interpreter running it.
71
+ """
72
+ if action.required:
73
+ return action.help
74
+ return super()._get_help_string(action)
75
+
60
76
 
61
77
  _PHYSICAL_PROVIDER_SOURCES = ("claude", "codex")
62
78
 
@@ -3209,11 +3209,16 @@ def _tui_claude_budget_domain(
3209
3209
  window_start_at=start_at,
3210
3210
  window_end_at=end_at,
3211
3211
  target_usd=target,
3212
- spent_usd=sum(
3212
+ # stable_sum, not sum: both figures are published on the dashboard
3213
+ # wire and byte-compared by the dashboard goldens, and the built-in
3214
+ # sum() switched to Neumaier compensated summation for floats in
3215
+ # CPython 3.12, so the same spend renders 49.20424485 on 3.12+ and
3216
+ # 49.204244850000016 on 3.11.
3217
+ spent_usd=stable_sum(
3213
3218
  cost for timestamp, cost in events
3214
3219
  if start_at <= timestamp < now_utc
3215
3220
  ),
3216
- recent_24h_usd=sum(
3221
+ recent_24h_usd=stable_sum(
3217
3222
  cost for timestamp, cost in events
3218
3223
  if recent_start <= timestamp < now_utc
3219
3224
  ),