# Next Session: Resume Sunday Demo Fix — Phase 2 + Phase 3

> **Supersedes** `docs/NEXT-SESSION-SUNDAY-DEMO-FIX-V3-RESUME.md` for the Phase 2+ resumption.
> V3 is still accurate for everything through Phase 1.
> **Read this first, then open `~/.claude/plans/polymorphic-riding-turtle.md` for plan details.**

## TL;DR

Session 53 (2026-04-11) **completed and committed all of Phase 1** — red, blue, and green LAB calibration locked in, turbopi-server restarted and healthy, sweep fix from session 52 committed, saturation patch committed, deploy infrastructure committed. All work pushed to `origin/main` at commit `9f26e9e`.

This next session picks up at Phase 2 (no-motor passthroughs, ~15 min) and Phase 3 (motor demos, ~2 h). Phase 4 (Sunday-morning smoke test) should run Sunday morning (2026-04-12) shortly before guests arrive.

## State at handoff (end of session 53)

### Git state
- Branch: `main` at commit `9f26e9e` ("fix: Sunday demo — LAB calibration, look_around sweep, camera saturation, TurboPi deploy")
- Pushed to `origin/main` on `https://github.com/myidentity/her-os.git`
- Working tree: only `docs/PROJECT.md` (M — session 48 ROS2 notes, unrelated) + large pile of pre-existing untracked docs and prototypes
- **Nothing else outstanding. Phase 1 is fully durable in two places (laptop + GitHub).**

### Pi state
- `turbopi-server`: **active** (verified at end of session 53 via `systemctl is-active turbopi-server` and `/health` check)
- `/home/pi/TurboPi/lab_config.yaml`: deployed with session-53 calibration (matches repo `services/turbopi-server/lab_config.yaml`)
- `/home/pi/bin/lab_calibrate_pi.py`: installed via `scripts/deploy-turbopi.sh`. This is a DURABLE path (survives reboot), unlike the old `/tmp/` path.
- Power: `throttled=0x0`, `EXT5V=5.06–5.08 V`, jumper-cap rewire from session 52 still holding. **Do not touch power setup.**

### Laptop state
- `scripts/lab_calibrate_webui.py` is running in the background at `127.0.0.1:8089` (pid `2225322` from session 53). **Kill it with `kill 2225322` before starting the next session** — it holds the port and you don't need it for Phase 2/3.
- `/tmp/lab_calibrate_frame.jpg`, `/tmp/lab_calibrate_bbox.json`, `/tmp/pi_lab_config.yaml` — leftover files from Phase 1, safe to `rm` if you want a clean `/tmp`.

### Calibration values now in production (reference)

| Color | L min | a min | b min | L max | a max | b max |
|---|---|---|---|---|---|---|
| red | 102 | 182 | 137 | 153 | 226 | 190 |
| blue | 55 | 175 | 13 | 108 | 224 | 64 |
| green | 67 | 64 | 109 | 148 | 128 | 184 |

These are the values the robot will use at runtime for Chase Ball / Color Spotter / QR Navigator. **Functional separation between colors is strong**: red/blue overlap on `a` but not on `b`; green is far below both on `a` (54+ unit gap). If Chase Ball misbehaves during Phase 3, the first debugging step is to compare live camera LAB stats against these ranges — not to re-calibrate from scratch.

## Pre-flight for Phase 2 (2 min)

```bash
# Is the Pi reachable?
ssh pi hostname && ssh pi "systemctl is-active turbopi-server"

# /health sanity
curl -s http://192.168.68.61:8080/health | jq '{status, demo_mode, demo_phase, safety_daemon_healthy, throttled}'
# Expect: ok, false, "idle", true, 0

# Is session 53's webui still hanging around on the laptop?
ss -tlnp 2>/dev/null | grep :8089 && echo "webui still running, kill it: kill \$(lsof -t -i:8089)"

# Remind yourself of the current state on the Pi
ssh pi "cat /home/pi/TurboPi/lab_config.yaml"
# Should match the table above.
```

## Phase 2 — no-motor passthroughs (~15 min, NO crouching needed)

Plan file: `~/.claude/plans/polymorphic-riding-turtle.md` §Phase 2.

Two demos to validate; both tested by tapping buttons in the Telegram car-demo keyboard.

| # | Demo | Trigger | Pass criterion | Risk level |
|---|---|---|---|---|
| 2.1 | 🎯 Look Around | Tap "Look Around" in Telegram | Pan/tilt servo visibly sweeps L→R→C over ~4 s; Telegram returns confirmation | **LOW — already live-verified at ~08:15 IST session 52, just re-confirm** |
| 2.2 | 📸 What Do I See? | Tap "What Do I See?" | Telegram returns a text description mentioning specific visible objects within ~5 s (not a generic "I see a room") | **MEDIUM — UNTESTED, first real exercise of Pi → Titan → Gemma 4 vision pipeline** |

**If 2.1 fails:** check `/health` for servo state, check `/var/log/turbopi-server.log` on the Pi, check annie-voice logs on Titan. The sweep fix is committed as of 9f26e9e, so if this fails it's a NEW bug, not the one we already fixed.

**If 2.2 fails:** likely culprits are `/photo/describe` endpoint on the Pi OR Gemma 4 vision on Titan. Check Titan vLLM logs. Failure modes:
- "I see a room" generic → vLLM isn't actually receiving the image
- Nothing returned → request timing out or photo endpoint broken
- Hallucinated objects → Gemma 4 is receiving an image but misreading it

**To re-spawn the menu if the keyboard is gone:**
```bash
ssh titan 'UUID=$(python3 -c "import uuid; print(uuid.uuid4().hex[:8])"); echo "{\"car_demo_menu\": true}" > ~/.her-os/annie/task_results/car-demo-menu-$UUID.json'
```

**Exit criterion:** both pass, OR both documented as failing (and flagged for drop from the Sunday menu).

## Phase 3 — motor demos (~2 h, HIGH supervision required)

Plan file: `~/.claude/plans/polymorphic-riding-turtle.md` §Phase 3.

**Safety reminder before you start (§10):** the Hailo safety daemon is DELIBERATELY DISABLED during demo subprocesses. There is NO automatic hand protection during Chase Ball / Obstacle Dodge / Traffic Cop. **Rajesh must sit next to the phone with finger on 🛑 Stop Demo throughout Phase 3.** Verbal briefing script for Sunday guests is in §10 — read it aloud before letting anyone else tap buttons.

Five motor demos to verify, ordered by safety:

1. **Chase Ball** — the new calibration values make this the canonical test. If the robot detects and follows a red ball during Chase Ball, green and blue will likely work too (they use the same detection pipeline, different LAB ranges).
2. **Obstacle Dodge**
3. **Traffic Cop**
4. **QR Navigator**
5. **Color Spotter**

**PID sign inversion procedure** (only if §3a detects a ball but the car drives the WRONG direction): see `~/.claude/plans/polymorphic-riding-turtle.md` §3c.

**Known plan bug to fix in-session (carry-over from session 52):** §5 state-machine guard loop `jq -e` predicate uses `.phase==idle` and `.frame_grabber_healthy==true` — neither is a real field in the `/health` contract. **Correct predicate:**
```bash
.demo_mode==false and .demo_phase=="idle" and .safety_daemon_healthy==true
```
Fix this before running the guard loop or it will spuriously trigger `systemctl restart turbopi-server` between every Phase 3 demo.

## Phase 4 — Sunday-morning smoke test (~15 min, runs Sunday 2026-04-12)

This is a separate session, scheduled for Sunday morning shortly before the demo. It re-runs Phase 2 + a truncated Phase 3 to catch overnight regressions. Plan file §Phase 4.

## Hardware gotchas (reference only — don't re-discover)

Saved in memory at `~/.claude/projects/-home-rajesh-workplace-her-her-os/memory/project_turbopi_camera_gotchas.md`. Summary:

1. **OpenCV `CAP_PROP_SATURATION` clamps to max on uvcvideo.** It's normalized [0,1]; passing 40 writes v4l2 saturation=128 (neon-red cast). Fix is committed in `scripts/lab_calibrate_pi.py::_set_saturation_via_v4l2`. Never use OpenCV to set v4l2 UVC controls.
2. **TurboPi ultrasonic sensor has a hardwired blue power LED** that biases auto-WB to globally boost red (pink floor cast). LED is ON during runtime so calibration matches. **Post-Sunday candidate: black electrical tape over the LED** — 30-second physical fix, eliminates the pink cast entirely.
3. **Pi `/tmp` wipes on reboot** — moot now that `deploy-turbopi.sh` installs `lab_calibrate_pi.py` to `/home/pi/bin/`.

## Post-Sunday candidates (NOT for this session)

- Black electrical tape over the TurboPi ultrasonic sensor's blue power LED (see hardware gotchas #2)
- Systemd drop-in on Pi that runs `v4l2-ctl --set-ctrl=saturation=40` at boot (so even if the saturation state drifts across reboots, we get back to the canonical value)
- Revisit `docs/ARCHITECTURE-TURBOPI.md` — add a section on how turbopi-server itself gets deployed (not just lab_config.yaml + lab_calibrate_pi.py). Currently vague.
- Decide whether `docs/PROJECT.md` session 48 ROS2 notes deserve their own commit or can be rolled into a later unrelated commit.

## Commit list for resume session

If Phase 2 and/or Phase 3 produces code changes, bundle them as a single follow-up commit. Expected files:
```
(Phase 2 usually requires no code changes — it's mostly tapping buttons + observing.)
(Phase 3 may require PID sign flips in services/turbopi-server/demo_runner.py or Hiwonder
 vendor files, and the §5 guard-loop jq predicate fix if we're running the guard loop.)
services/turbopi-server/demo_runner.py    # if PID inversion needed
services/turbopi-server/lab_config.yaml   # ONLY if re-calibration needed
```

Do NOT bundle the session-48 PROJECT.md changes into this commit; they're unrelated.

## Prompt for the next session (copy-paste)

```
Resume Sunday demo fix at Phase 2. Read
docs/NEXT-SESSION-SUNDAY-DEMO-FIX-V4.md first — it has the full state
at end of session 53, calibration values, Phase 2/3/4 procedures, and
the known plan bug carried from session 52. Phase 1 is DONE and pushed
as commit 9f26e9e. lab_config.yaml is live on the Pi. turbopi-server
is healthy. First action: kill the lingering webui server on the
laptop (pid 2225322 or `kill $(lsof -t -i:8089)`), then run the 2-min
Phase 2 pre-flight from the doc, then Phase 2 (15 min, no crouching),
then decide whether to tackle Phase 3 today or push it to tomorrow
morning. Sunday is 2026-04-12.

Plan file: ~/.claude/plans/polymorphic-riding-turtle.md
Hardware gotchas (memory): project_turbopi_camera_gotchas.md
```
