cctally 1.88.2 → 1.89.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.
Files changed (37) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/bin/_cctally_cache.py +827 -37
  3. package/bin/_cctally_config.py +125 -0
  4. package/bin/_cctally_core.py +86 -2
  5. package/bin/_cctally_dashboard_cache_report.py +31 -0
  6. package/bin/_cctally_dashboard_conversation.py +26 -7
  7. package/bin/_cctally_dashboard_sources.py +51 -0
  8. package/bin/_cctally_db.py +626 -0
  9. package/bin/_cctally_doctor.py +84 -1
  10. package/bin/_cctally_journal.py +2 -1
  11. package/bin/_cctally_parser.py +42 -0
  12. package/bin/_cctally_quota.py +1358 -112
  13. package/bin/_cctally_record.py +249 -9
  14. package/bin/_cctally_setup.py +14 -5
  15. package/bin/_cctally_store.py +16 -1
  16. package/bin/_cctally_tui.py +16 -2
  17. package/bin/_cctally_update.py +9 -2
  18. package/bin/_lib_background_mcp.py +168 -0
  19. package/bin/_lib_cache_report.py +19 -2
  20. package/bin/_lib_codex_conversation.py +8 -0
  21. package/bin/_lib_codex_conversation_query.py +8 -7
  22. package/bin/_lib_conversation.py +105 -5
  23. package/bin/_lib_conversation_dispatch.py +15 -4
  24. package/bin/_lib_conversation_query.py +294 -2
  25. package/bin/_lib_dashboard_sources.py +5 -1
  26. package/bin/_lib_doctor.py +202 -1
  27. package/bin/_lib_jsonl.py +12 -0
  28. package/bin/_lib_quota_alert_axes.py +188 -0
  29. package/bin/_lib_quota_ledger.py +274 -0
  30. package/bin/_lib_snapshot_cache.py +36 -0
  31. package/bin/cctally +6 -3
  32. package/dashboard/static/assets/index-BgoYXdus.js +92 -0
  33. package/dashboard/static/assets/index-Ub8vwz1M.css +1 -0
  34. package/dashboard/static/dashboard.html +2 -2
  35. package/package.json +4 -1
  36. package/dashboard/static/assets/index-B0ZCsoxI.css +0 -1
  37. package/dashboard/static/assets/index-Bvp8mxtz.js +0 -92
