Skip to content

fix(usage): reject inverted startDate-endDate range in usage.cost and sessions.usage#94096

Merged
steipete merged 3 commits into
openclaw:mainfrom
Alix-007:fix/usage-reject-inverted-date-range
Jun 30, 2026
Merged

fix(usage): reject inverted startDate-endDate range in usage.cost and sessions.usage#94096
steipete merged 3 commits into
openclaw:mainfrom
Alix-007:fix/usage-reject-inverted-date-range

Conversation

@Alix-007

@Alix-007 Alix-007 commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

usage.cost / sessions.usage accept an inverted explicit date range (startDate after endDate) from any gateway client. parseDateRange in src/gateway/server-methods/usage.ts never checks startMs <= endMs when both dates are explicitly given, so a backwards window (startMs > endMs) reaches the cost/session loader and respond(true, ...) returns an empty/wrong result with no error — a silently-wrong-window class bug. Callers (CLI/UI/scripts) get a successful response that hides the bad input instead of a clear rejection. This is the symmetric gap to merged #93745 (invalid calendar date rejection) and sibling to merged #93903 (cron absolute-timestamp validation): same family, the missing case where both dates are individually valid but ordered backwards.

Evidence

Real exported usageHandlers["usage.cost"] and usageHandlers["sessions.usage"] from the changed usage.ts were driven under tsx on Node v22.22.0 with only the outermost data IO in src/infra/session-cost-usage.ts replaced (via module.register()) by recorders capturing the (startMs,endMs) window; all validation runs as production code.

  • After fix (inverted {start=2026-02-03, end=2026-02-02}): both handlers return respond.ok=false, error={code:"INVALID_REQUEST", message:"startDate must not be after endDate"}, and the loader is never reached (reached loader? = false).
  • Negative control (parent usage.ts, fix removed — hasInvertedExplicitDateRange = undefined): same inverted range is silently accepted (respond.ok=true, error=null) and the real loader is reached with a backwards window (loadCostUsageSummaryFromCache(startMs=1770076800000,endMs=1770076799999,backwards=true) / discoverAllSessions(...backwards=true)).
  • Forward-range control {start=2026-02-01, end=2026-02-02}: still passes (respond.ok=true, reachedLoader=true, err=null) on the patched tree — the fix only rejects genuinely inverted ranges.
  • Vitest: 2 files / 44 tests passed (28s), including the new hasInvertedExplicitDateRange boundary case and the table-driven usage.cost / sessions.usage rejection case.

Full proof transcript (sanity line, both handlers, negative + forward controls) is in Real behavior proof below.

Summary

#93745 added findInvalidExplicitDate to reject invalid calendar dates in usage.cost / sessions.usage (merged). But parseDateRange in src/gateway/server-methods/usage.ts does not validate startMs <= endMs when both dates are explicitly given — an inverted range (startDate after endDate) yields a backwards window, and the cost loader silently returns empty while respond(true) succeeds. This is the symmetric gap to #93745 (same "silently wrong window" family; sibling to merged #93903's cron absolute-timestamp validation).

Changes

  • Added hasInvertedExplicitDateRange helper (reusing extracted hasExplicitDateValue). Both usage.cost and sessions.usage now reject startDate > endDate with INVALID_REQUEST: "startDate must not be after endDate" before touching runtime config / cost loader / session scan. parseDateRange's return contract is unchanged (validation is at the handler entry). testApi exposes the helper. +96/-1 across 2 files (one is the test).

Real behavior proof

Behavior addressed: an inverted explicit date range (startDate after endDate) used to be silently accepted by usage.cost / sessions.usageparseDateRange produced a backwards window (startMs > endMs), the real cost/session loader was reached with that backwards window, and respond(true, ...) returned an empty/wrong result with no error. The fix rejects it with respond(false, INVALID_REQUEST "startDate must not be after endDate") before any loader is touched.

Real environment tested: real exported usageHandlers["usage.cost"] and usageHandlers["sessions.usage"] imported from the changed src/gateway/server-methods/usage.ts and driven under tsx on Node v22.22.0 (Linux). Only the outermost data IO in src/infra/session-cost-usage.ts (loadCostUsageSummaryFromCache, discoverAllSessions, loadSessionLogs) was replaced — via a module.register() loader hook — with recorders that capture the exact (startMs,endMs) window each handler computes and then return empty data. Everything else in the handler (param validation, hasInvertedExplicitDateRange, resolveDateInterpretation, parseDateRange) runs as production code.

