# Next Session: Nav Self-Rescue + Bug Fixes

## What
Fix 2 bugs and add 3 features to Annie's robot navigation, making her smarter at approaching objects and escaping tight spaces. The Pi rate limiter is removed (Annie controls pacing), the IMU 360° wrap-around bug is fixed, the camera tilts down during close approach so ground objects stay in frame, and Annie backs up when boxed in against walls.

**Architecture principle:** Pi = dumb executor + safety guard. Annie = all intelligence.

## Plan
`~/.claude/plans/transient-waddling-boot.md`

Read the plan first — it has the full implementation with all 15 adversarial review findings addressed. Two parallel tracks (A: Pi, B: Annie) can run as independent agents.

## Key Design Decisions (from adversarial review — DO NOT revert these)

1. **B3 stuck condition requires `reason=="searching"`** — NOT `safe_fwd=False + any turn`. The original plan triggered spurious backups during legitimate centering turns in tight corridors.
2. **Added `"backward"` to Pi's `_CLEARANCE_SECTORS`** — rear lidar sectors (5,6,7). Without this, backup has ZERO rear collision protection. Pi returns 422 if rear is blocked.
3. **A2 captures `final_heading` inside motor lock** — prevents race condition where a concurrent drive command changes IMU heading between motor stop and post-coast read.
4. **B2 caches camera direction in `cam_dir` local** — only calls `/look` when direction actually changes. Prevents UART servo thrash (0.3s settle per write).
5. **B1 try/finally wraps ENTIRE function** including return-to-start leg, NOT just the for loop. Camera reset to center guaranteed on all exit paths.
6. **B3 resets BOTH `stuck_cycles` AND `search_rotations` before backup** — prevents infinite backup retry on 409 AND premature give_up after clearing space.
7. **B3 waypoint `action_taken` update moved to AFTER ACT phase** — backup `continue` skips ACT, so waypoint must not record the un-executed turn.
8. **B4 adds 100ms floor between nav cycles** — with rate limiter removed, this prevents runaway loops if VLM latency drops to near-zero.

## Files to Modify

**Track A (Pi — can be a worktree agent):**
1. `services/turbopi-server/main.py` — Remove rate limiter (A1: delete constants, global, function, calls, appends, deque import). Add `"backward"` to `_CLEARANCE_SECTORS` (A1b). Fix achieved_deg post-coast (A2: replace lines 971-981 with accumulated_deg coast extension, capture heading inside lock). Update docstring.
2. `services/turbopi-server/tests/test_drive_turn.py` — Delete `TestDriveTurnRateLimited` class + `_command_timestamps.clear()` from fixture. Add `TestDriveTurnWrapAround` (2 tests) + `TestRateLimitRemoved` (1 test).

**Track B (Annie — can be a worktree agent):**
3. `services/annie-voice/robot_tools.py` — Camera reset with try/finally wrapping entire function (B1). Tilt-down with `cam_dir` cache (B2). Backup with correct stuck condition + both counter resets + waypoint fix (B3). Rate floor (B4).
4. `services/annie-voice/tests/test_robot_tools.py` — Add `TestNavCameraTilt`, `TestNavBackupWhenBoxed`, `TestNavRateFloor`.

## Start Command
```
cat ~/.claude/plans/transient-waddling-boot.md
```
Then implement the plan using parallel agents for Track A and Track B. All adversarial findings are already addressed in it.

## Verification
1. `python3 -m pytest services/turbopi-server/tests/ -v` — all pass (rate limit tests deleted, wrap-around green)
2. `python3 -m pytest services/annie-voice/tests/test_robot_tools.py -v` — all pass (new tilt/backup tests)
3. `python3 -m pytest services/panda_nav/tests/ -v` — unchanged, 22 green
4. Commit + push + deploy:
   - `ssh pi "cd ~/workplace/her/her-os && git pull" && ssh pi "sudo systemctl restart turbopi-server"`
   - `ssh titan "cd ~/workplace/her/her-os && git pull"` then `./stop.sh annie && ./start.sh annie`
5. E2E hardware tests:
   - "go to the red ball" (ball on floor 2m away) → camera tilts down, approaches closer than 100cm
   - "find the blue cup" (nonexistent) → searches, no 429, gives up after 12 rotations
   - Robot 28cm from wall, "find the red ball" → backs up after 3 stuck search cycles
   - Backup near rear wall → Pi returns 422, robot doesn't reverse into wall
