Skip to content

refactor(macos): dedupe the cancellable fail-soft pattern in present/_present_status - #378

Merged
dhruvbatra merged 1 commit into
mainfrom
claude/cool-brahmagupta-gbhq14
Sep 4, 2026
Merged

refactor(macos): dedupe the cancellable fail-soft pattern in present/_present_status#378
dhruvbatra merged 1 commit into
mainfrom
claude/cool-brahmagupta-gbhq14

Conversation

@dhruvbatra

@dhruvbatra dhruvbatra commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Issue

MacOSPresentationController.present and _present_status (yutori/navigator/macos/presentation.py) each wrapped their dispatch body in the identical

except asyncio.CancelledError:
    raise
except Exception as error:  # noqa: BLE001 - presentation is fail-soft
    await self._degrade(f"presentation_failed:{type(error).__name__}", error)

block. This is the same duplication class the _fail_soft decorator (#373) already consolidated for show_thumbnail/before_capture/after_capture/encode_observation — those four methods explicitly couldn't reuse _fail_soft because they need to reraise CancelledError before degrading, so the pattern was left duplicated in these two methods instead.

Improvement

Extracted a new _fail_soft_cancellable decorator — the cancellation-aware counterpart to _fail_soft — and applied it to both present and _present_status. Each method now keeps only its distinct dispatch body.

Why it's safe

  • No behavior change. The removed try previously wrapped only the code below each method's early-return guards (e.g. if not self._status.available or self._stopping: return); those guards are simple attribute checks that cannot raise, so moving them inside the decorated body is equivalent. The exception handling order (reraise CancelledError, else degrade with the same f"presentation_failed:{type(error).__name__}" reason) is byte-for-byte preserved.
  • Verified: full suite passes unmodified — 914 passed, 3 skipped, 1 deselected (same as baseline). ruff check and ruff format --check both clean on the touched file.
  • Scope: 1 file changed, mechanical extraction only, no public API change (both are internal controller methods).

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com

🤖 Generated with Claude Code

https://claude.ai/code/session_01NoGweAuMDdcoLXYHWgfY3j


Generated by Claude Code


Note

Low Risk
Mechanical refactor in internal macOS presentation error handling with preserved cancellation and degrade semantics; no API or logic changes described.

Overview
Introduces _fail_soft_cancellable, a decorator that re-raises asyncio.CancelledError and otherwise degrades with the same presentation_failed:{exception} reason used before, matching the cancellation-aware branch that was duplicated on present and _present_status.

Both methods drop their inline try/except blocks and are annotated with the new decorator so only event-dispatch logic remains. The _fail_soft docstring now points readers at _fail_soft_cancellable for methods that must not treat cancellation as a presentation failure.

No intended behavior change—exception order and degrade messaging are preserved; early-return guards now run inside the decorated wrapper (still safe for the existing guard checks).

Reviewed by Cursor Bugbot for commit 86b132d. Bugbot is set up for automated code reviews on this repo. Configure here.

…_present_status

present and _present_status each wrapped their body in the identical
except asyncio.CancelledError: raise / except Exception as error: await
self._degrade(f"presentation_failed:{type(error).__name__}", error) shape.
Extract a shared _fail_soft_cancellable decorator (the cancellation-aware
counterpart to the existing _fail_soft decorator from #373) so both methods
keep only their distinct dispatch bodies.

No behavior change: the try/except previously wrapped the code below the
early-return guards in present, and those guards cannot raise, so moving
them inside the decorated body is equivalent. Full suite (914 passed / 3
skipped / 1 deselected) and ruff check/format pass unmodified.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NoGweAuMDdcoLXYHWgfY3j
@dhruvbatra
dhruvbatra merged commit d19d40e into main Sep 4, 2026
16 checks passed
@dhruvbatra
dhruvbatra deleted the claude/cool-brahmagupta-gbhq14 branch September 4, 2026 11:05
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