Exact steps or command run after this patch:

  1. git worktree add PR head fix/usage-reject-inverted-date-range.
  2. tsx real-runtime proof drives both handlers with an inverted range {startDate: "2026-02-03", endDate: "2026-02-02"} and reads back the respond(ok, payload, error) args plus whether the real loader was reached and with what window.
  3. node scripts/run-vitest.mjs src/gateway/server-methods/usage.test.ts --run.
  4. Negative control: restore the pre-PR (parent) usage.ts (fix removed, hasInvertedExplicitDateRange absent) and re-run the same proof.
  5. Forward-range control {startDate: "2026-02-01", endDate: "2026-02-02"} driven through both handlers to confirm the fix is not over-broad.

Evidence after fix (patched tree):

[sanity] inverted range parseDateToMs: startMs=1770076800000 endMs=1769990400000 startMs>endMs=true
---- usage.cost : INVERTED range {start=2026-02-03, end=2026-02-02} ----
  respond.ok      = false
  respond.error   = {"code":"INVALID_REQUEST","message":"startDate must not be after endDate"}
  reached loader? = false
  => PATCHED behavior: REJECTED (respond.false + INVALID_REQUEST, loader NOT reached)
---- sessions.usage : INVERTED range {start=2026-02-03, end=2026-02-02} ----
  respond.ok      = false
  respond.error   = {"code":"INVALID_REQUEST","message":"startDate must not be after endDate"}
  reached loader? = false
  => PATCHED behavior: REJECTED
---- negative control: FORWARD range {start=2026-02-01, end=2026-02-02} must still pass ----
  usage.cost:     respond.ok=true reachedLoader=true err=null
  sessions.usage: respond.ok=true reachedLoader=true err=null
RESULT: PASS

Negative control (parent usage.ts, fix removed) — inverted range is silently accepted, the real loader is reached with a backwards window, no error:

fix present in this checkout? hasInvertedExplicitDateRange = undefined
---- usage.cost : INVERTED range {start=2026-02-03, end=2026-02-02} ----
  respond.ok      = true
  respond.error   = null
  reached loader? = true  loadCostUsageSummaryFromCache(startMs=1770076800000,endMs=1770076799999,backwards=true)
  => PRE-PATCH BUG: SILENTLY ACCEPTED inverted range
---- sessions.usage : INVERTED range {start=2026-02-03, end=2026-02-02} ----
  respond.ok      = true
  respond.error   = null
  reached loader? = true  discoverAllSessions(startMs=1770076800000,endMs=1770076799999,backwards=true)
  => PRE-PATCH BUG: SILENTLY ACCEPTED inverted range

Vitest: 2 files / 44 tests passed (28s), including the new helper boundary case and the table-driven usage.cost / sessions.usage rejection case.

Observed result after fix: both handlers reject the inverted range with respond(false, undefined, {code: "INVALID_REQUEST", message: "startDate must not be after endDate"}) and the cost/session loader is never invoked; the forward range {2026-02-01 → 2026-02-02} still resolves and reaches the loader (respond(true)), so the fix only rejects genuinely inverted ranges. Reverting the source flips this back to silent acceptance with a backwards startMs > endMs window.

What was not tested: real on-disk cost/session data aggregation (the loaders were stubbed to return empty data — they are the layer below the validation under test); the rejection happens before any loader runs, so loader internals are out of scope here. UI/client surfacing of the new error and timezone/utcOffset interaction beyond the parsed-window comparison were not exercised.

Scope / context

No linked issue — symmetric follow-up to merged #93745 (usage invalid-date rejection) and #93903 (cron invalid absolute timestamp). No competing PR touches this gap.

Real behavior proof

Behavior addressed: usage.cost and sessions.usage used to accept an explicit inverted date range where startDate is after endDate. That produced a backwards startMs/endMs window, reached the cost/session loader, and returned a successful empty or wrong result. This patch rejects that input before any loader runs.

Real environment tested: Local Linux runtime with Node v22.22.0 and tsx, importing the real exported usageHandlers["usage.cost"] and usageHandlers["sessions.usage"] from src/gateway/server-methods/usage.ts. Only the outermost data IO in src/infra/session-cost-usage.ts was replaced with recorder functions so the computed startMs/endMs windows could be captured; validation and date parsing ran as production code.

