feat(token-report): 2-decimal USD, cost-per-day chart, PR titles - #465
Conversation
- Round all surfaced dollar amounts to 2 decimals (cents) via _fmt_usd (printf "$%.2f"); codify it as an org standard in AGENTS.md → Cost reporting. - Add a "Cost per day (stacked by repo)" ASCII stacked-bar chart: one bar per day, length scaled to the priciest day, segments lettered per top-6 repo with the rest bucketed as "." plus a legend of per-repo window totals. (GitHub Markdown/Mermaid has no native stacked bar; an ASCII bar renders everywhere.) Requires a date column — appended to annotate_records as col 13. - Add the first 35 chars of each PR title to the "Most expensive PRs" table. main() resolves titles for the top-10 PRs via gh and passes them to the pure renderer through PR_TITLE_FILE; titles are pipe-sanitized and ellipsized. Tests: 2-decimal rounding (+ sub-cent), cost-per-day chart presence and bar scaling, PR-title truncation/sanitization/blank-fallback. All bats green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughThis PR enhances the token report with standardized USD cost formatting, adds per-day cost attribution tracking, introduces a cost-per-day stacked breakdown visualization, and embeds PR titles in the most-expensive-PR section. Changes span standards documentation, data schema expansion, new rendering features, and comprehensive test coverage. ChangesToken Report Cost Attribution Enhancement
Sequence DiagramsequenceDiagram
participant main as main()
participant annotate as annotate_records()
participant render_cost as render_cost_per_day()
participant render_report as render_token_report()
participant titles_fetch as fetch PR titles
main->>titles_fetch: resolve top-10 PR titles
titles_fetch-->>main: populate PR_TITLE_FILE
main->>annotate: emit enriched records
annotate-->>main: cache_write, date fields
main->>render_cost: render daily breakdown
render_cost-->>main: stacked bar chart
main->>render_report: render final report
render_report->>PR_TITLE_FILE: read title data
render_report-->>main: report with titles embedded
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Dev-Lead — review-changes (no-changes)No changes were needed for this PR. |
There was a problem hiding this comment.
Code Review
This pull request introduces several enhancements to the token and cost reporting tool, including rounding USD amounts to two decimal places, adding an ASCII stacked-bar chart for daily cost by repository, and displaying PR titles in the most expensive PRs table. Feedback on these changes focuses on improving portability, efficiency, and resource cleanup. Specifically, it is recommended to replace a non-portable awk split call with a substr loop, consolidate multiple piped commands inside a loop into a single awk invocation to reduce process overhead, and write the temporary titles file to the tracked $jsonl_dir directory to leverage its automatic cleanup trap.
Dev-Lead — fix-bot-comment (no-changes)Agent reasoning |
donpetry-bot
left a comment
There was a problem hiding this comment.
Automated review — APPROVED ✓
Risk: LOW
Reviewed commit: f5e4679ab4561820669651fbd7a91bdc43196696
Review mode: triage-approved (single reviewer)
Summary
Three additive enhancements to scripts/token_report.sh: (1) all surfaced USD amounts now route through _fmt_usd and render at 2 decimals (cents), codified as an org standard in AGENTS.md; (2) a new ASCII "Cost per day (stacked by repo)" chart built from a new date column appended to annotate_records; (3) the "Most expensive PRs" table gains a Title column, with titles resolved by main() and passed to the pure renderer via PR_TITLE_FILE. Docs and tests are updated to match.
Linked issue analysis
No issues linked. The PR description itself is well-structured and clearly motivates each of the three changes (formatting consistency, missing daily/repo visualization, PR identifiability).
Findings
- Risk surface: none touched — no auth, secrets, crypto, DB/migrations, CI workflows, or dependency changes. Pure scripting + docs + tests.
- Code quality (spot-checks):
gh pr view "$purl"is invoked with the URL properly quoted; the URL set comes fromtop_pr_urls(reading the internal JSONL context column), and titles are sanitized (tr -d '\r\n',tr '|' '/', length-capped to 35 chars +…) before insertion into the Markdown table — table can't be broken by hostile titles.mktemptitles file is cleaned up withrm -fimmediately afterrender_token_reportreturns. Gemini's suggestion to place it under$jsonl_dir(which has a trap-based cleanup) is a nice-to-have for crash-safety but not blocking.- Downstream column indices preserved (cache_write=12, date=13 appended), so existing consumers are unaffected.
render_cost_per_dayis pure (reads only the enriched TSV) and no-ops cleanly when there are no priced, dated rows.
- Tests: 4 new bats cases cover 2-decimal + sub-cent rounding, cost-per-day chart presence, bar scaling, title truncation, pipe sanitization, and the blank-fallback path. All bats suites green (token_report 23, model_pricing 13, fleet_report 40).
- Non-blocking suggestions from gemini-code-assist (worth considering in a follow-up, not required for this approval):
- Replace non-portable
awk splitwith asubstrloop. - Consolidate per-iteration piped commands in the title-fetch loop into one
awkinvocation. - Write the titles tempfile under
$jsonl_dirto inherit its trap-based cleanup.
- Replace non-portable
CI status
All required checks green; nothing failing. SonarCloud Quality Gate passed (0 new issues, 0 security hotspots, 0 duplication). CodeQL, gitleaks, AgentShield, Agent Security Scan, shellcheck, bats, and unit-tests all SUCCESS. CodeRabbit was rate-limited and did not review, but the other static-analysis lanes provide adequate coverage for this scope.
Reviewed automatically by the PR-review agent (single-reviewer mode: opus 4.7). Reply if you need a human review.
There was a problem hiding this comment.
Pull request overview
This PR enhances the org-wide token cost report generator by standardizing USD formatting, adding a daily cost visualization, and enriching the “most expensive PRs” section with PR titles while keeping the renderer network-free.
Changes:
- Standardize all surfaced USD amounts to 2-decimal (cents) rendering via
_fmt_usd. - Add a “Cost per day (stacked by repo)” ASCII chart driven by an appended per-record date column.
- Add an optional PR Title column to the “Most expensive PRs” table, with titles fetched in
main()and passed viaPR_TITLE_FILE.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
tests/token_report.bats |
Updates and expands unit tests for 2-decimal USD formatting, the cost-per-day chart, and PR title rendering/sanitization. |
scripts/token_report.sh |
Implements 2-decimal USD formatting, daily stacked cost chart generation, and PR title resolution + rendering via PR_TITLE_FILE. |
docs/token-report.md |
Documents the new chart and PR title behavior and the 2-decimal USD formatting standard. |
AGENTS.md |
Codifies the 2-decimal USD cost reporting rule as a repo-local standard. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 80bd0ccba8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Dev-Lead — review-changes (applied)Changes committed and pushed. |
Dev-Lead — waiting on PR blockers (intent: review-changes)PR: #465 |
|
Note @don-petry I reviewed this PR and no code changes were needed, but it still has blocking checks or reviews (failing or cancelled checks, or changes-requested reviews), so I cannot mark it done yet. I'll re-check automatically. |
Dev-Lead — fix-reviews (applied)Changes committed and pushed. |
|
@donpetry-bot review |
|
@don-petry I'm on it — starting a fresh review now. Results will appear in a few minutes. |
Dev-Lead — review-changes (no-changes)No changes were needed for this PR. |
|
@donpetry-bot review |
|
@don-petry I'm on it — starting a fresh review now. Results will appear in a few minutes. |
donpetry-bot
left a comment
There was a problem hiding this comment.
Automated review — APPROVED ✓
Risk: LOW
Reviewed commit: f6df3d4455570044103a0ee81d3a0ed0ed9fa522
Review mode: triage-approved (single reviewer)
Summary
Confirming the triage tier's LOW-risk assessment. The PR makes three additive changes — all in scripts/token_report.sh plus docs and tests:
_fmt_usdnow renders dollars at 2 decimals (cents) viaprintf "$%.2f"; this is codified as an org standard inAGENTS.md → Cost reporting(with a promotion note forpetry-projects/.github).- New
render_cost_per_dayproduces an ASCII stacked-bar chart (one bar per day, length scaled to the priciest day, top-6 repos lettered + others bucketed as.);annotate_recordswas extended with adatecolumn (col 13) to feed it. - The "Most expensive PRs" table gains a Title column;
main()resolves titles for the top-10 PRs viagh pr viewand passes them to the pure renderer throughPR_TITLE_FILE(titles are pipe-sanitized, newline-stripped, and truncated to 35 chars +…).
Linked issue analysis
No issues linked. The PR description clearly motivates each of the three changes (formatting consistency, missing daily/repo visualization, PR identifiability) and includes an explicit test plan.
Findings
- Risk surface: none touched — no auth, secrets, crypto, DB/migrations, CI workflow, or dependency changes. Pure shell + docs + bats.
- Code quality (spot-checks):
- Renderer remains network-free: only
main()callsgh pr view, then writespr_titles.tsvinto$jsonl_dirso it inherits the existing trap-based cleanup. Renderer reads viaPR_TITLE_FILEonly. - Title sanitization is defense-in-depth against table-breakage and CR/LF leaks:
gsub(/\r/,""),gsub(/\|/,"/"), length-capped to 35 chars +…before insertion into the Markdown row. - Downstream column indices are preserved (cache_write=12 unchanged; date appended as col 13), so existing consumers of
annotate_recordsaren't affected. top_pr_urlsis pure and reusesannotate_records; only priced rows contribute ($10 == 1).render_cost_per_dayno-ops cleanly when there are no priced, dated rows (nd == 0 → exit 0)._fmt_usdchange is consistent everywhere costs are surfaced; ET is preserved as the fine-grained comparator.
- Renderer remains network-free: only
- Tests: new bats cases cover 2-decimal rounding (incl. sub-cent →
$0.00), cost-per-day chart presence and bar-length scaling, PR-title truncation, pipe sanitization, and the no-PR_TITLE_FILEblank-fallback path. All bats suites pass per the PR's test plan. - Prior bot reviews:
gemini-code-assistoffered non-blocking portability suggestions (usesubstrloop instead ofawk split; consolidate per-iteration pipes into oneawk; write tempfile under$jsonl_dir). The third has already been adopted (titles_file="$jsonl_dir/pr_titles.tsv"); the other two are nice-to-have follow-ups, not blocking.copilot-pull-request-reviewerleft 2 inline notes, no blocking issues.coderabbitaiwas rate-limited and did not produce a review, but the other static-analysis lanes provide adequate coverage for this scope.
CI status
All required checks green. SonarCloud Quality Gate passed (0 new issues, 0 security hotspots, 0 duplication). CodeQL, gitleaks (Secret scan), AgentShield, Agent Security Scan, shellcheck, ShellCheck (CI), bats, validate-agent-profiles, gh-aw-compile, Compile agentic workflows, unit-tests, and the dependency-audit lane all completed without failure (npm/pnpm/cargo/pip/govulncheck/dependabot SKIPPED as expected for this change set).
Reviewed automatically by the PR-review agent (single-reviewer mode: opus 4.7). Reply if you need a human review.
|
Dev-Lead — waiting on PR blockers (intent: review-changes)PR: #465 |
|
Note @don-petry I reviewed this PR and no code changes were needed, but it still has blocking checks or reviews (failing or cancelled checks, or changes-requested reviews), so I cannot mark it done yet. I'll re-check automatically. |
* feat(token-report): 2-decimal USD, cost-per-day chart, PR titles
- Round all surfaced dollar amounts to 2 decimals (cents) via _fmt_usd
(printf "$%.2f"); codify it as an org standard in AGENTS.md → Cost reporting.
- Add a "Cost per day (stacked by repo)" ASCII stacked-bar chart: one bar per
day, length scaled to the priciest day, segments lettered per top-6 repo with
the rest bucketed as "." plus a legend of per-repo window totals. (GitHub
Markdown/Mermaid has no native stacked bar; an ASCII bar renders everywhere.)
Requires a date column — appended to annotate_records as col 13.
- Add the first 35 chars of each PR title to the "Most expensive PRs" table.
main() resolves titles for the top-10 PRs via gh and passes them to the pure
renderer through PR_TITLE_FILE; titles are pipe-sanitized and ellipsized.
Tests: 2-decimal rounding (+ sub-cent), cost-per-day chart presence and bar
scaling, PR-title truncation/sanitization/blank-fallback. All bats green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore: apply manual instructions [skip ci-relay]
* fix(reviews): address review comments [skip ci-relay]
---------
Co-authored-by: donpetry-bot <{}+donpetry-bot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
* feat(token-report): 2-decimal USD, cost-per-day chart, PR titles
- Round all surfaced dollar amounts to 2 decimals (cents) via _fmt_usd
(printf "$%.2f"); codify it as an org standard in AGENTS.md → Cost reporting.
- Add a "Cost per day (stacked by repo)" ASCII stacked-bar chart: one bar per
day, length scaled to the priciest day, segments lettered per top-6 repo with
the rest bucketed as "." plus a legend of per-repo window totals. (GitHub
Markdown/Mermaid has no native stacked bar; an ASCII bar renders everywhere.)
Requires a date column — appended to annotate_records as col 13.
- Add the first 35 chars of each PR title to the "Most expensive PRs" table.
main() resolves titles for the top-10 PRs via gh and passes them to the pure
renderer through PR_TITLE_FILE; titles are pipe-sanitized and ellipsized.
Tests: 2-decimal rounding (+ sub-cent), cost-per-day chart presence and bar
scaling, PR-title truncation/sanitization/blank-fallback. All bats green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore: apply manual instructions [skip ci-relay]
* fix(reviews): address review comments [skip ci-relay]
---------
Co-authored-by: donpetry-bot <{}+donpetry-bot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
* feat(token-report): 2-decimal USD, cost-per-day chart, PR titles
- Round all surfaced dollar amounts to 2 decimals (cents) via _fmt_usd
(printf "$%.2f"); codify it as an org standard in AGENTS.md → Cost reporting.
- Add a "Cost per day (stacked by repo)" ASCII stacked-bar chart: one bar per
day, length scaled to the priciest day, segments lettered per top-6 repo with
the rest bucketed as "." plus a legend of per-repo window totals. (GitHub
Markdown/Mermaid has no native stacked bar; an ASCII bar renders everywhere.)
Requires a date column — appended to annotate_records as col 13.
- Add the first 35 chars of each PR title to the "Most expensive PRs" table.
main() resolves titles for the top-10 PRs via gh and passes them to the pure
renderer through PR_TITLE_FILE; titles are pipe-sanitized and ellipsized.
Tests: 2-decimal rounding (+ sub-cent), cost-per-day chart presence and bar
scaling, PR-title truncation/sanitization/blank-fallback. All bats green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore: apply manual instructions [skip ci-relay]
* fix(reviews): address review comments [skip ci-relay]
---------
Co-authored-by: donpetry-bot <{}+donpetry-bot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…ozen @v2) (#919) * chore(auto-rebase): pin caller to @auto-rebase/stable channel (was @v2) This repo's auto-rebase caller pinned the frozen `@v2` tag (376a4fcb, 2026-05-19), which predates the review-ready eligibility gate (#465/#468) and violates the org standard (callers MUST pin the centrally-advanced `auto-rebase/stable` channel, never a frozen `@vX` — see standards/ci-standards.md → Reusable workflow versioning). Re-syncs the caller stub from standards/workflows/auto-rebase.yml: - uses: ...auto-rebase-reusable.yml@v2 → @auto-rebase/stable - corrected "MUST NOT change the uses ref" header guidance - documents the eligibility / ready_label inputs Effect: once the `auto-rebase/stable` channel is promoted to a commit containing #528 (the tooling_ref fix) + #468 (the gate), this repo automatically adopts the review-ready restriction. Until then it runs the current channel head (unchanged unrestricted behavior) — no broken state. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019LUUSUQHqwLWZ583SAs41K * chore: apply manual instructions [skip ci-relay] --------- Co-authored-by: donpetry-bot <{}+donpetry-bot@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
* feat(token-report): 2-decimal USD, cost-per-day chart, PR titles
- Round all surfaced dollar amounts to 2 decimals (cents) via _fmt_usd
(printf "$%.2f"); codify it as an org standard in AGENTS.md → Cost reporting.
- Add a "Cost per day (stacked by repo)" ASCII stacked-bar chart: one bar per
day, length scaled to the priciest day, segments lettered per top-6 repo with
the rest bucketed as "." plus a legend of per-repo window totals. (GitHub
Markdown/Mermaid has no native stacked bar; an ASCII bar renders everywhere.)
Requires a date column — appended to annotate_records as col 13.
- Add the first 35 chars of each PR title to the "Most expensive PRs" table.
main() resolves titles for the top-10 PRs via gh and passes them to the pure
renderer through PR_TITLE_FILE; titles are pipe-sanitized and ellipsized.
Tests: 2-decimal rounding (+ sub-cent), cost-per-day chart presence and bar
scaling, PR-title truncation/sanitization/blank-fallback. All bats green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore: apply manual instructions [skip ci-relay]
* fix(reviews): address review comments [skip ci-relay]
---------
Co-authored-by: donpetry-bot <{}+donpetry-bot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
* feat(token-report): 2-decimal USD, cost-per-day chart, PR titles
- Round all surfaced dollar amounts to 2 decimals (cents) via _fmt_usd
(printf "$%.2f"); codify it as an org standard in AGENTS.md → Cost reporting.
- Add a "Cost per day (stacked by repo)" ASCII stacked-bar chart: one bar per
day, length scaled to the priciest day, segments lettered per top-6 repo with
the rest bucketed as "." plus a legend of per-repo window totals. (GitHub
Markdown/Mermaid has no native stacked bar; an ASCII bar renders everywhere.)
Requires a date column — appended to annotate_records as col 13.
- Add the first 35 chars of each PR title to the "Most expensive PRs" table.
main() resolves titles for the top-10 PRs via gh and passes them to the pure
renderer through PR_TITLE_FILE; titles are pipe-sanitized and ellipsized.
Tests: 2-decimal rounding (+ sub-cent), cost-per-day chart presence and bar
scaling, PR-title truncation/sanitization/blank-fallback. All bats green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore: apply manual instructions [skip ci-relay]
* fix(reviews): address review comments [skip ci-relay]
---------
Co-authored-by: donpetry-bot <{}+donpetry-bot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
…eview-ready deadlock (#1201) * fix(dev-lead): label opened PRs auto-rebase:ready to break the review-ready deadlock The auto-rebase 'review-ready' gate (#465) only rebases PRs that are approved OR carry the auto-rebase:ready label. That label half was never wired up — no producer applies it — so the only path to eligibility is an approval. A dev-lead PR that falls behind before it is approved is therefore skipped by auto-rebase, drifts into a merge conflict, and can never be approved (pr-review skips red/conflicting PRs): a deadlock that rots the PR for weeks. dev-lead now applies auto-rebase:ready to every PR it opens, so its PRs are auto-rebase-eligible from creation and stay current until merge. The label is created idempotently (--force) first so a repo missing it does not break, and all label operations are guarded so PR creation never fails on a labeling hiccup. Addresses Part A of petry-projects/.github#711. Part C (escalate skipped-but- conflicting PRs) and standardizing the label in labels.yml are tracked follow-ups. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Juznz5V6su81ffSND8fg7s * test: address CodeRabbit — drop needless LABEL_RECORD export, use STUB_BIN_DIR The record path is baked into the gh stub via the unquoted heredoc, so exporting it was unnecessary; placing it under STUB_BIN_DIR lets teardown clean it up. (The reviewer's other suggestion — return '[]' for the pulls?state=open case — is not applicable: the mock gh bypasses --jq, so check_existing_pr reads the raw echo and needs the post-jq count '0'; returning '[]' would make [ ... -gt 0 ] throw.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Juznz5V6su81ffSND8fg7s * chore: dev-lead update (review-changes) [skip ci-relay] * chore: dev-lead update (review-changes) [skip ci-relay] --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>



Three report enhancements (all in
scripts/token_report.sh), each tested.1. Round all dollar amounts to 2 decimals (cents) + org standard
_fmt_usdnow usesprintf "$%.2f"— every surfaced USD figure (totals, by workflow/tier/model, by repo, per-day, per-PR) goes through this single formatter, so they stay consistent. Sub-cent values render$0.00; ET remains the fine-grained comparator.petry-projects/.github).2. "Cost per day (stacked by repo)" chart
.), with a legend of per-repo window totals.annotate_recordsas col 13 (downstream columns unchanged).3. PR titles in "Most expensive PRs"
…) of each PR title.main()resolves titles for the top-10 PRs viaghand passes them to the pure renderer throughPR_TITLE_FILE; titles are pipe-sanitized (so the table can't break) and newline-stripped. Renderer stays network-free (blank title when no file → unit tests unaffected).Test plan
shellcheck --severity=warningclean on all touched scriptsbats— token_report (23), model_pricing (13), fleet_report (40): 0 failures🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation