Skip to content

fix(cli): reapply date-bound validation - #1608

Merged
ryoppippi merged 1 commit into
mainfrom
codex/reapply-date-bound-coauthor
Aug 15, 2026
Merged

fix(cli): reapply date-bound validation#1608
ryoppippi merged 1 commit into
mainfrom
codex/reapply-date-bound-coauthor

Conversation

@ryoppippi

@ryoppippi ryoppippi commented Aug 15, 2026

Copy link
Copy Markdown
Member

Reapply the date-bound validation removed by the preceding revert.

This restores the documented CLI and configuration validation while recording dok123 as a co-author of the reapplication.

Testing: pre-push clippy, treefmt, gitleaks, and cargo test passed.


Summary by cubic

Reapplies strict validation of --since/--until date bounds in the CLI and config. Previously we accepted loosely formatted values by stripping dashes, which could silently change which rows a report kept; now only YYYY-MM-DD or YYYYMMDD are accepted, dates must be real calendar dates, and invalid values exit with an error. The same check applies to since/until in config.

  • Exposes DATE_BOUND_FORMATS from ccusage-cli and updates normalize_date_bound to return Option<String> after validating and normalizing to YYYYMMDD.
  • CLI parser (ccusage-cli-parser) errors with “Expected YYYY-MM-DD or YYYYMMDD” and rejects undocumented spellings.
  • Config loader (ccusage-config) validates since/until early, surfaces a single config error, and keeps pi-store errors gated to readers; valid bounds are normalized before applying shared options.
  • Docs clarify accepted formats and inclusivity; tests cover invalid dates and both accepted formats.

Bold sections aren't required here, but migration notes follow.

  • Migration
    • CLI: ensure scripts and users pass YYYY-MM-DD or YYYYMMDD; invalid values now fail with a non-zero exit.
    • Config: set since/until as strings using those formats; non-strings or invalid dates fail config validation.
    • External users of ccusage-cli: update call sites to handle normalize_date_bound returning Option<String>.

Written for commit 6d00c28. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added date filtering with YYYY-MM-DD and YYYYMMDD formats.
    • Date filters now support inclusive ranges and configuration-file values.
  • Bug Fixes
    • Invalid formats, impossible dates, and non-calendar dates are rejected with clear errors and a non-zero exit code.
    • Improved handling of date-filter and command-line option validation.
  • Documentation
    • Documented supported date formats, validation rules, and public date-format information.

Reapply documented date-bound validation and reject impossible calendar dates in CLI and configuration files.

Co-authored-by: dok123 <[email protected]>
@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e2161b13-ff7a-46e9-97ae-ea3c1b82e1db

📥 Commits

Reviewing files that changed from the base of the PR and between a7227a8 and 6d00c28.

📒 Files selected for processing (8)
  • docs/guide/cli-options.md
  • rust/crates/ccusage-cli-parser/src/parser.rs
  • rust/crates/ccusage-cli-parser/src/tests.rs
  • rust/crates/ccusage-cli/README.md
  • rust/crates/ccusage-cli/src/lib.rs
  • rust/crates/ccusage-cli/src/types.rs
  • rust/crates/ccusage-config/src/config.rs
  • rust/crates/ccusage-core/src/summary.rs

📝 Walkthrough

Walkthrough

The change validates --since and --until as real dates in two formats, normalizes valid values to YYYYMMDD, and applies the same rules to configuration-file values.

Changes

Date-bound validation

Layer / File(s) Summary
Date-bound normalization contract
rust/crates/ccusage-cli/src/types.rs, rust/crates/ccusage-cli/src/lib.rs, rust/crates/ccusage-cli/README.md, rust/crates/ccusage-core/src/summary.rs
normalize_date_bound now accepts YYYY-MM-DD and YYYYMMDD, validates calendar dates, and returns Option<String>. The format constant is publicly re-exported and documented.
CLI date parsing
rust/crates/ccusage-cli-parser/src/parser.rs, rust/crates/ccusage-cli-parser/src/tests.rs, docs/guide/cli-options.md
--since and --until reject invalid values with descriptive errors. Tests and documentation cover accepted formats, inclusivity, and invalid dates.
Configuration date validation
rust/crates/ccusage-config/src/config.rs
Configuration date bounds now undergo type and calendar validation. Pi-store and date-bound errors use separate fields, and value-taking options are recognized during command detection.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: ⚪ Minimal · up to 6d00c

