Skip to content

fix(quick-router): abstain on absolute setpoint schedules and conditions - #916

Open
RealDiligent wants to merge 3 commits into
GeniePod:mainfrom
RealDiligent:fix/critical-issue-setpoint-schedule-abstain
Open

fix(quick-router): abstain on absolute setpoint schedules and conditions#916
RealDiligent wants to merge 3 commits into
GeniePod:mainfrom
RealDiligent:fix/critical-issue-setpoint-schedule-abstain

Conversation

@RealDiligent

@RealDiligent RealDiligent commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Closes #914

Summary

Relative in <duration> setpoints already abstained (#829), but absolute schedules (at 9pm, tonight), conditionals (when I get home), and exclusions (except the bedroom) still actuated immediately and dropped the qualifier — including dimming rooms the caller asked to exclude.

Root cause

The set/preheat branch only guarded in <time_expression>. parse_temperature_target still read the numeric setpoint out of strings like 68 at 9pm or 40 percent except the bedroom.

Fix

  • Add setpoint_has_schedule_or_condition mirroring simple_turn_request multi-clause abstain (when / unless / if / except / only / and / everything).
  • Detect trailing absolute schedule words (tonight, before bed, …) and to <value> at <clock/time> tails (so set the thermostat at 68 still works as the value separator).
  • Cover brightness setpoints the same way (set the lights to 30 percent at 9pm).

Impact

Scheduled/conditional setpoints abstain for LLM grounding; bare setpoints and room-qualified in the den keep actuating now.

Test plan

  • New unit test setpoint_with_absolute_schedule_or_condition_abstains covers the issue reproductions and keep-alive cases.
  • Full workspace cargo test — CI validation required.

Real Behavior Proof

  • I have built and run the affected code locally (or noted why I could not).
  • I have verified the change end-to-end on Jetson hardware.
  • I have NOT verified on Jetson hardware, and I explain the equivalent verification path or validation gap below.

CI-only / static review on Windows dev host. Verification is the new route() unit tests plus full workspace CI on Linux.

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of thermostat “set”/“preheat” requests that include schedule, conditional, or exclusion qualifiers.
    • Commands like “set to 68 at 9pm,” “when I get home,” or “except the bedroom” are no longer applied immediately (the qualifier is preserved instead of being dropped).
    • Unqualified thermostat adjustments continue to work as expected.

@github-actions github-actions Bot added the bug Something isn't working label Jul 30, 2026
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@RealDiligent, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 44 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c6490b6a-585b-460b-9717-5e0b6b86b832

📥 Commits

Reviewing files that changed from the base of the PR and between 6fafa49 and d4c8505.

📒 Files selected for processing (1)
  • crates/genie-core/src/tools/quick.rs
📝 Walkthrough

Walkthrough

The quick router detects absolute schedules, conditionals, and exclusions in set/preheat setpoints and abstains instead of actuating immediately. Tests cover qualified and unqualified forms.

Changes

Qualified setpoint routing

Layer / File(s) Summary
Schedule and condition detection
crates/genie-core/src/tools/quick.rs
The numeric setpoint path detects schedule, conditional, exclusion, and absolute time qualifiers before routing an immediate home-control action. Tests preserve routing for unqualified values and at value separators.

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

Possibly related PRs

Suggested labels: bug

Suggested reviewers: matedev01, ultrahighsuper, yurii214

🚥 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 matches the main change: quick-router abstains on absolute setpoint schedules and conditions.
Linked Issues check ✅ Passed The changes add abstention for absolute schedules, conditions, and exclusions on setpoints while preserving unqualified actuation, matching #914.
Out of Scope Changes check ✅ Passed The diff stays focused on quick-router setpoint handling and a targeted unit test, with no unrelated feature additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Fix failing CI checks
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/genie-core/src/tools/quick.rs`:
- Around line 2051-2056: Update the scheduled-setpoint detection around
is_absolute_schedule_tail to inspect the final “ at ” tail whether the numeric
value follows “to” or “at”, so inputs like “set the thermostat at 68 at 9pm” are
recognized as scheduled rather than actuated immediately. Add a regression test
covering this “at”-separator form.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 32e85a42-fa01-4157-bacc-c33cea6b844f

📥 Commits

Reviewing files that changed from the base of the PR and between 02a577d and 84b15ec.

📒 Files selected for processing (1)
  • crates/genie-core/src/tools/quick.rs

Comment on lines +2051 to +2056
if let Some((_, after_to)) = rest.split_once(" to ")
&& let Some((_, at_tail)) = after_to.rsplit_once(" at ")
{
let at_tail = at_tail.trim();
if is_absolute_schedule_tail(at_tail) {
return true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Handle scheduled setpoints using at as the value separator.

set the thermostat at 68 at 9pm bypasses this to-only branch, then parse_temperature_target reads 68 and actuates immediately. Inspect the final at tail regardless of whether the numeric value was introduced by to or at, and add this regression case.

Proposed fix
-    if let Some((_, after_to)) = rest.split_once(" to ")
-        && let Some((_, at_tail)) = after_to.rsplit_once(" at ")
-    {
-        let at_tail = at_tail.trim();
-        if is_absolute_schedule_tail(at_tail) {
-            return true;
-        }
+    if let Some((before_at, at_tail)) = rest.rsplit_once(" at ")
+        && parse_temperature_target(before_at).is_some()
+        && is_absolute_schedule_tail(at_tail.trim())
+    {
+        return true;
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if let Some((_, after_to)) = rest.split_once(" to ")
&& let Some((_, at_tail)) = after_to.rsplit_once(" at ")
{
let at_tail = at_tail.trim();
if is_absolute_schedule_tail(at_tail) {
return true;
if let Some((before_at, at_tail)) = rest.rsplit_once(" at ")
&& parse_temperature_target(before_at).is_some()
&& is_absolute_schedule_tail(at_tail.trim())
{
return true;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/genie-core/src/tools/quick.rs` around lines 2051 - 2056, Update the
scheduled-setpoint detection around is_absolute_schedule_tail to inspect the
final “ at ” tail whether the numeric value follows “to” or “at”, so inputs like
“set the thermostat at 68 at 9pm” are recognized as scheduled rather than
actuated immediately. Add a regression test covering this “at”-separator form.

jak-glitch and others added 2 commits July 30, 2026 23:18
Closes GeniePod#914

Relative "in <duration>" setpoints already abstained (GeniePod#829), but absolute
schedules ("at 9pm", "tonight"), conditionals ("when I get home"), and
exclusions ("except the bedroom") still actuated now and dropped the
qualifier. Mirror the turn_on/turn_off multi-clause abstain so the LLM can
arm them, while keeping bare setpoints and "at"-as-value-separator.

Co-authored-by: Cursor <cursoragent@cursor.com>
set_brightness keeps a float value argument; assert against json!(40.0).

Co-authored-by: Cursor <cursoragent@cursor.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
crates/genie-core/src/tools/quick.rs (1)

2051-2056: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

The at value-separator form still bypasses scheduled-setpoint detection.

set the thermostat at 68 at 9pm has no " to " clause, so this block never inspects the final " at " tail; parse_temperature_target then actuates immediately and drops the schedule. Add a separator-independent check and regression cases for thermostat and brightness forms. This is the same unresolved finding from the previous review.

Proposed fix
-    if let Some((_, after_to)) = rest.split_once(" to ")
-        && let Some((_, at_tail)) = after_to.rsplit_once(" at ")
+    if let Some((before_at, at_tail)) = rest.rsplit_once(" at ")
+        && parse_temperature_target(before_at).is_some()
     {
         let at_tail = at_tail.trim();
         if is_absolute_schedule_tail(at_tail) {
             return true;
         }

Also applies to: 6438-6485

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/genie-core/src/tools/quick.rs` around lines 2051 - 2056, Update the
scheduled-setpoint detection around is_absolute_schedule_tail so it
independently inspects the final “ at ” tail, rather than requiring a preceding
“ to ” clause; ensure forms like “set the thermostat at 68 at 9pm” are
recognized before parse_temperature_target actuates immediately. Add regression
coverage for both thermostat and brightness value-separator forms, preserving
existing “to … at …” behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@crates/genie-core/src/tools/quick.rs`:
- Around line 2051-2056: Update the scheduled-setpoint detection around
is_absolute_schedule_tail so it independently inspects the final “ at ” tail,
rather than requiring a preceding “ to ” clause; ensure forms like “set the
thermostat at 68 at 9pm” are recognized before parse_temperature_target actuates
immediately. Add regression coverage for both thermostat and brightness
value-separator forms, preserving existing “to … at …” behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f9ca3902-74ba-4195-9e78-9da9a048f3b7

📥 Commits

Reviewing files that changed from the base of the PR and between 84b15ec and 6fafa49.

📒 Files selected for processing (1)
  • crates/genie-core/src/tools/quick.rs

Spoken amounts like "one hundred and five" contain " and "; abstaining
on that token broke quick_spoken_setpoint_test. Keep when/unless/if/except/
only/everything without the coordinating "and" guard.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug] quick-router: "set the thermostat to 68 at 9pm" actuates now — only relative delays are guarded, not absolute schedules or conditions

2 participants