Exact steps or command run after this patch: In the PR head worktree fork/fix/usage-reject-inverted-date-range, ran a tsx proof script that drives both handlers with {startDate:"2026-02-03", endDate:"2026-02-02"}, records respond(ok,payload,error), records whether loaders are reached, then repeats a forward-range control and a negative control with the parent usage.ts restored. Also ran node scripts/run-vitest.mjs src/gateway/server-methods/usage.test.ts --run.

Evidence after fix: Live terminal output from the proof script:

[sanity] inverted range parseDateToMs: startMs=1770076800000 endMs=1769990400000 startMs>endMs=true
---- usage.cost : INVERTED range {start=2026-02-03, end=2026-02-02} ----
  respond.ok      = false
  respond.error   = {"code":"INVALID_REQUEST","message":"startDate must not be after endDate"}
  reached loader? = false
  => PATCHED behavior: REJECTED (respond.false + INVALID_REQUEST, loader NOT reached)
---- sessions.usage : INVERTED range {start=2026-02-03, end=2026-02-02} ----
  respond.ok      = false
  respond.error   = {"code":"INVALID_REQUEST","message":"startDate must not be after endDate"}
  reached loader? = false
  => PATCHED behavior: REJECTED
---- negative control: FORWARD range {start=2026-02-01, end=2026-02-02} must still pass ----
  usage.cost:     respond.ok=true reachedLoader=true err=null
  sessions.usage: respond.ok=true reachedLoader=true err=null
RESULT: PASS

Negative control with the parent usage.ts restored showed respond.ok=true, respond.error=null, and loaders reached with backwards=true windows for both handlers.

Observed result after fix: Both handlers now return respond(false, undefined, {code:"INVALID_REQUEST", message:"startDate must not be after endDate"}) for the inverted range and never invoke the cost/session loader. The forward range still succeeds and reaches the loader. Vitest passed 44 tests.

What was not tested: Real on-disk cost/session data aggregation was not exercised because the loaders were stubbed below the validation layer. UI/client rendering of the new error and deeper timezone/utcOffset behavior beyond the parsed-window comparison were not exercised.

@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. size: S labels Jun 17, 2026
@Alix-007
Alix-007 force-pushed the fix/usage-reject-inverted-date-range branch from bba436c to 71a9928 Compare June 17, 2026 10:37
@clawsweeper

clawsweeper Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 30, 2026, 3:49 PM ET / 19:49 UTC.

Summary
The PR centralizes usage date-range validation in resolveDateRange so usage.cost and sessions.usage reject invalid or inverted explicit dates, with focused gateway tests updated around that contract.

PR surface: Source -4, Tests +36. Total +32 across 2 files.

Reproducibility: yes. Source inspection shows current main builds an inverted parseDateRange window for valid reversed explicit dates and passes it into both usage loaders; the PR body also includes parent negative-control terminal proof and a forward-range control.

Review metrics: 1 noteworthy metric.

  • Gateway RPC Contract Change: 2 methods changed. Both usage.cost and sessions.usage change a currently accepted request shape into INVALID_REQUEST, so maintainers should notice the compatibility choice before merge.

Root-cause cluster
Relationship: canonical
Canonical: #94096
Summary: This PR is the canonical open item for inverted explicit usage date ranges; related merged PRs cover adjacent date-validation gaps only.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • none.

Risk before merge

  • [P1] Existing gateway clients that currently send reversed but shape-valid explicit usage date ranges will receive INVALID_REQUEST instead of a successful empty or backwards-window response; that stricter fail-closed RPC behavior needs maintainer acceptance before merge.

Maintainer options:

  1. Accept Strict Usage Date Validation (recommended)
    Land this PR if maintainers agree reversed explicit usage dates should fail closed at the gateway RPC boundary instead of returning a successful empty or backwards-window result.
  2. Require A Compatibility-Preserving Design
    Ask for a different design before merge if any supported client intentionally relies on reversed explicit ranges returning success.

Next step before merge

  • No automated repair is needed; the remaining action is maintainer acceptance or rejection of the stricter fail-closed gateway RPC behavior.

Security
Cleared: The diff only changes gateway usage validation and focused tests, with no dependency, workflow, secret, permission, or code-execution surface change.

Review details

Best possible solution:

Land the centralized validation after maintainers accept the stricter gateway RPC contract; otherwise ask for a compatibility-preserving design for reversed explicit ranges.

