# S03: Transcript Folder Watcher — Auto-Ingest Service — UAT

**Milestone:** M007
**Written:** 2026-03-30T19:26:20.063Z

## UAT: Transcript Folder Watcher — Auto-Ingest Service

### Preconditions
- Chrysopedia stack running on ub01 (`docker ps --filter name=chrysopedia` shows all services healthy)
- Watch folder exists: `/vmPool/r/services/chrysopedia_watch/`
- Watcher container running: `docker ps --filter name=chrysopedia-watcher` shows healthy

---

### Test 1: Valid Transcript Auto-Ingest (Happy Path)

1. SSH to ub01
2. Create a valid transcript JSON file:
   ```bash
   cat > /vmPool/r/services/chrysopedia_watch/uat_valid.json << 'EOF'
   {
     "source_file": "uat_test_video.mp4",
     "creator_folder": "UAT Creator",
     "duration_seconds": 120.5,
     "segments": [{"start": 0.0, "end": 5.0, "text": "Hello world"}]
   }
   EOF
   ```
3. Wait 10 seconds for watcher to detect and process
4. **Expected:** `docker logs chrysopedia-watcher --tail 20` shows:
   - File pickup log line mentioning `uat_valid.json`
   - Stability check pass
   - POST to ingest API with HTTP 200
   - File moved to processed/
5. **Expected:** `ls /vmPool/r/services/chrysopedia_watch/processed/uat_valid.json` — file exists
6. **Expected:** `ls /vmPool/r/services/chrysopedia_watch/uat_valid.json` — file no longer in root

### Test 2: Invalid JSON File Handling

1. Create an invalid JSON file (missing required keys):
   ```bash
   echo '{"foo": "bar"}' > /vmPool/r/services/chrysopedia_watch/uat_invalid.json
   ```
2. Wait 10 seconds
3. **Expected:** `ls /vmPool/r/services/chrysopedia_watch/failed/uat_invalid.json` — file exists
4. **Expected:** `cat /vmPool/r/services/chrysopedia_watch/failed/uat_invalid.json.error` — contains validation error mentioning missing keys
5. **Expected:** File no longer in root watch folder

### Test 3: Malformed JSON (Parse Error)

1. Create a file with broken JSON:
   ```bash
   echo 'not json at all' > /vmPool/r/services/chrysopedia_watch/uat_broken.json
   ```
2. Wait 10 seconds
3. **Expected:** File moved to `failed/uat_broken.json` with `.error` sidecar containing JSON parse error

### Test 4: Non-JSON File Ignored

1. Create a non-JSON file:
   ```bash
   echo 'hello' > /vmPool/r/services/chrysopedia_watch/readme.txt
   ```
2. Wait 10 seconds
3. **Expected:** File remains in root watch folder — not moved to processed/ or failed/
4. **Expected:** No log entry in watcher for this file

### Test 5: File Stability (Simulated Partial Write)

1. Start writing a large file slowly:
   ```bash
   (echo '{"source_file":"test.mp4",' ; sleep 3 ; echo '"creator_folder":"Test","duration_seconds":60,"segments":[]}') > /vmPool/r/services/chrysopedia_watch/uat_slow.json
   ```
2. **Expected:** Watcher waits for file stability before processing (logs show stability check)
3. **Expected:** File ultimately processed (valid JSON) and moved to processed/

### Test 6: Watcher Survives API Downtime

1. Stop the API: `docker stop chrysopedia-api`
2. Drop a valid JSON file into watch folder
3. **Expected:** File moves to `failed/` with `.error` sidecar containing connection error
4. Restart the API: `docker start chrysopedia-api`
5. **Expected:** Watcher continues running (check `docker ps --filter name=chrysopedia-watcher`)

### Cleanup
```bash
rm -f /vmPool/r/services/chrysopedia_watch/processed/uat_*.json
rm -f /vmPool/r/services/chrysopedia_watch/failed/uat_*.json
rm -f /vmPool/r/services/chrysopedia_watch/failed/uat_*.json.error
rm -f /vmPool/r/services/chrysopedia_watch/readme.txt
```

### Operational Readiness (Q8)
- **Health signal:** `docker ps --filter name=chrysopedia-watcher` shows healthy; `docker logs chrysopedia-watcher --tail 5` shows recent activity or idle polling
- **Failure signal:** Container exits or becomes unhealthy; `.error` sidecar files accumulate in `failed/` directory
- **Recovery procedure:** `docker compose restart chrysopedia-watcher` — no state to lose, watcher re-scans on startup
- **Monitoring gaps:** No alerting on failed/ file accumulation; no metrics endpoint. Admin must manually check `failed/` directory or watcher logs.