package/CHANGELOG.md CHANGED
@@ -5,6 +5,38 @@ based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [1.89.1] - 2026-07-31
9
+
10
+ ### Fixed
11
+ - Cache Report no longer shows a healthy measured 0% on a day with no activity yet — the panel, spotlight, daily rows, sparkline and net-$ bars now mark an unmeasured day explicitly (#443).
12
+ - Cache Report daily rows whose anomaly predicates could not be evaluated now render a neutral flag with an explanatory legend, instead of a green check (#443).
13
+ - Cache Report single-source views now show a provider's degraded or stale status chip, matching what the all-sources view already showed (#443).
14
+ - The all-sources Cache Report summary no longer reports an anomaly for data the panel beside it calls "building baseline" (#443).
15
+ - An empty Cache Report source no longer renders KPIs and a healthy verdict alongside its empty label (#443).
16
+ - A Cache Report that failed to build now says so, instead of showing an indefinite loading state (#443).
17
+ - Internal (maintainer-only): the public repository's CI matrix no longer fails before running a single test. v1.89.0 started treating three harnesses as mandatory so that a lost executable bit could not silently drop one from a full-suite run, but one of them — the remote-test transport harness — is maintainer-local tooling that the public mirror deliberately never carries, so on every public checkout the guard refused immediately and took all three Python versions down with it. The requirement now applies only in the private checkout, where the file is supposed to exist, while the public matrix goes on running the shipped subset as designed. Nothing the guard was added to catch has been given up: in the private tree a harness that loses its executable bit — or disappears outright — still fails the run. (#446)
18
+
19
+ ## [1.89.0] - 2026-07-31
20
+
21
+ ### Fixed
22
+ - Backgrounded-MCP recovery now preserves every placeholder claimant and fails closed when one tool call claims conflicting task ids, instead of silently letting the last stored row choose which response to attach. Timestamp-less and notification-shaped non-meta rows can no longer make the capped card and its full-response lookup disagree, adversarial delimiters cannot extend a result past the notification wrapper, and the entire stored notification block is bounded rather than only its result text. Ordinary inline result lookups keep their narrow query path when the session has no background placeholder. (#450 Task A)
23
+ - The Conversation Viewer now shows the real response of an MCP tool call that Claude Code moved to the background. Claude Code changed MCP dispatch so a call that blocks for 120 seconds is moved to a background task, and it records the eventual completion in a form cctally was discarding at read time — so those calls showed only the harness placeholder ("still running after 120s… you'll receive a notification with the result when it completes") and the answer never appeared, even though it had arrived. The completion is now stored and joined back onto the call that made it, so a backgrounded Codex review reads exactly like one that returned inline, is searchable, and offers "load full response" for long answers. Existing history is repaired by a one-time background re-read of your Claude session logs on upgrade; on a large library that re-read is a real one-time wait, and it briefly restores transcripts older than your retention window, so the ordinary retention sweep runs straight afterwards. Matching is deliberately cautious: if a background task id is claimed by more than one call, or its completion cannot be identified beyond doubt, cctally leaves the placeholder in place rather than risk attaching an answer to the wrong call.
24
+ - A call that was moved to the background and never came back no longer reports itself as a successful call. Any call with a result and no error was labelled "✓ ok", so a still-running background call showed a green tick directly above text saying it had not finished. Such a call now reads "running in background", and a call whose response really was recovered says so and shows when it completed. The same distinction now appears on the generic tool card, which previously flagged only errors and truncation. On a phone-width screen those labels shorten — the full wording stays available on hover — and a pending Codex card puts its status and prompt on a second line, so the model, tool name, status, and a useful prompt preview all remain legible without horizontal overflow.
25
+ - An expanded Codex response can be collapsed again. "Show full response" expanded the response and then removed itself, leaving no way back to the clamped view; it is now a toggle that stays put, labelled for whichever direction it will take, and reports its state to screen readers.
26
+ - A Codex conversation opened from a search hit, an outline entry, or any link that points at a specific message no longer renders in reverse, with the final response at the top and the opening prompt at the bottom. Opening a conversation at a specific message starts the reader at the end of the transcript and pages backwards, and the request that asks for that last page carries a yes/no "start at the end" flag — but the Codex reader was reading that flag as a count of messages, so "start at the end" was served as a single message. The reader's live-tail poll then found what looked like a one-message conversation, fetched the rest, and appended it behind that message, leaving the last response first and the first prompt last. Reopening the conversation from the sessions list rebuilt it correctly, which is why the reversal came and went. The same confusion also meant an ordinary open ignored the page size entirely and returned the whole conversation in one response, so very long Codex conversations did more work per request than intended. Claude conversations were never affected, and nothing about the stored transcripts changed — only how a page of them was cut. (#445)
27
+ - Internal (maintainer-only): the mandatory remote-test transport harness now uses explicit lock-holder readiness and release barriers for claim, fallback, parity, root-mutex, and watch-launch arbitration instead of depending on a two-second scheduling window. Its expected self-termination diagnostic no longer leaks into suite output, and `bin/cctally-test-all` now treats the harness as required rather than allowing a lost executable bit to silently remove it from CI and authoritative full-suite runs. (#446)
28
+ - The Codex hook no longer blocks every turn for seconds on end, and no longer times out on a large history. It was reconciling your entire quota history from scratch **twice** per turn — measured at about 4 seconds per pass locally on a 212,000-observation store, and around 30 seconds for the reporter of the issue, against Codex's 30-second hook limit. The second pass could never take the short-circuit that was supposed to skip it, so both cost full price. cctally now records which quota windows actually changed, as they change, and re-derives only those; the turn runs one reconciliation instead of two. On the same 212,000-observation store a steady-state tick fell from about 4,000ms to 250-350ms, and a tick carrying a new observation to under 280ms. Nothing about the numbers themselves changes — the same windows, percentages, milestones and alerts are produced, verified by comparing an incremental pass against a full one on real data. A complete verification pass still runs at most once a day; the dashboard and `cctally codex quota` run it directly, and when the hook is the one that reaches the deadline it hands the pass to a background process rather than making you wait for it. (public [#5](https://github.com/omrikais/cctally/issues/5))
29
+ - Reading new Codex session files during a hook is now time-bounded and resumable. Previously a tick had to finish reading everything it found, so the first tick after a heavy Codex session — or after upgrading with a large backlog of history — could run long on its own. The hook now stops at a wall-clock budget (`codex.hook.ingest_budget_seconds`, default 5 seconds, configurable and capped safely below Codex's hook limit), records exactly where it stopped, and continues from there next time, cycling through your sessions so older history drains instead of being starved by the sessions you are actively using. The session the hook fired for is read first, so live numbers stay correct while history catches up. An explicit `cctally cache-sync --source codex` is never budgeted and always runs to completion — and it is also what performs the one-time full re-read of Codex history that some upgrades ask for, since a time-bounded tick cannot do that job safely; the dashboard, the terminal dashboard and any `cctally codex` command will do it for you just as well. While history is still loading, `cctally doctor` reports it under `codex.ingest_backlog` and the dashboard's Codex hero says so — and doctor only warns once it has been stuck for over an hour, because a backlog right after a busy session is normal.
30
+ - The first Codex hook after upgrading no longer runs long enough to hit Codex's hook limit. This release changes the local statistics index version, which makes the first use after upgrading rebuild that index from the journal — measured at 76 seconds of an 82-second first hook on a 212,000-observation store, against a 30-second limit, after which nothing is saved and the next turn starts over. The hook now performs that rebuild in the background and skips its own work for a turn instead, and it does the same for every other whole-history reconciliation it could otherwise be handed — a rebuilt index, a classification change, a large burst of new data. Your Codex quota numbers may lag by a turn or two on those occasions; nothing is lost, and every other way of running cctally still does the work immediately.
31
+ - A one-time full re-read of Codex history no longer leaves the hook stuck forever on an install that only ever runs the hook. A time-bounded tick cannot perform that re-read safely, so it declines it — and if you have no dashboard open and never run a `cctally codex` command, nothing else was going to perform it either, which would have frozen all Codex spend, quota, milestones and alerts indefinitely while every surface still reported a healthy store. The hook now starts the re-read in the background instead of just declining it, records that it declined so the state is visible, and `cctally doctor` reports it — quietly while the background re-read is in flight, and as a warning once it has been outstanding for over an hour with the drain command to run.
32
+ - The dashboard's Codex hero now actually announces the explanation behind its spend figure to a screen reader. The description — why a spend value is unavailable, or that history is still loading — was attached to a plain container that assistive technology does not read a label from, so it was silently unreachable; the visible line beside it was deliberately hidden to avoid repeating the same sentence twice, which left no working channel at all. Nothing about the visual design changes.
33
+ - `cctally doctor` now reports when the background pass that verifies your Codex quota projection stops landing. That pass moved off the hook so a turn can never block on it, which means an install driven only by the Codex hook depends entirely on the background worker — and on the paths where the hook does no projection work of its own, a worker that never succeeds leaves the Codex blocks, milestones and alerts missing while every other check still reads healthy. The new `codex_quota_verification` leg warns only after a full day with failed hand-offs and no completed pass, and the remedy is any non-hook command (`cctally cache-sync --source codex`), which runs the pass immediately.
34
+ - Turning Codex quota alerts on — or upgrading with them already on — now arms them reliably, and does not leave every Codex turn re-reading your whole quota history afterwards. Activation deliberately costs one pass over the full history so that thresholds you had already crossed are recorded as already-handled instead of firing as a burst of stale alerts, and cctally now treats that pass as done only when a pass genuinely performed it. A background reporting task, which never evaluates a threshold at all, can no longer consume the activation and leave alerts permanently unarmed with no way to ask again; and the pass that does perform the work now records that it did, so it is not repeated on the following turn and every turn after it. (public [#5](https://github.com/omrikais/cctally/issues/5))
35
+ - Codex quota windows whose model was never recorded are now resolved once and stored, instead of being looked up on every read. This closes a gap where a separate model allowance such as GPT-5.3-Codex-Spark could be filed as ordinary account weekly quota on an install that skipped the earlier repair or rebuilt its cache from the journal. Existing history is repaired on upgrade by a one-time migration and re-checked cheaply on every Codex sync; a window whose model genuinely cannot be determined is left alone rather than guessed at.
36
+
37
+ ### Changed
38
+ - Upgrading rebuilds the local statistics index from the journal on first open, twice over — once for the change-tracking state the incremental reconciliation needs, and once for the daily verification deadline. This is the documented, automatic resolution for an index-version change and needs no action; your usage history lives in the append-only journal and is unaffected. The dashboard's source payload version also moves, which a browser tab left open across an in-place upgrade will see; the tab keeps working either way.
39
+
8
40
  ## [1.88.2] - 2026-07-31
9
41
 
10
42
  ### Fixed