Do we have a high-confidence way to reproduce the issue?

Yes. Source inspection shows current main builds an inverted parseDateRange window for valid reversed explicit dates and passes it into both usage loaders; the PR body also includes parent negative-control terminal proof and a forward-range control.

Is this the best way to solve the issue?

Yes, pending maintainer compatibility acceptance. Centralizing invalid-date and inverted-range checks in resolveDateRange is cleaner than duplicating handler guards, and the tests preserve forward ranges, defaults, and existing date-interpretation behavior.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 076da567f434.

Label changes

Label justifications:

  • P2: This is a bounded gateway usage validation bugfix with limited blast radius and no emergency availability, security, or data-loss signal.
  • merge-risk: 🚨 compatibility: The PR intentionally changes accepted gateway RPC behavior for reversed explicit date ranges from success to INVALID_REQUEST.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body includes copied terminal output driving the real exported handlers after the patch, a parent negative control, and a forward-range control, which is sufficient for this non-visual gateway RPC change.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes copied terminal output driving the real exported handlers after the patch, a parent negative control, and a forward-range control, which is sufficient for this non-visual gateway RPC change.
Evidence reviewed

PR surface:

Source -4, Tests +36. Total +32 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 37 41 -4
Tests 1 88 52 +36
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 125 93 +32

What I checked:

