# Next Session: WhatsApp Agent — Phase 5 Live Verification + Observability Wiring

**Date:** 2026-04-07
**Status:** DEPLOYED but not yet E2E verified (2 blockers: Tasker, Titan)

## What

Phase 5 hardening code is deployed on Panda (commit 426a06c). Manual curl test confirmed trigger regex matches "Annie, what time is it?" correctly. Two blockers prevented live E2E verification: (1) Tasker on Pixel isn't posting to Panda, (2) Titan LLM was down so classify/respond failed. This session: fix both blockers, complete live E2E, then wire wa_observability emit calls so jackal events flow to the dashboard.

## Blockers to Resolve

### 1. Tasker Not Posting (HIGH)

Tasker on Pixel didn't fire when a WhatsApp message was received. Pixel is reachable from Panda (ping 199ms). Possible causes:

- Tasker profile disabled (check for green checkmark)
- Tasker battery-optimized/killed by Android (check notification icon present)
- Task URL wrong (must be `http://192.168.68.57:8780/v1/message`)
- Body template still has hardcoded sender (change to `{"group":"%antitle","sender":"%antitle","text":"%antext"}`)

**Debug steps:**
```bash
# 1. Check if Tasker is running on Pixel
ssh panda "adb -s 192.168.68.60:5555 shell dumpsys package net.dinglisch.android.taskerm | grep -i 'last'"

# 2. Check Tasker's notification listener
ssh panda "adb -s 192.168.68.60:5555 shell settings get secure enabled_notification_listeners"

# 3. Send a test WhatsApp message and watch for Tasker HTTP in real-time
ssh panda "tail -f /tmp/whatsapp-agent.log"
# (then send a WhatsApp message to Annie's Pixel from your phone)

# 4. If Tasker is dead, force-start it
ssh panda "adb -s 192.168.68.60:5555 shell am start -n net.dinglisch.android.taskerm/.Tasker"
```

### 2. Titan LLM Down (HIGH)

Startup log: `LLM unreachable at http://192.168.68.55:8003/v1`. Compaction, trigger classify, and response generation all require Titan.

```bash
# Check if vLLM is running on Titan
ssh titan "ps aux | grep vllm | grep -v grep"

# If not, start it (or use start.sh)
./start.sh llm

# Verify from Panda
ssh panda "curl -s http://192.168.68.55:8003/v1/models | head -5"
```

## Live E2E Test Plan (after blockers resolved)

```bash
# 1. Verify health — should show llm_circuit_breaker: closed
ssh panda "curl -s http://localhost:8780/v1/health | python3 -m json.tool"

# 2. Send a DM from your phone → check sender extraction
# Expected: sender = "Rajesh", text = full message
ssh panda "tail -f /tmp/whatsapp-agent.log"

# 3. Send a group message → check sender extraction from "Name: text" format
# Expected: sender extracted from text prefix, text = remainder

# 4. Send "Annie, what time is it?" from your phone
# Expected: trigger regex → LLM classify → direct_request → generate → u2 send
# Check cadence: daily_count should increment

# 5. Verify circuit breaker (optional):
# Stop Titan LLM, send 3 trigger messages, check health → breaker should be "open"
# Restart Titan, wait 300s, send another → breaker should auto-reset to "half_open" then "closed"

# 6. Check compaction (wait until X:05):
# Expected: hourly compaction runs, mark-and-sweep clears only snapshot count
```

## Wire wa_observability Emit Calls

After E2E is verified, wire the emit functions in `agent.py`. The functions are defined in `wa_observability.py` but not yet called.

### Files to Modify

1. **`services/whatsapp-agent/agent.py`** — add emit calls at 4 points:

```python
# At top: import
from wa_observability import (
    emit_message_received,
    emit_compaction,
    emit_trigger,
    emit_response,
    emit_circuit_breaker,
)

# In _drain_buffer_loop, after buffering each message:
emit_message_received(msg["sender"], len(msg["text"]))

# In _check_trigger, after classification:
emit_trigger(sender, classification)

# In _check_trigger, after send_response:
emit_response(sender, len(response), sent)

# In _hourly_compaction_loop, after successful compaction:
emit_compaction(hour_label, len(messages), len(digest))
```

2. **Tests** — verify emit calls don't break (mock wa_observability or let them fail silently since _obs_emit swallows exceptions)

### Dashboard Verification

After wiring emit calls:
```bash
# Check jackal events appear on dashboard
# Open dashboard → look for sandy tan "Jackal" creature in thinking zone
# Events should flow: wa_message_received on each buffered message
```

## Pre-existing Issue: Phoenix Mismatch

`annie-voice/observability.py` has phoenix as `acting/indicf5-tts` but `chronicler.py` has it as `thinking/daily-reflection` (context-engine). This causes 3 TS + 2 Python test failures in cross-service sync tests. **Not blocking** — separate cleanup task.

Options:
- Rename the IndicF5 phoenix to a different creature name (e.g., "firebird")
- Update chronicler.py to match the annie-voice entry (if phoenix is now primarily TTS)
- Keep both — split phoenix into phoenix (daily-reflection) and phoenix-tts (indicf5)

## Environment

- **Panda** (192.168.68.57): WhatsApp agent on port 8780, phone services
- **Titan** (192.168.68.55): Gemma 4 on port 8003, Context Engine on port 8100
- **Pixel** (192.168.68.60): WhatsApp + Tasker, ADB-connected to Panda

## Key Files

| File | What |
|------|------|
| `services/whatsapp-agent/agent.py` | Main daemon — wire emit calls here |
| `services/whatsapp-agent/wa_observability.py` | Standalone emitter (emit functions defined) |
| `services/whatsapp-agent/receiver.py` | Sender extraction (`_extract_sender`) |
| `services/whatsapp-agent/config.py` | `LLMCircuitBreaker` singleton, `sanitize_sender()` |
| `/tmp/whatsapp-agent.log` | Agent log on Panda |
