Repository navigation
Token report: retain selected upstream usage, status and cache reports beside each tool's row - #415
Merged
seathatflowsinourveins merged 11 commits intoSep 29, 2026
Conversation
…s beside each tool's row report_sources runs each selected upstream report command at refresh (ccusage daily, ai-memory status, qmd status, agentsview usage, OmniRoute cache and compression analytics), retains its complete output with the other captures, and records the parsed report on that component's coverage row. A report never carries a savings value: saved is always null, so nothing is added to a counter. Entries are validated when the configuration loads; a failed or unparsable report stays separate from the last good one. Four tests failed before the change and pass after it (56 -> 60). Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
- Names that fold to the same capture folder are rejected when the config loads (report_label), instead of aborting the refresh with FileExistsError. - Reports are stored under the scope "Report / <name>", which never equals a counter's scope, so a report cannot replace a counter's last good value. - The report's tool goes through native_tool_identity, so the documented component id (jcodemunch-mcp) joins its coverage row. - README curl examples use --fail-with-body, so an HTTP error exits nonzero. - New tests: last good report kept on the same ledger after a real TimeoutExpired (partial output retained, nondefault timeout forwarded); report and counter scopes stay separate; the component id joins its row. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Collaborator
Author
|
Cross-family review, one repair round. Review. GPT-6 (
Repair (
Checks: 63 tests OK, 🤖 Generated with Claude Code |
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…resh; reserved report scope prefix; unknown-tool issue; argv/stdin/memory notes
F1: capture_report_sources records a failed snapshot (saved null, kind,
boundary, error; evidence holds argv, cwd and the error, never output)
and an issue of the existing failed-report shape when capture() raises
OSError or ValueError, then continues with the next entry. Python 3.13
docs: subprocess raises ValueError for invalid Popen arguments (an
embedded NUL); os functions raise OSError for names the OS rejects
(ENAMETOOLONG). validate_report_sources now rejects a NUL in any argv
element and a name whose folded report_label exceeds 100 characters.
F2: REPORT_SCOPE_PREFIX ("Report / ") is a module constant; counter_scopes
values and context_roots names that start with it are rejected in
load_config and at the start of refresh(). Default scopes are unchanged.
F3: a report entry whose tool is not a component id in the stack
manifest adds an issue naming the entry and the tool; the report is
still captured and recorded. A missing or unreadable manifest skips
the check.
F4: README states that argv is stored literally, that commands inherit
the reporter's environment, stdin and the project working directory,
and that a successful JSON report is stored twice per snapshot.
Tests added red first (6 tests; 7 failures and 1 error before the fix).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
…report_sources repair round Hot-file protocol (docs/lanes.md): manifests/evidence.json in the last commit only. Re-registered tools/token-report/token_manifest.py, test_token_manifest.py and README.md; component_matrix.py --write and new_host_grand_list.py --write left their reports unchanged; scripts/validate.py passed. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…v check; empty component list skips the tool check A4: both HTML templates rendered a report row (scope "Report / <name>", saved null) as a savings counter with the headline "Unavailable". The portable card and the full view's native_reports item now show the report's kind (usage/status/cache/savings report) and its scope, never "Unavailable" or "estimated tokens"; the full view's good() lookup skips report rows, so a report scope that sorts before a counter no longer blanks the RTK or Headroom card. A failed report keeps the failed-counter state. Counter rows render byte-identically to the previous templates (scratch A/B on counter-only data). The new test renders a real refresh with both templates and runs each template's own script in node against a small fake DOM, like test_returned_results.cjs; it is skipped only without node. A6: validate_report_sources rejects a name or argv element that UTF-8 cannot encode (a lone surrogate such as "\ud800" or "\udcff" from JSON), which otherwise aborted the whole refresh at the UTF-8 manifest write. A7: stack_component_ids returns None for an empty components list, like a missing or unreadable manifest, so the caller skips the unknown-tool check instead of flagging every report tool. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…on and login, timeout budget, load-time rejections A1: the ccusage example ran bare `ccusage daily`, which covers every detected source (ccusage 20.0.26 README L85, L115-116), under a Claude Code boundary. It is now `ccusage claude daily` (README L66) with a Claude-only boundary, plus a `ccusage codex daily` entry (L67) with a Codex-only boundary. Both focused forms accepted --offline --no-cost --json on empty scratch data (exit 0, cost fields omitted; a bogus flag exits 2). A2: OmniRoute 3.8.51 computes /api/cache promptCache totals from usage_history (src/lib/db/settings/cacheMetrics.ts), which cleanup prunes at retention.usageHistory (src/lib/db/cleanup.ts L100-135; default 30, src/types/databaseSettings.ts L161), and the response also carries upstream savings estimates. since=all on the compression route drops the time filter over compression_analytics, pruned at 30 days by default (databaseSettings.ts L152, cleanup.ts L149-171). Both boundaries now say so. A3: both routes answer without a credential only while requireLogin is false (upstream default true, src/lib/db/settings.ts L176) or during first-run setup from loopback (src/shared/utils/apiAuth.ts isAuthRequired); otherwise a dashboard session or a manage-scope Bearer key in a header. The README states the 401 / curl exit 22 / nonzero refresh consequence and curl's -H @file form (curl --manual: added in 7.55.0), with the file kept 0600 outside every worktree, referring back to the existing argv paragraph. A5: the scheduled unit's TimeoutStartSec=900 (token-report-refresh.service L135, Type=oneshot) bounds the sequential captures; one steady-state refresh measured about 35 seconds on one host (coordinator, 2026-09-29 UTC). The load-time rejections from the current code (NUL, UTF-8, folded label over 100, reserved Report / prefix) and the unknown-tool issue are documented in one paragraph. A8: the OmniRoute examples give curl as /usr/bin/curl, to adjust per host. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…second report_sources repair round docs/lanes.md hot-file protocol: the five changed token-report files (README.md, test_token_manifest.py, token_manifest.py and both HTML templates) re-registered with host_receipts.register_file; component_matrix --write and new_host_grand_list --write regenerated their reports with no change; scripts/validate.py passed. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…ort card says its kind is configured; README names the pin Round-2 verifier minors on the report_sources repair: a lone surrogate in a report's tool or boundary passed load_config and aborted the whole refresh at the sqlite bind or the UTF-8 manifest write; the failed-refresh line on a report card said the value above was an observation when it is a configured kind; the README named an OmniRoute build the stack does not pin and listed only two of the credentials the management policy accepts. The README wrap is repaired and its load-time rejection list now names tool and boundary. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…t, branch files re-registered) Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Collaborator
Author
|
Review record, 2026-09-29 (native-agent-stack-10). Merge candidate: head
|
seathatflowsinourveins
deleted the
claude/token-report-upstream-reports-20260927
branch
September 29, 2026 05:07
4 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of the token-saving practice manifest: each tool row in the private token manifest should carry that tool's own upstream report, not only the five tools with a savings counter.
Change
report_sources(private config) selects upstream report commands. At refresh each one is captured like the existing counters (complete stdout and stderr, exit code, hashes), then parsed and recorded on its component'scoverage_matrixrow.savedis always null, andkindis one ofusage report,status report,cache reportorsavings report.savings reportcovers an upstream estimate, such as OmniRoute's compressiontokensSaved, which is kept as evidence and never counted.argv, name/tool/boundary/argvencodable as UTF-8 (no lone surrogate), a folded capture-folder label of at most 100 characters, and nocounter_scopesvalue orcontext_rootsname starting withReport /, the scope prefix reserved for reports.toolthat is not a component id inmanifests/stack.jsonis still captured, but adds an issue, so every refresh exits nonzero until it is corrected; a stack manifest that is missing, unreadable or lists no component skips that check.ccusagesource per report (ccusage claude dailyandccusage codex daily, because the baredailymixes every detected agent), OmniRoute's retention and login boundaries, whyargvis retained verbatim and how to pass a credential through curl's header-file form instead, the runtime a refresh may take within the unit'sTimeoutStartSec=900, and the load-time rejections. It warns against OmniRoute's per-account routes, which carry account emails.Why
The 2026-09-27 read-only survey found
token_manifest.pyran onlyrtk gain,headroom savings, jCodeMunchget_session_statsand Context Mode stats files. ccusage, ai-memory, qmd, agentsview and OmniRoute have their own report commands but never reached the manifest.token-efficiency-evidence-cardsassigned this gap to this session; its in-flight branches do not touchtools/token-report/. The #381 invoke metrics stay in PR-A'schild-usage.mjs/skill_usage.py; this change covers only native reports.Evidence
Measured 2026-09-29 by the coordinator at head
357d9076(mainb1be50c8merged in by the hot-file protocol). These are local integration checks and repository unit tests, not upstream tests.python3 -B -m unittest discover -s tools/token-report -p 'test_*.py': 72 tests OK (main has 56).node --test tools/token-report/test_returned_results.cjs: 3 pass, 0 fail.python3 -B scripts/validate.py:{"components": 69, "hashed_files": 7994, "profiles": 4, "receipts": 168, "status": "passed"};scripts/evidence_manifest.py --checkfiles 7994 passed;scripts/component_matrix.py --checkrows 32;scripts/new_host_grand_list.py --checkpassed, 32 layers;scripts/build_ecosystem.py --checkpassed;python3 -B -m unittest tests.test_ecosystem_manifest tests.test_native_dashboard_data tests.test_omniroute_gateway_unit tests.test_token_e2e_preregistration: 148 tests OK.token_manifest.py compareover the 25 retained ledger pairs that have both files present, once with main's copy of the script and once with this branch's, and diffed the payloads: 25 byte-identical after timestamps and paths are scrubbed, 0 differing, 0 failures in either run.toolandboundarycases added on this head failed 2 subtests before the fix and pass after it.token-report-refresh.timerruns from the live clone, so enablingreport_sourceson the workstation is a follow-up after merge.Review rounds (2026-09-29, native-agent-stack-10)
Round 1, head
78f61121. GPT-6 (gpt-6-astra, effort max,codex exec -s read-only; the model is the-mrequest, not an observed resolution): needs_changes (2 major, 2 minor): acounter_scopesvalue starting withReport /could replace a counter's last good value; anargvNUL aborted the whole refresh; an unknowntoolwas stored silently; the hot-file edit sat in two commits (moot under a squash merge). Claude security-reviewer (Opus, max): needs_changes (4 minor, 3 nit): one entry that raises aborts the refresh, unbounded output and stdin, no secret-safe credential path, double storage of each snapshot, the scope rule held only by convention, a relativeargv[0]. Claude evidence-reviewer (Opus, max): needs_changes (1 major, 7 minor, 2 nit): the README's bareccusage dailymixes every detected agent; OmniRoute's cache boundary and login requirement; both HTML templates rendered reports as savings counters; timeout budget; the body's test counts. Round 1 repair (d04f8c76) fixed isolation, NUL and label length, the reserved scope prefix, the unknown-tool issue and the README boundaries (69 tests); the second builder round (a470293e, 72 tests) fixed the ccusage examples, the OmniRoute retention and login paragraphs, both templates, UTF-8 rejection, the empty component list and the timing budget. Each round had an independent Opus verifier that re-ran the acceptance commands.Round 2 verifier (
ready_to_pushtrue, 3 minor and 5 nit): fixed on this head: a lone surrogate intoolorboundarypassedload_configand aborted the refresh at the sqlite bind or the UTF-8 manifest write (now rejected with the name andargvcheck); the failed-refresh line on a report card said the value above was an observation (it now says the kind is configured, not observed); the README named an OmniRoute build the stack does not pin (it names the 3.8.50 pin; the verifier read every cited source line at upstream v3.8.50 too) and listed two credentials where the management policy accepts more; the README wrap. Left as residuals below.Residuals
ccusage claude daily --help(20.0.26) does not list--no-cost, which the subcommand applies (measured exit 0, cost fields omitted); the README example is valid and the help text is an upstream gap.manifests/evidence.jsonsits in earlier branch commits than the last one (moot under a squash merge).SOTA sources
Each optional report source runs an upstream tool's own documented report command. This PR only captures their output.
ccusage claude daily --offline --no-cost --jsonandccusage codex daily --offline --no-cost --json(its README documents both, and that the bareccusage dailycovers every detected source).ai-memory status --json.qmd --index <name> status.agentsview usage daily --no-sync --offline --json.manifests/stack.json): its ownGET /api/cacheandGET /api/analytics/compression?since=allroutes, their retention (src/lib/db/cleanup.ts,src/types/databaseSettings.ts) and management-auth policy (src/shared/utils/apiAuth.ts,src/server/authz/policies/management.ts).curl --manual: the-H @filenameheader-file form (added in 7.55.0) and--fail-with-body(7.76.0). systemdsystemd.service(5)forTimeoutStartSec.rtk gain; headroom 0.37.0headroom savings --json; jcodemunch-mcp 1.108.319get_session_stats; context-mode 1.0.169 stats files. Pins are inmanifests/stack.json.🤖 Generated with Claude Code