The PR reapplies documented date-bound validation without any supplied evidence of a current correctness, security, availability, or deployment risk; no actionable merge-blocking risk remains beyond normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant CLIUser
  participant CLIParser
  participant normalize_date_bound
  participant ConfigContext
  CLIUser->>CLIParser: provide --since or --until
  CLIParser->>normalize_date_bound: validate date bound
  normalize_date_bound-->>CLIParser: normalized YYYYMMDD or validation failure
  ConfigContext->>normalize_date_bound: validate configured date bound
  normalize_date_bound-->>ConfigContext: normalized value or date-bound error
  CLIParser-->>CLIUser: parsed option or error
Loading

Possibly related PRs

  • ccusage/ccusage#1604: Implements the same date-bound validation across the same parser, configuration, export, and test areas.
  • ccusage/ccusage#1607: Reintroduces the date-bound parsing, normalization, configuration, and test changes.
  • ccusage/ccusage#1157: Introduced the extracted CLI parser and normalize_date_bound logic extended by this change.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: restoring date-bound validation for the CLI.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/reapply-date-bound-coauthor

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
ccusage-guide 6d00c28 Commit Preview URL

Branch Preview URL
Aug 15 2026, 06:50 PM

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

This PR can reject a valid effective configuration bound when an overridden lower-precedence value is invalid.

Reviewed changes — Reviewed the complete date-bound validation reapplication across the CLI parser, shared normalization, configuration loading, tests, and documentation.

  • CLI validation — Restricts --since and --until to the documented formats and real calendar dates, then normalizes them to YYYYMMDD.
  • Configuration validation — Applies the same validation to raw config values and preserves command discovery for value-taking root options.
  • Regression coverage and documentation — Adds validation tests, normalization tests, and user-facing documentation for accepted formats and rejection behavior.

Pullfrog  | ⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to @v0 or keep the SHA fresh with Dependabot | Fix all ➔Fix 👍s ➔View workflow run | Using GPT Luna (free via Pullfrog for OSS) | 𝕏

