cctally 1.90.1 → 1.92.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 (44) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/README.md +2 -2
  3. package/bin/_cctally_cache.py +863 -74
  4. package/bin/_cctally_config.py +57 -0
  5. package/bin/_cctally_core.py +53 -8
  6. package/bin/_cctally_dashboard.py +146 -5
  7. package/bin/_cctally_dashboard_conversation.py +164 -18
  8. package/bin/_cctally_dashboard_envelope.py +69 -12
  9. package/bin/_cctally_dashboard_sources.py +27 -1
  10. package/bin/_cctally_db.py +372 -10
  11. package/bin/_cctally_doctor.py +18 -1
  12. package/bin/_cctally_journal.py +535 -13
  13. package/bin/_cctally_journal_repair.py +6 -0
  14. package/bin/_cctally_parser.py +6 -0
  15. package/bin/_cctally_quota.py +171 -55
  16. package/bin/_cctally_record.py +13 -1
  17. package/bin/_cctally_rederive.py +4 -0
  18. package/bin/_cctally_store.py +311 -6
  19. package/bin/_cctally_transcript.py +32 -2
  20. package/bin/_lib_cache_report.py +8 -3
  21. package/bin/_lib_cache_report_wire.py +8 -20
  22. package/bin/_lib_codex_conversation.py +959 -81
  23. package/bin/_lib_codex_conversation_query.py +2792 -167
  24. package/bin/_lib_codex_find_projection.py +370 -0
  25. package/bin/_lib_codex_harness_preamble.py +176 -0
  26. package/bin/_lib_codex_hooks.py +5 -3
  27. package/bin/_lib_codex_js_scan.py +254 -0
  28. package/bin/_lib_codex_landmarks.py +309 -0
  29. package/bin/_lib_codex_reasoning_headings.py +73 -0
  30. package/bin/_lib_codex_segments.py +259 -0
  31. package/bin/_lib_codex_title_clean.py +116 -0
  32. package/bin/_lib_conversation_dispatch.py +153 -21
  33. package/bin/_lib_conversation_watch.py +4 -2
  34. package/bin/_lib_dashboard_sources.py +33 -32
  35. package/bin/_lib_doctor.py +64 -0
  36. package/bin/_lib_quota_alert_axes.py +31 -34
  37. package/bin/_lib_stats_damage.py +523 -0
  38. package/bin/cctally +5 -0
  39. package/dashboard/static/assets/index-BEzzJtUd.js +97 -0
  40. package/dashboard/static/assets/index-DnWdv8um.css +1 -0
  41. package/dashboard/static/dashboard.html +2 -2
  42. package/package.json +9 -1
  43. package/dashboard/static/assets/index-Bar8-S1i.css +0 -1
  44. package/dashboard/static/assets/index-CRogVlEC.js +0 -92
