# S02: Composition Prompt + Test Harness Compose Mode — UAT

**Milestone:** M014
**Written:** 2026-04-03T01:10:16.667Z

## UAT: S02 — Composition Prompt + Test Harness Compose Mode

### Preconditions
- Working directory: project root (`/home/aux/projects/content-to-kb-automator`)
- Python 3.12+ available
- Backend dependencies installed (`pip install -r backend/requirements.txt`)
- S01 synthesis prompt exists at `prompts/stage5_synthesis.txt`

### Test 1: Composition prompt structural integrity
1. Open `prompts/stage5_compose.txt`
2. Verify it contains XML tag references: `<existing_page>`, `<existing_moments>`, `<new_moments>`, `<creator>`
3. Verify citation re-indexing section explains offset scheme: existing [0]-[N-1], new [N]-[N+M-1]
4. Verify merge rules section covers: preserve existing prose, enrich vs duplicate, new section creation
5. Verify at least one JSON example block parses as valid JSON with `pages` key and `body_sections_format: "v2"`
- **Expected:** All checks pass. Prompt is >2000 chars.

### Test 2: Compose CLI subcommand help
1. Run: `cd backend && python -m pipeline.test_harness compose --help`
- **Expected:** Exit code 0. Output shows `--existing-page`, `--fixture`, `--existing-fixture` as required args; `--prompt`, `--output`, `--category`, `--model`, `--modality` as optional.

### Test 3: Unit test suite — full run from project root
1. Run: `python -m pytest pipeline/test_harness_compose.py -v`
- **Expected:** 16 tests pass. No errors or warnings. Runs in <2s.

### Test 4: Unit test suite — full run from backend directory
1. Run: `cd backend && python -m pytest pipeline/test_harness_compose.py -v`
- **Expected:** 16 tests pass. Same results as Test 3.

### Test 5: Prompt XML tag population
1. In a Python shell, import `build_compose_prompt` from `pipeline.test_harness`
2. Call with a mock existing page dict, 3 existing moments, 2 new moments, and a creator name
3. Verify the returned string contains `<existing_page>` with valid JSON inside
4. Verify `<existing_moments>` section has indices [0], [1], [2]
5. Verify `<new_moments>` section has indices [3], [4] (offset by 3)
6. Verify `<creator>` tag contains the creator name
- **Expected:** All XML tags present with correct content and citation indices.

### Test 6: Category filtering behavior
1. Create two MockKeyMoment objects with different `topic_category` values (e.g., "Sound Design" and "Mixing")
2. Create an existing page dict with `topic_category: "Sound Design"`
3. Call `build_compose_prompt` with both moments as new_moments
4. Verify only the "Sound Design" moment appears in the prompt (filtering happens in run_compose, not build_compose_prompt — verify at run_compose level or in test suite)
- **Expected:** TestCategoryFiltering tests confirm only matching-category moments are used.

### Edge Cases
- **Empty new moments:** `build_compose_prompt` with empty new_moments list produces valid prompt with empty `<new_moments>` section
- **Single new moment:** Index starts at N (offset from existing count)
- **Large offset:** 50 existing + 10 new moments produces indices [50]-[59] for new moments
