uttrflow / uttrflow/uttrflow-swift

A suggestion hidden for lack of caret space still reports isShowing and keeps idle polling active

Open
#812 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Swift
Stars
4
Forks
17
Avg merge
3h 32m
Merged PRs (30d)
277

Description

## Problem

On main `5c310667cd35c44abd8bbd26c19b0905471287b4`, `SuggestionPanelController.isShowing` tests whether the requested suggestion is non-silent, even when rendering deliberately hides its native window. The coordinator uses that flag to keep its one-second polling timer running after the activity window expires.

This happens when an otherwise valid caret is exactly at the known field right edge: there is no room for a ghost, `SuggestionGeometry.anchor` returns nil, and `render()` orders the panel out. The request remains `.certain(...)`, so `isShowing` remains true.

## Evidence

- [SuggestionPanelController.swift](https://github.com/uttrflow/uttrflow-swift/blob/5c310667cd35c44abd8bbd26c19b0905471287b4/Sources/Uttrflow/Suggestion/SuggestionPanelController.swift#L86-L87): visibility is inferred only from the request. `render()` and `resize()` can order the window out when placement fails without changing that request.
- [SuggestionTicking.swift](https://github.com/uttrflow/uttrflow-swift/blob/5c310667cd35c44abd8bbd26c19b0905471287b4/Sources/Uttrflow/Suggestion/SuggestionTicking.swift#L26-L34): `isShowing` bypasses the elapsed activity-window check.
- [SuggestionCoordinator.swift](https://github.com/uttrflow/uttrflow-swift/blob/5c310667cd35c44abd8bbd26c19b0905471287b4/Sources/Uttrflow/Suggestion/SuggestionCoordinator.swift#L245-L252): passes the panel flag to the ticking rule; admitted ticks call `wake(.tick)`, whose turn reads the focused field.

A macOS test using the unmodified production controller, SwiftUI view, geometry, and ticking rule:

1. Obtain a real screen visible frame and construct a valid caret inside it.
2. Set the field rectangle to end exactly at the caret x coordinate, with width 100 points.
3. Show `.certain("meeting")` using `.inlineGhost` placement.
4. Read `panel.window.isVisible` and `panel.isShowing`.
5. Record an activity in `SuggestionTicking`, then call `tick` with a timestamp one hour later and the panel flag.

Observed:

```text
windowVisible=false isShowing=true
tickAfterOneHour=true
```

Both expected-false assertions fail. A control with sufficient space shows the panel and reports true, then reports false after `hide()`. All 23 existing suggestion surface, log, ticking-policy and pressure-policy tests passed in the isolated harness.

The hour is a supplied test timestamp, not a wall-clock energy experiment. This verifies native visibility and the production timer decision; it does not measure CPU use or run a full external-app Accessibility session.

## Impact

With a retained suggestion that cannot be placed, the idle timer is admitted even though there is no visible surface to follow. Its coordinator can continue unnecessary focused-field reads while the user is idle. Priority P2.

## Acceptance criteria

- Make the visibility signal consumed by ticking reflect whether rendering actually shows a surface, including placement failure and hidden presentation paths.
- Preserve requested content as needed for legitimate later redraws, without treating a hidden request as visible.
- Cover a caret at the field right edge, a visible suggestion, explicit hide, and a later valid placement.
- Verify that polling stops after the activity window when placement leaves nothing visible and restarts on the next activity.

## Related work

This is a specific remaining visibility-state defect after closed #374 introduced activity-bounded polling. That original unconditional-timer behavior is no longer the implementation. #548 concerns bounding long ghosts; this issue concerns the idle timer after the current geometry correctly refuses to draw one.

Contributor guide

Open the contributing guide

Research direction

Start with Sources/Uttrflow/Suggestion/SuggestionPanelController.swift, SuggestionTicking.swift, and SuggestionCoordinator.swift, then run the existing suggestion surface and ticking-policy tests. Reproduce the caret-at-field-right-edge case from the issue and add coverage for visible, hidden, explicit-hide, and later-valid-placement states. Done means native visibility and polling agree, including after the activity window expires.

Written by the indexing model from the issue text.

Assessment

Tech stack
macos, swift
Domain
desktop, performance
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.