package/CHANGELOG.md CHANGED
@@ -5,6 +5,80 @@ based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [1.92.0] - 2026-08-05
9
+
10
+ ### Added
11
+ - Add per-run bearer authentication for non-loopback dashboards, with fragment-to-HttpOnly-cookie browser bootstrap and a restart-only Settings/CLI opt-out (#282).
12
+ - Add account-scoped conversation browsing, search, reading, export, and permalinks to the dashboard and `cctally transcript`, while preserving the existing all-account and single-account output shapes (#347).
13
+
14
+ ### Changed
15
+ - Long Codex conversations now open with two concurrent data requests instead of issuing a third detail request just to repeat totals already available from the outline. On the same 3,733-row conversation, the first painted row improved from 784 ms to 421–429 ms while live-tail streaming remained connected (#477).
16
+ - A Codex tool result in the conversation reader no longer opens with the harness's own `Script completed` / `Wall time` / `Output:` boilerplate, and a call that failed is now identified as failed rather than shown with no outcome at all. Roughly 50,000 results in a real store lose three to five lines of boilerplate, and 82.4% now resolve to a real completed, failed or still-running state. Every Codex tool call now ends with an explicit **ok**, **error**, **running** or **outcome unknown**, and a failing call finally matches the reader's Errors filter, which previously matched no Codex call at all. Four more tool families became legible instead of raw: an `exec` call whose body is a JavaScript program, and every `js` call, show the invocations the reader could decode — and say so when the body also contains statements it could not read, so the list is never presented as the whole program; `write_stdin` and `wait` show which shell session they wrote to or which sandbox cell they polled; and `tool_search_call` shows its query. A patch event now shows a per-file diff, including for added and deleted files, which the provider retains as content but never transmits as a diff — those are labelled as rendered from retained content rather than passed off as provider-supplied, and a file whose diff was clipped to nothing says a diff exists and none of it fit rather than claiming none was retained. A conversation's shell sessions are numbered and grouped: each call shows which session it belongs to, a run that stays in one session names it, and the call that opened a session is marked as the one that started it, identified from that call's own output. Where the retained data does not identify an opener the reader says so, and where the session list itself was capped it says that instead, so nothing is reported as absent when it was merely not loaded. Session numbers are conversation-local and the provider's own session identifier is never shown. Finally, an assistant message carrying a serialized external-agent marker renders as a labelled disclosure naming the tool with its input behind it, instead of printing the raw marker mid-prose. An `apply_patch` call now shows the diff it is holding: the card decodes the patch text it already carries into a per-file diff, so a call no longer reports "no diffs" and "no diff retained" over a patch it is holding, and it no longer contradicts the matching patch-applied event elsewhere in the same conversation. A change that genuinely carries no line-level diff now says only that, rather than making a claim about what the provider retained. The exit code and running time behind an outcome are now shown in the expanded card as well as its tooltip, on every card family that shows an outcome, so they are reachable on a phone. A `write_stdin` row and a terminal row with collapsed output both keep a readable command preview at phone width instead of being squeezed to a couple of characters. Exported transcripts are unchanged (#463).
17
+ - The Codex conversation outline now offers landmarks proportional to the work a conversation did, so a real failure is reachable from the navigation chrome without a text search. Alongside the existing per-turn spine, the outline lists each authored reasoning heading, each failing tool call and each plan call as its own row, indented under the turn it belongs to; clicking one loads the part of the turn that holds it rather than the top of a turn that may run to 142 calls. On the heaviest conversation in a real store that is 424 landmarks where there were none. The outline's stats card starts reporting Codex's real models, tools, duration and errors instead of leaving four rows blank, and where the conversation's retained evidence cannot say whether anything failed it now says "not reported" rather than showing a confident zero — the comparison strip does the same. The Files tab lists each file a patch touched with its per-file `+N −M`, and a file row now jumps to the change that touched it; a count that cannot be determined is left blank rather than understated. Conversation titles stop showing the harness's own markup — a skill invocation's private filesystem path, a slash-command wrapper — on every surface that renders one, including `cctally transcript search --source codex --kind title`. A tool call that reported an error status is now treated as failed by the reader's Errors filter and badge, matching what the server reports. Clicking a landmark scrolls to the individual call or heading it names rather than to the segment containing it, which on a real conversation moved the failing call from as much as 6,574 pixels below the fold to the top of the window. The stats card's error line now reads "11 errors in 2 turns" for Codex as it already did for Claude, instead of reporting the same number twice; the jump chip beside it counts error turns, not failing calls; and repeated plan rows are numbered so four of them are told apart. A conversation title whose prompt text was written straight against the end of a skill link is cleaned too, which it was not before (#463).
18
+
19
+ ### Fixed
20
+ - Conversation Viewer outline pins now stay truthful after restoring a saved position inside a tall turn and after jumping to a cache rebuild on a sidechain member: an unaligned inner failure is no longer marked, and an available enclosing prompt or subagent row remains current instead (#492).
21
+ - Codex spend and quota ingest no longer freeze after the first append to a tracked rollout when a large history begins with legacy record envelopes (#502).
22
+ - Stats damage characterization now detects a table or index whose root page holds the wrong kind of b-tree page. The previous check accepted any valid page type, so the damage shape that actually occurs — a table rooted at an index leaf — was reported as healthy (#496).
23
+ - A detached Codex quota verification can no longer make the following hook tick acknowledge success without evaluating its budget alerts. If the verifier still owns the stats ingest lock, the tick remains due and retries as soon as that lock is released (#461).
24
+ - Cache Report no longer warns that net cache spend is negative when savings and write costs cancel to an effectively zero floating-point residue (#471).
25
+ - Fix `cctally setup` npm installs repeatedly adding duplicate Codex Stop/SubagentStop hooks instead of reconciling them (#458).
26
+ - Cache Report charts now announce one consistent window size to screen readers and identify unobserved days as a measured subset (#469).
27
+ - Codex quota rows restored from the journal or repaired during migration now invalidate cached dashboard and projection state immediately, instead of waiting for an unrelated later Codex mutation (#457).
28
+ - Codex file-path search now indexes the dict-shaped patch events the provider actually records, and upgrades backfill retained history so existing conversations become searchable by touched file (#489).
29
+ - A stats index rebuild that publishes a damaged index now reports failure instead of printing a success line, and the next command refuses that index rather than silently accepting it. A corruption incident now retains substantially more evidence about itself — why the rebuild ran, the write-ahead log bytes present when the damage was found, a structured description of what was damaged, and whether the published replacement passed validation — so a recurring fault can be told apart from a one-off. Internal (maintainer-only): a correlator classifies the existing incident corpus as far as retained evidence allows and reports the remainder as unknown (#496).
30
+ - A conversation's injected-context rows are readable on a phone. Labels such as "SESSION CONTEXT" and "AGENT MODE", and the section list beside them, were being broken apart mid-word — one or two characters per line — and they now wrap at spaces like ordinary text. The whole summary row is protected rather than one kind of row, so a row type added later cannot come back broken (#463, #493).
31
+ - A file path, a relative path or a custom link target in conversation text is no longer rendered as a working link or image. Those targets could not lead anywhere useful, and the browser was quietly requesting some of them from the dashboard; they now appear as plain text with no destination stored anywhere in the page. Web and email links are unaffected. This applies to both Claude and Codex conversations (#463, #484).
32
+ - Codex and Claude each have one colour across the whole app. The same blue previously meant Claude on the dashboard's source chips and Codex in the conversation viewer, so the colour could not be used to tell them apart. Codex now uses its own brand green and Claude uses purple everywhere, including the provider pills in the Forecast, Trend and Source Detail views. Colours that indicate a state rather than a provider are unchanged (#463).
33
+ - Opening a conversation link now selects the matching source tab and highlights the conversation's row in the list, including when a search or filter was left active that would otherwise have hidden it, and the browser's Back button returns to where you were instead of to an intermediate list view. Going Back or Forward keeps the search and filters you had set, rather than clearing them as following a fresh link does. Opening one side of a comparison in the reader moves the list to that side's source the same way. Opening a parent or child thread, or a subagent's child conversation, now stays within the account you were viewing (#463).
34
+ - The Conversation Viewer now preserves Claude tool names and request/result details on qualified links, keeps terminal copy controls clear of long working directories at phone width, and uses the same **ok**, **error**, **running**, and **outcome unknown** wording across Codex web, MCP, and subagent cards (#488).
35
+ - Qualified Claude conversation links now retain error, subagent, plan, compaction, file, and cache-rebuild navigation, while one-segment Codex links open under the Codex source instead of Claude (#491).
36
+ - MCP tools that report a protocol-level error inside a successful Codex transport response now appear as failed in conversation cards, the Errors filter and count, and outline landmarks instead of being shown as successful (#494).
37
+ - Stepping through Codex landmarks in the conversation viewer now moves. After a jump to a failing call or a plan call, pressing `e`/`E` or shift-clicking the jump chip re-found the first landmark forever going forward and reported no landmark at all going backward, because the position the jump left behind was not one the stepping cursor could read. The keyboard now also lands on the individual call or heading a landmark names, as clicking the same landmark in the rail already did, and the rail's highlight follows whichever of the three — rail row, chip, keyboard — issued the jump. A failing tool result that the reader shows on its own can now be jumped to at all: it carried no address in the page, so a jump aimed at it landed at the top of the surrounding block. That same result is now also shown as failed instead of as though it had succeeded, and one whose output was clipped says so. A patch the provider reported as errored counts as a failure too — only the word "failed" did before, so a patch reporting "error" was counted by the Errors badge and then hidden by the Errors filter. An MCP tool call and a subagent now decide what a failure is the same way the rest of the reader does. For MCP that closes a hole nobody could have reached, because a Codex MCP call has only ever reported "ok" or "error" and the card already recognised "error". For subagents it is a real if uncommon fix: a subagent run reporting "failed" was shown with the neutral marker rather than the error marker, so those runs now read as errors and reach the Errors filter and badge. Clicking a cache-rebuild row clears a focus filter that would hide the turn it lands on, in the session detail modal as well as in the outline; only the outline copy did that before. The stats card says "3 errors in 1 turn" rather than "in 1 turns". The Errors filter's own count badge now agrees with the jump chip beside it: on a Codex conversation whose failures cluster in a few turns it read the number of failing calls — 27 next to a chip reading 14 — and it now reads the number of error turns at every width (#463).
38
+ - Dashboard conversation source controls and provider context now render their intended borders and active surface, stale source status keeps its outline, and Codex reasoning uses the dashboard prose typeface instead of falling back to the browser default (#481).
39
+ - Codex conversation search now shows readable retained tool output instead of serialized `[{"text": ...}]` content wrappers, including a safe best-effort excerpt when a retained array was clipped mid-value. Opening the Codex conversation list and its filter facets now reads materialized conversation rollups in set-based pages rather than rebuilding and pricing every conversation one at a time; on a production-shaped 1,668-conversation store the warm 50-row browse fell from 6,694 SQL reads / 1.334 seconds to 8 reads / 0.162 seconds with a byte-identical response (#438).
40
+ - Find in a Codex conversation now counts and reaches every visible match instead of counting only the messages or reading units that contain one. Repeated matches inside the same formatted message, command, output, reasoning disclosure, or folded patch/web/MCP result each get their own navigation stop; next and previous cross the complete result set without skipping the short first page. Regex and case-sensitive modes keep their existing meaning, live updates preserve the selected match when it still exists, and a removed match is announced explicitly. Claude find behavior is unchanged (#482).
41
+ - Conversation deep links now finish only after the requested message is mounted and stably aligned at its start. Deferred virtualizer height corrections no longer leave a tall target thousands of pixels above the viewport, and a target that cannot be retained in view now produces a visible failure instead of silently clearing the jump (#479).
42
+ - Pressing `h` or `H` in a long Codex conversation now reliably reaches the adjacent reasoning heading even when that heading's row is unmounted behind a very large turn. A failed hop keeps the existing heading marked instead of clearing it, and headings on collapsed subagent bucket roots now open and land like other subagent headings (#486).
43
+ - A failed Conversation Viewer page request during a deep-link or find jump now retries with bounded backoff and then shows a connection error, instead of spinning forever until the tab or test worker runs out of memory. A transient failure still recovers and continues the jump (#480).
44
+ - A missing, empty, unrecognized, or temporarily unmounted `$CODEX_HOME` no longer causes an ordinary sync or rebuild to erase retained Codex accounting and conversation history. Orphan pruning now requires positive evidence from each configured root, still removes genuinely deleted rollout files and deliberately deconfigured roots, and reports every safety refusal through `cctally doctor` (#485).
45
+ - Codex quota alerts no longer leave a future-clocked capture unevaluated forever when its window goes quiet. The scheduled boundary now remembers which Codex root owns it, so the first hook tick after it matures re-evaluates only that root, retires the boundary, and keeps the next quiet tick fast without scanning unrelated quota history (#460).
46
+
47
+ ## [1.91.0] - 2026-08-03
48
+
49
+ ### Added
50
+ - The Codex conversation reader now shows an indicator inside the transcript while a further page is loading, so a scroll-up or a jump that has to fetch is visibly in progress rather than silently pending. When a jump cannot reach its target the reader now says so instead of falling silent (#463).
51
+ - Internal (maintainer-only): the whole frontend test estate now runs inside `bin/cctally-test-all` through a new `bin/cctally-frontend-test` harness, with a two-sided golden pinning the Codex reader path on both the server envelope and the adapted client model. Every CI lane that runs the bundle now provisions it (#463).
52
+ - Internal (maintainer-only): the React client now runs ESLint's hook-order rule in both its normal build and the authoritative test bundle, so a conditional hook fails statically instead of surviving until a mounted component changes branches at runtime (#468).
53
+ - Codex reasoning now lists every heading the model actually wrote, one readable line each, instead of a single clipped line that hid the rest. Press `h` and `H` to step forward and back through them, including into a part of the conversation that has not loaded yet. Codex re-states earlier headings as a turn goes on, so a heading a turn has already shown is listed once rather than again each time (#463).
54
+ - Internal (maintainer-only): `bin/cctally-frontend-test` now typechecks the React client, so a TypeScript error fails the authoritative local and remote suite instead of only the CI build (#463).
55
+
56
+ ### Changed
57
+ - A long Codex conversation now opens without downloading the whole thing: the server serves a bounded page and the reader loads the rest as you scroll. The heaviest conversation in a real store went from 13.2 MB in a single response to 2.5 MB (#463).
58
+ - A very long Codex turn is now split into several bounded reading units instead of one enormous message, so the reader can scroll it smoothly. Deep links, bookmarks and saved reading positions issued before this change still resolve (#463).
59
+ - A Codex message that is not the one its turn's cost is attributed to now reports no cost at all rather than a zero, so a consumer of the JSON can tell "this message carries no cost of its own" apart from "this cost nothing". No displayed figure changes: every rendering site already showed a cost only when there was a positive one (#463).
60
+ - Consecutive Codex messages now read as the separate messages they were, instead of being run together into one block of prose (#463).
61
+ - The dashboard's Codex Cache Report wire now publishes only `cached_input_percent`, reports structurally inapplicable wasted-cost and efficiency values as `null`, and identifies the coordinated contract change as source schema version 4 (#465).
62
+
63
+ ### Fixed
64
+ - Internal (maintainer-only): generated cache fixtures now store UTC timestamps in the same `+00:00` form as production, so rows exactly at a reader's upper boundary are exercised instead of being silently excluded by lexical ordering (#467).
65
+ - Internal (maintainer-only): the remote-test harness's synthetic lock holders now acknowledge that their lock path is gone before a fixture continues, and wrapper cleanup no longer strands an owned lock when its secondary process-start probe is transiently unavailable under load (#464).
66
+ - The Codex hero's transient ingest-backlog note now stays to one compact line on phone-width screens instead of wrapping into two to four lines. The full `+N sessions still loading` wording remains on wider screens, and the complete explanation remains available to assistive technology at every width (#459).
67
+ - Multi-account Codex quota labels now stay attached to the account they came from when two accounts share one `$CODEX_HOME` root. The dashboard no longer borrows another account's label or window duration from an otherwise-identical active quota key, while single-account dashboards keep their existing undecorated join (#437).
68
+ - The dashboard's All tab now keeps its combined spend and token total when one provider's quota evidence is stale. The retained actuals carry a visible `Stale quota` marker in both the hero and current-usage modal, while forward-looking projections remain paused (#359).
69
+ - Multi-account Codex dashboard cards now mark stale quota evidence on the account it belongs to. A fresh sibling no longer hides another account's staleness, and the stale card keeps showing its retained percentage, reset, and spend; after reset its quota fields still clear while historical spend remains (#416, #360).
70
+ - The dashboard's Recent Alerts card and modal now identify which account each alert belongs to and honor the selected account filter, while retaining vendor-wide crossings as `All accounts`. Simultaneous same-threshold alerts from different accounts no longer collapse into one toast, and single-account dashboards keep their previous undecorated shape (#345).
71
+ - The dashboard now marks incomplete Codex totals everywhere they are shown: the Combined spend hero carries the same visible `+N sessions still loading` caveat as the Codex hero, and the Codex current-cycle modal explains that its totals will rise as bounded ingest finishes. The disclosure also reaches the Codex section embedded in the All-sources modal, while account-scoped stale-cycle notes keep their existing scope (#456).
72
+ - A deep link, bookmark or saved reading position pointing into a long Codex turn now loads the message it names. Because the reader's outline omits some turns from its navigation list, any position inside one of those turns resolved to nothing at all and the reader stayed on the last page it had, showing no error. On the heaviest conversation in a real store this affected every position inside a split turn. The same omission applies to Claude conversations for a position inside a system or lifecycle turn, and those now load as well (#463).
73
+ - Find in a Codex conversation now reports and reaches every match. Matches inside a long turn, past its first reading unit, were dropped from the result list — on the heaviest conversation in a real store one query reported 2 matches where there are 16 — and none of the dropped ones could be navigated to (#463).
74
+ - Paging up through a Codex conversation now returns the page immediately before your cursor. It previously returned the conversation's opening messages instead, which made scrolling up appear to jump to the beginning (#463).
75
+ - `cctally transcript export` and the dashboard export no longer repeat each Codex reasoning heading, so an exported Codex transcript reads once through rather than twice (#463).
76
+ - The transcript paging indicator no longer sits under the "↓ N new" pill on a narrow screen (#463).
77
+ - A long Codex reasoning heading is now readable in full: it wraps instead of being cut off mid-sentence with no way to see the rest (#463).
78
+ - A Codex message that opened a code block and never closed it no longer swallows the messages that follow it into that code block (#463).
79
+ - Internal (maintainer-only): the issue-triage tracker now keeps its reconciler ledger in a collapsed disclosure, matching the managed issue comments instead of rendering raw machine-state JSON below the human execution plan (#475).
80
+ - Concurrent first-time commands no longer misclassify a freshly initialized `stats.db` as a database written by a newer cctally. A waiting opener now rechecks the index epoch after acquiring the initialization lock, so it accepts the winner's completed index instead of sending epoch `1006` through the frozen legacy migration dispatcher.
81
+
8
82
  ## [1.90.1] - 2026-08-02
9
83
 
10
84
  ### Fixed
package/README.md CHANGED
@@ -30,9 +30,9 @@ Your Claude Code plan meters you with a percentage that creeps up all week. ccta
30
30
  </p>
31
31
 
32
32
  <!-- cctally:latest-stable:begin -->
33
- **Latest stable: v1.87.1** (2026-07-30)
33
+ **Latest stable: v1.90.1** (2026-08-02)
34
34
 
35
- - Codex session names now remain visible in Recent Sessions when an individual account is selected, whenever transcript visibility is enabled. Selecting an account no longer replaces every session name with an em dash; disabling transcript visibility still hides names in both the all-accounts and focused-account views.
35
+ - Internal (maintainer-only): the public release snapshot no longer ships the issue-triage pytest modules without the private workflow implementation they import. Those tests now stay behind the same mirror boundary as their `.agent-workflows` dependencies, preventing collection failures across the public Python matrix.
36
36
  <!-- cctally:latest-stable:end -->
37
37
 
38
38
  ## Quick start