/// so the check runs here and surfaces through `config_error` for every
/// command that applies shared options, not just the pi-store readers.
fn detect_date_bound_error(&self) -> Option<String> {
self.option_maps().into_iter().find_map(|options| {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This scans the maps in lower-to-higher precedence order and returns the first invalid value, while apply_config_to_shared() lets later maps override earlier ones. For example, an invalid defaults.since combined with a valid commands.daily.since now rejects ccusage daily before the valid effective bound is applied, so please validate the effective bound or otherwise ignore invalid values that are shadowed by a higher-precedence map.

@pkg-pr-new

pkg-pr-new Bot commented Aug 15, 2026

Copy link
Copy Markdown

Open in StackBlitz

ccusage

npx https://pkg.pr.new/ccusage@1608

@ccusage/ccusage-darwin-arm64

npx https://pkg.pr.new/@ccusage/ccusage-darwin-arm64@1608

@ccusage/ccusage-darwin-x64

npx https://pkg.pr.new/@ccusage/ccusage-darwin-x64@1608

@ccusage/ccusage-linux-arm64

npx https://pkg.pr.new/@ccusage/ccusage-linux-arm64@1608

@ccusage/ccusage-linux-x64

npx https://pkg.pr.new/@ccusage/ccusage-linux-x64@1608

@ccusage/ccusage-win32-x64

npx https://pkg.pr.new/@ccusage/ccusage-win32-x64@1608

commit: 6d00c28

@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: 6d00c281a474
Base SHA: a7227a895df0

This compares the PR package against the configured base package on the same CI runner.

Package runtime diagnostics

Compares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself.

Fixtures: Claude /home/runner/_work/_temp/ccusage-large-fixture (1.01 GiB, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 files)
All rows run --offline --json, measured by hyperfine with 0 warmups and 1 runs. This isolates wrapper overhead from the installed native optional dependency and the workspace release binary built on the runner.

Command Runtime Input Median Throughput Samples
claude --offline --json Package wrapper 1.01 GiB 345.2ms 2.92 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 309.5ms 3.25 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 121.4ms 8.30 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 96.6ms 10.42 GiB/s 1

Committed fixture performance

Committed small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage.

Fixtures: Claude apps/ccusage/test/fixtures/claude (0.00 MiB, 2 files), Codex apps/ccusage/test/fixtures/codex (0.00 MiB, 1 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published ccusage package from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 2 warmups and 7 runs.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude daily --offline --json 0.00 MiB 37.6ms 40.5ms 0.93x 55.00 MiB 55.00 MiB 1.00x 0.04 MiB/s 0.04 MiB/s
claude session --offline --json 0.00 MiB 33.3ms 31.6ms 1.06x 55.00 MiB 55.00 MiB 1.00x 0.05 MiB/s 0.05 MiB/s
codex daily --offline --json 0.00 MiB 32.6ms 29.1ms 1.12x 55.00 MiB 55.25 MiB 1.00x 0.03 MiB/s 0.03 MiB/s
codex session --offline --json 0.00 MiB 28.0ms 28.6ms 0.98x 55.25 MiB 55.25 MiB 1.00x 0.03 MiB/s 0.03 MiB/s

Large real-world-shaped fixture performance

Generated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures.

Fixtures: Claude /home/runner/_work/_temp/ccusage-large-fixture (1.01 GiB, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published ccusage package from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 0 warmups and 1 runs.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude --offline --json 1.01 GiB 358.8ms 339.5ms 1.06x 958.84 MiB 957.10 MiB 1.00x 2.81 GiB/s 2.97 GiB/s
codex --offline --json 1.01 GiB 120.4ms 120.0ms 1.00x 409.16 MiB 423.17 MiB 1.03x 8.36 GiB/s 8.39 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 19.09 KiB 19.09 KiB +0.00 KiB 1.00x
installed native package binary 4244.53 KiB 4246.22 KiB +1.69 KiB 1.00x

Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees.

@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: 6d00c281a474
Base SHA: a7227a895df0

This compares the Rust PR release binary against the configured base package on the same CI runner.

Package runtime diagnostics

Compares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself.

Fixtures: Claude /home/runner/_work/_temp/ccusage-large-fixture (1.01 GiB, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 files)
All rows run --offline --json, measured by hyperfine with 0 warmups and 1 runs. This isolates wrapper overhead from the installed native optional dependency and the workspace release binary built on the runner.

Command Runtime Input Median Throughput Samples
claude --offline --json Package wrapper 1.01 GiB 339.9ms 2.96 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 299.9ms 3.36 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 128.1ms 7.86 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 106.6ms 9.44 GiB/s 1

Committed fixture performance

Committed small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage.

Fixtures: Claude apps/ccusage/test/fixtures/claude (0.00 MiB, 2 files), Codex apps/ccusage/test/fixtures/codex (0.00 MiB, 1 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published native ccusage binary from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 2 warmups and 7 runs.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude daily --offline --json 0.00 MiB 44.9ms 9.2ms 4.87x 55.00 MiB 24.97 MiB 0.45x 0.03 MiB/s 0.17 MiB/s
claude session --offline --json 0.00 MiB 43.1ms 9.4ms 4.57x 55.00 MiB 24.97 MiB 0.45x 0.04 MiB/s 0.16 MiB/s
codex daily --offline --json 0.00 MiB 35.8ms 9.5ms 3.76x 55.25 MiB 24.70 MiB 0.45x 0.02 MiB/s 0.09 MiB/s
codex session --offline --json 0.00 MiB 34.5ms 9.3ms 3.73x 55.00 MiB 24.70 MiB 0.45x 0.02 MiB/s 0.09 MiB/s

Large real-world-shaped fixture performance

Generated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures.

Fixtures: Claude /home/runner/_work/_temp/ccusage-large-fixture (1.01 GiB, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published native ccusage binary from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 0 warmups and 1 runs.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude --offline --json 1.01 GiB 370.3ms 288.4ms 1.28x 950.85 MiB 967.10 MiB 1.02x 2.72 GiB/s 3.49 GiB/s
codex --offline --json 1.01 GiB 124.1ms 102.3ms 1.21x 415.16 MiB 413.16 MiB 1.00x 8.11 GiB/s 9.84 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 19.09 KiB 19.09 KiB +0.00 KiB 1.00x
installed native package binary 4244.53 KiB 4246.22 KiB +1.69 KiB 1.00x

Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 8 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="rust/crates/ccusage-config/src/config.rs">

<violation number="1" location="rust/crates/ccusage-config/src/config.rs:69">
P2: Config date-bound validation ignores config-layer and CLI precedence, so an invalid bound in a lower-precedence layer fails a command even when a valid value would override it. `detect_date_bound_error` scans every `option_maps()` layer and reports the first invalid `since`/`until`, while `apply_shared_options` deliberately drops unnormalizable low-layer values in favor of higher-precedence ones. Because `config_error()` is consulted in `parser.rs` before `apply_shared` and before the CLI `--since`/`--until` is parsed, an invalid `since` under `defaults` (or an unconsumed layer) now hard-fails commands that never apply it, including `statusline`/`blocks`, and can no longer be rescued by a valid command-specific config or CLI override. Validate against the effective merged value (the value that actually wins after layering) rather than each raw layer.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

/// parser gives `--since` / `--until`. `apply_shared_options` cannot fail,
/// so the check runs here and surfaces through `config_error` for every
/// command that applies shared options, not just the pi-store readers.
fn detect_date_bound_error(&self) -> Option<String> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Config date-bound validation ignores config-layer and CLI precedence, so an invalid bound in a lower-precedence layer fails a command even when a valid value would override it. detect_date_bound_error scans every option_maps() layer and reports the first invalid since/until, while apply_shared_options deliberately drops unnormalizable low-layer values in favor of higher-precedence ones. Because config_error() is consulted in parser.rs before apply_shared and before the CLI --since/--until is parsed, an invalid since under defaults (or an unconsumed layer) now hard-fails commands that never apply it, including statusline/blocks, and can no longer be rescued by a valid command-specific config or CLI override. Validate against the effective merged value (the value that actually wins after layering) rather than each raw layer.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At rust/crates/ccusage-config/src/config.rs, line 69:

<comment>Config date-bound validation ignores config-layer and CLI precedence, so an invalid bound in a lower-precedence layer fails a command even when a valid value would override it. `detect_date_bound_error` scans every `option_maps()` layer and reports the first invalid `since`/`until`, while `apply_shared_options` deliberately drops unnormalizable low-layer values in favor of higher-precedence ones. Because `config_error()` is consulted in `parser.rs` before `apply_shared` and before the CLI `--since`/`--until` is parsed, an invalid `since` under `defaults` (or an unconsumed layer) now hard-fails commands that never apply it, including `statusline`/`blocks`, and can no longer be rescued by a valid command-specific config or CLI override. Validate against the effective merged value (the value that actually wins after layering) rather than each raw layer.</comment>

<file context>
@@ -29,25 +29,64 @@ pub struct ConfigContext {
+    /// parser gives `--since` / `--until`. `apply_shared_options` cannot fail,
+    /// so the check runs here and surfaces through `config_error` for every
+    /// command that applies shared options, not just the pi-store readers.
+    fn detect_date_bound_error(&self) -> Option<String> {
+        self.option_maps().into_iter().find_map(|options| {
+            [
</file context>

@ryoppippi
ryoppippi merged commit a6eefcd into main Aug 15, 2026
42 checks passed
@ryoppippi
ryoppippi deleted the codex/reapply-date-bound-coauthor branch August 15, 2026 18:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant