Skip to content

Fix disabled rules, window geometry validation, and privacy logging#5

Merged
frankieg33 merged 3 commits into
mainfrom
claude/fix-window-geometry-validation-nmmQ9
May 13, 2026
Merged

Fix disabled rules, window geometry validation, and privacy logging#5
frankieg33 merged 3 commits into
mainfrom
claude/fix-window-geometry-validation-nmmQ9

Conversation

@frankieg33

Copy link
Copy Markdown
Owner

Summary

This PR hardens configuration validation, fixes rule resolution semantics, and improves privacy in logging. It addresses three distinct issues:

  1. Disabled app rules now act as explicit exclusions — A disabled AppRule for a process prevents fallback to bucket inheritance, fixing a bug where unchecking an app inside a bucket silently did nothing.

  2. Window geometry and UI state are now validated on load — Absurd persisted values (e.g., from a tampered config) that could make the settings window unusable or crash the renderer are dropped, falling back to defaults.

  3. Activity logging no longer leaks window titles — Window titles (which may contain sensitive data like document names or URLs) are now logged only at debug level; info-level logs omit them.

Key Changes

  • config.rs

    • resolve_process() now checks if a matching AppRule exists (enabled or disabled) before considering bucket inheritance. A disabled rule returns None, preventing the process from falling through to a bucket.
    • clamp_ranges() validates window geometry (window_width, window_height, window_x, window_y) and activity splitter height (activity_current_height), dropping out-of-range values to prevent UI breakage.
    • Added tests: test_disabled_rule_suppresses_bucket_inheritance(), test_clamp_drops_absurd_geometry(), test_clamp_preserves_sane_geometry().
  • ui/main.slint

    • Added orig-app-index and orig-index fields to GroupAppModel, GroupModel, and UnassignedRuleModel to preserve original indices across search filtering.
    • Replaced loop variable indices (g-idx, a-idx) with struct fields (group.orig-index, app.orig-app-index) so callbacks dispatch the correct unfiltered indices, making search-stable filtering work correctly.
  • src/main.rs

    • build_groups() now tracks original bucket indices and app indices via .enumerate() before filtering, storing them in the model.
    • build_unassigned_rules() pre-computes the unfiltered unassigned list, then filters and maps with enumerated indices to ensure orig_index matches what callbacks reconstruct.
    • on_set_activity_current_height() now clamps the value to 80.0..=800.0 and validates it is finite before persisting.
    • on_restore_defaults() now calls autostart::set_auto_start(false) to unregister the Windows startup entry when restoring defaults, preventing a mismatch between config and OS state.
    • Icon picker callback now inherits the bucket's enabled state when creating a new customized AppRule, preventing a disabled bucket from being silently promoted to managed.
  • src/monitor.rs

    • Action::Minimize and Action::Close logging now omit the window title from info-level logs (moved to debug level) to avoid leaking sensitive activity into the Windows release log. The full title is still recorded in the in-memory Activity log for the UI.

Implementation Details

  • The orig-index fields are populated during model construction and remain stable across search filtering, allowing the UI to dispatch callbacks with the correct unfiltered indices.
  • Geometry validation uses inclusive ranges (MIN_W..=MAX_W, etc.) and drops invalid values rather than clamping them, ensuring the window falls back to its preferred size/position.
  • The disabled rule check happens before bucket iteration, making it a hard exclusion rather than a soft override.

https://claude.ai/code/session_01UmuM86GuBpcCaPzAQDawXZ

- config: clamp persisted window geometry and Activity splitter height
  on load; drop absurd/non-finite values rather than passing them to
  Slint (avoids local DoS via tampered fade.toml).
- config: a disabled AppRule now suppresses bucket inheritance instead
  of falling through, so unchecking an app in an enabled bucket — or
  assigning a disabled Ungrouped rule into one — actually exempts it.
- main: search-filtered group/app/unassigned models now carry stable
  orig_index fields; Slint passes those to mutating callbacks so
  delete/move/toggle/icon/timeout edits target the visible row instead
  of the filtered display position.
- main: icon picker on an in-bucket app inherits bucket.enabled when
  creating its AppRule, instead of hard-coding enabled=true (which
  silently promoted apps inside disabled buckets to managed).
- main: Restore Defaults now also calls autostart::set_auto_start(false)
  so the OS startup entry is removed, matching the reset UI state.
- main: validate the Activity splitter height callback input (finite +
  clamped) before persisting.
- monitor: drop the window title from the info-level minimize/close
  log line — titles can leak document/URL/chat metadata to the
  on-disk Windows release log. Full title remains available at debug
  level and in the in-memory Activity log.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces several robustness and privacy improvements. Key changes include making disabled app rules authoritative exclusions in process resolution, adding range clamping for window geometry and UI state in the configuration, and ensuring UI callbacks remain stable during searches by tracking original indices. Additionally, window titles are moved to debug logs to prevent sensitive information leakage. Feedback was provided regarding a performance optimization in resolve_process to use eq_ignore_ascii_case for string comparisons, which avoids unnecessary allocations within the loop.

Comment thread src/config.rs
timeout_mins: rule.timeout_mins,
action: rule.action.clone(),
});
if rule.process.to_lowercase() == process_lower {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Using to_lowercase() inside a loop creates a new String allocation on every iteration. Since process_lower is already computed outside the loop, you can use eq_ignore_ascii_case to perform a more efficient comparison without extra allocations. While to_lowercase() is more robust for full Unicode, process names on Windows are typically ASCII-compatible, making eq_ignore_ascii_case a significant performance win in this polling path.

Suggested change
if rule.process.to_lowercase() == process_lower {
if rule.process.eq_ignore_ascii_case(process) {

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 921a6d8602

ℹ️ 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".

Comment thread src/config.rs
Comment on lines +162 to +163
} else {
return None;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Align managed-set tracking with disabled AppRule exclusions

Returning early with None for a disabled app rule changes the effective-rule semantics, but Monitor::poll_once still builds currently_managed by blindly unioning enabled buckets and enabled app rules (see src/monitor.rs step 0). In a bucket-enabled + app-disabled case, the process is now unmanaged by resolve_process yet still tracked as managed, so re-enabling that app later is not detected as “newly managed” and the idle grace-period reset is skipped; already-idle windows can be minimized/closed immediately after the user enables them. Please update managed-set construction to use the same resolution logic as resolve_process.

Useful? React with 👍 / 👎.

Addresses review feedback on PR #5:

- monitor: build currently_managed via Config::resolve_process so a
  disabled AppRule that excludes its process is reflected in the
  managed set too. Without this, a bucket-enabled + app-disabled
  process was still tracked as managed; re-enabling the AppRule later
  wasn't detected as "newly managed" and the idle grace period was
  skipped, so an already-idle window could be minimized/closed
  immediately on toggle.
- config: switch resolve_process comparisons to eq_ignore_ascii_case;
  process names are ASCII (.exe), and this drops a per-iteration
  String allocation on the hot polling path.

Copy link
Copy Markdown
Owner Author

Addressed both review comments in ca76437:

  • Codex P1: Monitor::poll_once now builds currently_managed via Config::resolve_process so a disabled AppRule that excludes its process is reflected in the managed set, preserving the "newly managed" grace-period behavior on re-enable.
  • Gemini medium: resolve_process now uses eq_ignore_ascii_case to avoid per-iteration String allocations on the polling path.

@codex review
/gemini review


Generated by Claude Code

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ca76437819

ℹ️ 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".

Comment thread src/config.rs Outdated
timeout_mins: rule.timeout_mins,
action: rule.action.clone(),
});
if rule.process.eq_ignore_ascii_case(process) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Restore Unicode case-insensitive process matching

resolve_process switched from Unicode-aware lowercasing to eq_ignore_ascii_case, which only folds ASCII characters. On Windows, executable names can contain non-ASCII letters, so rules like "Åpp.exe" vs "åpp.exe" no longer match and the process can be treated as unmanaged (or miss a disabled-rule exclusion) depending on casing. This is a functional regression for internationalized process names introduced by this change.

Useful? React with 👍 / 👎.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces several stability and privacy enhancements, including stable indexing for UI elements to maintain correct behavior during searches, and sanitization of window geometry and activity splitter height in the configuration. It also improves privacy by moving window titles from info-level to debug-level logs and ensures the Windows auto-start entry is properly unregistered when restoring defaults. Feedback indicates that replacing to_lowercase() with eq_ignore_ascii_case() for process name matching is a regression for Unicode-named processes in non-English locales.

Comment thread src/config.rs Outdated
timeout_mins: rule.timeout_mins,
action: rule.action.clone(),
});
if rule.process.eq_ignore_ascii_case(process) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

While eq_ignore_ascii_case is faster than to_lowercase(), it only handles ASCII characters. Process names on Windows can contain Unicode characters (e.g., "Música.exe"). Using eq_ignore_ascii_case will fail to match these correctly if the case differs on a non-ASCII character, whereas the previous implementation was Unicode-aware. This is a regression in correctness for non-English locales.

Comment thread src/config.rs Outdated
}
for proc in &bucket.processes {
if proc.to_lowercase() == process_lower {
if proc.eq_ignore_ascii_case(process) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Similar to the change in app_rule resolution, using eq_ignore_ascii_case here for bucket process matching is a regression for Unicode process names. It will fail to match non-ASCII characters correctly if their case differs between the configuration and the running process.

Reverts the eq_ignore_ascii_case optimization on review feedback from
both Codex (P2) and Gemini: Windows executable names can contain
non-ASCII letters (e.g. "Música.exe", "Åpp.exe"), and ASCII-only case
folding regressed matching for those processes. to_lowercase costs a
few extra allocations per poll but only runs O(rules) per cycle, which
is well below the polling-loop budget.

Copy link
Copy Markdown
Owner Author

Reverted the eq_ignore_ascii_case change in da841fb — both Codex and Gemini correctly flagged it as a Unicode regression for non-ASCII process names. Back to to_lowercase for Unicode-aware folding.

@codex review
/gemini review


Generated by Claude Code

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Can't wait for the next one!

ℹ️ 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".

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces several robustness and UI stability improvements. Key changes include refining the resolve_process logic to make disabled AppRules authoritative, adding input validation for window geometry and activity height, and updating UI models to track original indices for stable interaction during search and filtering. Additionally, the pull request enhances logging privacy by moving sensitive window titles to debug logs and fixes a bug where restore_defaults failed to disable Windows auto-start. I have no feedback to provide.

@frankieg33 frankieg33 merged commit c2ef067 into main May 13, 2026
1 check passed
@frankieg33 frankieg33 deleted the claude/fix-window-geometry-validation-nmmQ9 branch May 13, 2026 16:37
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.

2 participants