Likely related people:

  • Takhoffman: Authored the merged token usage dashboard work that added the sessions.usage gateway surface, date filtering, and UI usage controller plumbing. (role: feature introducer and adjacent owner; confidence: high; commits: 8a352c8f9dfd, 7a7e4cd4c481; files: src/gateway/server-methods/usage.ts, ui/src/ui/controllers/usage.ts, src/gateway/server-methods/usage.sessions-usage.test.ts)
  • huntharo: Authored the merged local-time usage PR that added mode and utcOffset behavior for the same explicit date-range inputs. (role: date-range contract contributor; confidence: high; commits: 844d84a7f53b; files: src/gateway/server-methods/usage.ts, packages/gateway-protocol/src/schema/sessions.ts, ui/src/ui/controllers/usage.ts)
  • steipete: Earlier usage cost summary/cache commits touched this path, and the latest PR-head commit refactors the proposed fix into centralized resolveDateRange validation. (role: recent area contributor and PR-head refactor author; confidence: high; commits: 3ce1ee84ace4, 0e17e55be902, c054ea08a98a; files: src/gateway/server-methods/usage.ts, src/gateway/server-methods/usage.test.ts)
  • harjothkhara: Authored the merged sibling PR that added invalid explicit calendar-date rejection for the same usage.cost and sessions.usage handlers. (role: adjacent validation contributor; confidence: medium; commits: a3f3b043c99d; files: src/gateway/server-methods/usage.ts, src/gateway/server-methods/usage.test.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels Jun 17, 2026
@Alix-007
Alix-007 force-pushed the fix/usage-reject-inverted-date-range branch from 71a9928 to eb91411 Compare June 18, 2026 02:13
@Alix-007

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Added/clarified real-behavior proof for the inverted explicit date-range validation.

Behavior addressed
Before this patch, usage.cost and sessions.usage accepted valid-but-inverted explicit date ranges (startDate > endDate), proceeded into the handler path, and could silently return an empty/backwards window. After the patch, both handlers reject the request with respond(false) and INVALID_REQUEST: startDate must not be after endDate before cost/session loading.

Focused verification run on this branch

  • node scripts/run-vitest.mjs src/gateway/server-methods/usage.test.ts -> 2 files / 44 tests passed
  • node_modules/.bin/oxlint src/gateway/server-methods/usage.ts src/gateway/server-methods/usage.test.ts -> clean

The focused test exercises the real exported handler/testApi path for both usage.cost and sessions.usage, including the guard that prevents loadCostUsageSummaryFromCache from being called on inverted ranges.

Typecheck note
I also tried node_modules/.bin/tsgo -p tsconfig.core.json; it is currently blocked by an unrelated repo baseline error in src/config/io.ts / src/secrets/config-io.ts about configWritePostCommitRollback, not by this PR's touched files.

@clawsweeper

clawsweeper Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@openclaw-barnacle openclaw-barnacle Bot added the triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. label Jun 20, 2026
@Alix-007

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review — Added a Real behavior proof section. It drives the real usage.cost / sessions.usage handlers; post-patch an inverted startDate>endDate range is rejected with INVALID_REQUEST before any cost/session loader runs, while a negative control on the pre-patch code silently accepts it and queries a backwards window. Forward ranges still pass (no over-rejection). Vitest (44 tests) passes.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 20, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. label Jun 21, 2026
@Alix-007

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review — Added the What Problem This Solves and Evidence headings the proof workflow expects (proof content unchanged, just restructured under the required sections). This should clear needs-pr-context.

@clawsweeper clawsweeper Bot added status: 🔁 re-review loop A fresh ClawSweeper review was explicitly requested after the latest review. and removed status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jun 21, 2026
@Alix-007

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review — Updated the PR body with a machine-readable ## Real behavior proof section using the exact field names required by the current proof policy. I verified the updated body locally against evaluateRealBehaviorProof and the latest GitHub Real behavior proof check is now passing.

@clawsweeper clawsweeper Bot added status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed status: 🔁 re-review loop A fresh ClawSweeper review was explicitly requested after the latest review. labels Jun 23, 2026
@steipete steipete self-assigned this Jun 30, 2026
@steipete
steipete force-pushed the fix/usage-reject-inverted-date-range branch 2 times, most recently from b215447 to 348d141 Compare June 30, 2026 19:14
@steipete
steipete force-pushed the fix/usage-reject-inverted-date-range branch from 348d141 to c054ea0 Compare June 30, 2026 19:42
@steipete

Copy link
Copy Markdown
Contributor

Land-ready maintainer pass on exact head c054ea08a98ad57928f0ef20997da54cb9b2532c:

  • Consolidated the PR's second date parser and duplicated handler guards into one discriminated resolveDateRange result. Final production diff is +37/-41 versus current main (net -4); invalid and reversed ranges cannot be consumed as timestamps.
  • Focused proof: node scripts/run-vitest.mjs src/gateway/server-methods/usage.test.ts src/gateway/server-methods/usage.sessions-usage.test.ts — 4 files, 88 tests passed.
  • Real exported-handler proof: both usage.cost and sessions.usage returned INVALID_REQUEST for 2026-02-03 through 2026-02-02 under UTC+5:30; a throwing getRuntimeConfig proved neither path crossed into loader setup. The forward fixed-offset control resolved to an ordered range.
  • Fresh autoreview: clean, no accepted/actionable findings (0.98 confidence).
  • Exact-head hosted CI: run 28471202153, all 67 relevant checks green, including gateway CodeQL/security and QA Smoke.
  • Repository landing verifier: exact-head hosted CI/Testbox gates passed.

Remote Crabbox was unavailable because this machine lacks the Blacksmith CLI and broker credentials; the deterministic gateway boundary was exercised through the real exported handlers.

@steipete
steipete merged commit 640258d into openclaw:main Jun 30, 2026
96 checks passed
@steipete

Copy link
Copy Markdown
Contributor

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 1, 2026
… sessions.usage (openclaw#94096)

* fix(usage): reject inverted startDate-endDate range

* chore: retrigger CI for real behavior proof check

* refactor(usage): resolve validated date ranges once

---------

Co-authored-by: Peter Steinberger <[email protected]>
QiuYuang pushed a commit to QiuYuang/openclaw that referenced this pull request Jul 1, 2026
… sessions.usage (openclaw#94096)

* fix(usage): reject inverted startDate-endDate range

* chore: retrigger CI for real behavior proof check

* refactor(usage): resolve validated date ranges once

---------

Co-authored-by: Peter Steinberger <[email protected]>
chenyangjun-xy pushed a commit to chenyangjun-xy/openclaw that referenced this pull request Jul 1, 2026
… sessions.usage (openclaw#94096)

* fix(usage): reject inverted startDate-endDate range

* chore: retrigger CI for real behavior proof check

* refactor(usage): resolve validated date ranges once

---------

Co-authored-by: Peter Steinberger <[email protected]>
chenyangjun-xy pushed a commit to chenyangjun-xy/openclaw that referenced this pull request Jul 3, 2026
… sessions.usage (openclaw#94096)

* fix(usage): reject inverted startDate-endDate range

* chore: retrigger CI for real behavior proof check

* refactor(usage): resolve validated date ranges once

---------

Co-authored-by: Peter Steinberger <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gateway Gateway runtime merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: M status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants