Skip to content

Judge mobile policy time windows at the stored time floor too - #1118

Merged
kwsantiago merged 1 commit into
mainfrom
policy-time-windows
Oct 25, 2026
Merged

kwsantiago merged 1 commit into
mainfrom
policy-time-windows

Conversation

@kwsantiago

@kwsantiago kwsantiago commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

What

  • The mobile policy's allowed-hours and allowed-days rules are now judged at the PolicyClock the caller establishes, not Utc::now(). Both the device reading and the floored reading have to fall inside the window.
  • A spend recorded for the daily and weekly limits is now dated at the floored time rather than the device clock. While a policy depends on the floor, an unusable floor refuses the recording instead of falling back to the device clock.
  • The rule docs on PolicyRules now say what the time rules are worth against whoever holds the device.

Why

The time-window rules were the one place in evaluate that read the wall clock directly, so they saw a different time from the expiry check and ignored the stored floor entirely. A clock set back behind the floor is now refused.

Velocity spends were stamped by the device clock. A spend made with the clock set back was dated early and left the 24-hour window early once the clock was put right, so the daily limit could be spent twice in a short time. Totals are still measured on the device clock, which is the reading that can only count more.

Limits

Without a time source the holder cannot set, these rules are a convenience against mistakes rather than a control against the holder, and the docs now say so. Setting the clock forward is not detected. The floor's own limits are documented on allowed_hours.

Tests

  • Hour windows at exact instants and edges, a window that wraps past midnight, and day rules.
  • A clock set back behind the floor is refused for both rules. Each reading is checked on its own, so a rule that read only one reading would fail a test.
  • Spends are dated at the floor end to end through record_policy_transaction, and an unusable floor under a policy refuses the recording.
  • Mutation: judging only the raw clock fails the set-back tests. Stamping at the raw clock fails the dating test. Dropping the refusal fails the unusable-floor test.
  • cargo test -p keep-mobile (548 tests) and workspace clippy with the CI features pass.

Summary by CodeRabbit

  • Bug Fixes
    • Policy time-window checks now use the configured clock and effective time floor, including for ranges that cross midnight.
    • Transactions are dated using the effective time floor when available. If it cannot be used while a policy is active, the transaction is rejected rather than recorded with an unreliable timestamp.
    • Without a configured policy, transaction recording falls back to UTC.
    • Improved handling of clock changes and invalid time readings to prevent transactions from passing restrictions when both clock readings do not qualify.

The allowed-hours and allowed-days rules read Utc::now() directly, bypassing the clock every other validity decision is judged at. They now take the caller's PolicyClock and require both the device reading and the floored reading to fall inside the window, so a clock set back behind a later time the app has already seen is refused.

A spend recorded for the daily and weekly limits is now dated at the floored time rather than the device clock. Dated by a clock set back, it left the limit window early once the clock was put right, and the limit could be spent again.

The rule docs now say what these rules are worth against whoever holds the device. The floor never rises past the clock and does not follow real time across a reboot, and a clock set forward is not caught at all, so the time rules are a convenience until there is a time source the holder cannot set.
@coderabbitai

coderabbitai Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 3a9be652-d57a-4736-8b57-422185e77986
Commits

Reviewing files that changed from the base of the PR and between 6bd7753 and dfd9afc.

Files selected for processing: 3
  • keep-mobile/src/lib.rs
  • keep-mobile/src/policy.rs
  • keep-mobile/src/velocity.rs

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Walkthrough

Policy time-window checks now use supplied and floored clock readings. Spend recording uses an explicit timestamp, selected from the effective time floor when available, and passes it to velocity tracking.

Changes

Policy Clock and Spend Recording

Layer / File(s) Summary
Evaluate time windows
keep-mobile/src/policy.rs
Hour and day restrictions check both the supplied clock and the effective floored time. Unrepresentable readings deny evaluation. Tests cover window boundaries, rollback, and overnight ranges.
Record spends with explicit timestamps
keep-mobile/src/lib.rs, keep-mobile/src/policy.rs, keep-mobile/src/velocity.rs
KeepMobile::record_policy_transaction selects the spend timestamp and returns InvalidPolicy if the floor is unusable while a policy is configured. Policy recording passes that timestamp to VelocityTracker::record_at. Tests cover floor-based timestamps and refusal to record when the floor is unusable under a policy.

Priority: Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Merge Risk: Minimal · up to dfd9a

No identified issue prevents merging after normal checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 65.38% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 26 functions across 3 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 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: mobile policy time windows are evaluated against the stored time floor in addition to the device time.
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: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

I’m a rabbit, and I check the clock,
Two readings keep each window in view.
A floored timestamp marks each spend,
The tracker saves the moment true.
I twitch my nose and hop away.

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

@kwsantiago
kwsantiago merged commit 1e1bc82 into main Oct 25, 2026
23 of 24 checks passed
@kwsantiago
kwsantiago deleted the policy-time-windows branch October 25, 2026 13:54
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