fix: make /api/settings/status fast and truthful - #21
Open
luca-71 wants to merge 2 commits into
Open
Conversation
The endpoint hung long enough to look broken. Each osascript call was
already bounded, but the endpoint's total was not: probing Calendar went
through get_todays_events(), which on a cold cache fans out over every
calendar in batches of two at 15s apiece. On a 10-calendar account that
alone runs to 75s, before Mail (20s) and Notes (15s) are even reached.
Prior to the user granting TCC permission, these block on a system
dialog instead.
Add _probe_integration(), which caps each probe at 8s and reports a slow
integration the same as a broken one, and run the three concurrently --
they touch independent apps, so the endpoint now costs one budget rather
than three.
Probe Calendar with get_calendar_names() instead: a single already
bounded osascript that answers the question a status endpoint actually
asks ("is Calendar reachable?"). Capping the wait alone would have left
the endpoint honest about its deadline but wrong about the result --
returning calendar_accessible: false for a Calendar that works fine.
Measured: response drops from hanging (>60s) to 0.28s warm / 2.3s cold,
and calendar_accessible now reports true.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
get_recent_notes() read note properties unguarded, so a single note that Notes.app refuses to describe aborted the whole AppleScript and the function returned []. On this library, note p627 did exactly that. Guard each note individually and keep scanning until `count` readable notes are collected, bounded so a run of bad notes can't walk an entire library. The folder lookup gets its own guard. `name of container of note` turns out to fail with -1728 for every note on recent macOS -- the container resolves, but as a bare `item` whose name is not exposed -- so "folder" is empty in practice. Real folder names are only reachable by walking `every note of folder`, which scans the whole library on every call; not worth it while no caller reads the field. Guarding rather than dropping the lookup keeps it self-healing if Apple restores the property. Also probe Notes with get_note_folders() in /api/settings/status, and treat an empty result as a failure. Both notes_access and calendar_access answer an unreachable app with the same empty value they use for "nothing found", so a probe that only caught raised exceptions reported Notes as accessible while its script was failing on every call. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Aug 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The endpoint hung long enough to look broken, leaving the settings panel unable to load — and once it did answer, one of its three answers was wrong.
1. No overall time budget
Each individual
osascriptcall was already bounded, but the endpoint total was not. Probing Calendar went throughget_todays_events(), which on a cold cache fans out over every calendar in batches of two at 15s apiece. On a 10-calendar account that alone runs to 75s, before Mail (20s) and Notes (15s) are even reached. Prior to the user granting TCC permission, these block on a system dialog instead.Added
_probe_integration(), capping each probe at 8s and reporting a slow integration the same as a broken one, and run the three concurrently viaasyncio.gather— they touch independent apps, so the endpoint now costs one budget rather than three.2. The probes could not see failure
calendar_accessandnotes_accessboth answer an unreachable app with the same empty value they use for "nothing found". A probe that only caught raised exceptions therefore reported an app as healthy while its script was failing on every single call — which is exactly what was happening to Notes.Calendar and Notes are now probed by listing containers (
get_calendar_names()/get_note_folders()), with an empty result read as failure. Listing also sidesteps the expensive paths entirely.This part matters on its own: capping the wait alone would have left the endpoint honest about its deadline but wrong about its result.
3. One unreadable note emptied the whole listing
get_recent_notes()read note properties unguarded, so a single note that Notes.app refuses to describe aborted the entire AppleScript and the function returned[].Each note is now guarded individually, and the scan continues until
countreadable notes are collected — bounded, so a run of bad notes cannot walk an entire library.The folder lookup gets its own guard.
name of container of noteturns out to fail with -1728 for every note on recent macOS: the container resolves, but as a bareitemwhose name is not exposed. Sofolderis empty in practice. Real folder names are only reachable by walkingevery note of folder, which scans the whole library on every call — not worth it while no caller reads the field. Guarding rather than dropping the lookup keeps it self-healing if Apple restores the property.Measured
calendar_accessibletruenotes_accessibletrue(while failing on every call)true(and actually working)get_recent_notes(10)[]Verified against a 10-calendar, 140-note account. The recurring
Notes script failed: ... (-1728)warnings are gone from the server log.Tests
pytest tests/gives 35 passed, 8 failed — identical before and after these changes, so no regressions. The 8 pre-existing failures are unrelated: 7 needplaywright install, andtest_browse_action_keywordsimportsACTION_KEYWORDS, a symbol that no longer exists inserver.py.🤖 Generated with Claude Code