# Opus Review

**Model:** claude-opus-4
**Generated:** 2026-03-05T15:30:00Z

---

## Review of Sprint 5c Implementation Plan: Editor Screenshot + Camera Control

### 1. Async Dispatch is Under-specified (Section 4 — Critical)

The plan calls `_handle_editor_screenshot` "the FIRST async handler in the server dispatch." The current `_dispatch()` function calls handlers synchronously via `match`. Adding an `await` inside `_dispatch()` has significant implications:

- If `_dispatch()` itself is not async, calling `await _handle_editor_screenshot(...)` will not work
- If you make `_dispatch()` async, ALL callers must await it — but `_process()` cannot be async
- The practical pattern: call the handler (not await it) from dispatch — it runs as a standalone coroutine that internally awaits frame signals before sending response via `send_response()`

**This is the single biggest risk in the plan.** If implemented naively, it will either fail to compile or block the editor's `_process` loop.

### 2. Camera Restore Race Condition (Section 4)

Between the two `frame_post_draw` awaits and the restore, the user could interact with the viewport. The restore would clobber the user's new camera position.

### 3. Missing `look_at` Guard (Section 4, Step 4)

`Camera3D.look_at()` crashes if target == camera position. Add a guard.

### 4. `readOnlyHint` Annotation Wrong for `godotiq_camera` (Section 3)

`look_at` modifies camera, `focus_node` modifies selection. Should be `readOnlyHint=False`.

### 5. Missing Python-side Validation (Sections 1, 2)

`camera_position=[1, 2]` would be forwarded to Godot and fail there. Validate array length on Python side.

### 6. `focus_node` Clears User Selection Silently (Section 5)

Clearing editor selection is a destructive side effect not mentioned in tool description.

### 7. Missing `viewport` Value Validation (Section 1)

Invalid viewport values like `"foo"` should be rejected early.

### 8. Prompt Category Mismatch (Section 6)

`godotiq_screenshot` currently under "PLAY & DEBUG" but editor mode works without game.

### Summary

| Priority | Issue |
|----------|-------|
| **Critical** | Async dispatch pattern — call handler without await |
| **High** | look_at crash guard (position == target) |
| **High** | readOnlyHint=False for camera |
| **Medium** | Python-side array validation |
| **Medium** | focus_node selection warning |
| **Low** | Prompt category for dual-mode screenshot |
