# Normal Camera Unused Pool Extension Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Extend the no-generation normal-camera atlas prep system across larger unused image pools, starting with the uncovered `reverse cowgirl` folder. **Architecture:** Keep the folder inventory and curated variant catalog as the source of truth. Add read-only review/backlog builders to `normal_camera_atlas_prep.py`, write review artifacts under `ab_batches/normal_camera/`, then add selected catalog variants only when review evidence supports stable non-POV camera/pose families. **Tech Stack:** Python standard library, Pillow for optional contact-sheet image output, existing JSON catalogs, existing `tools/prompt_smoke.py` smoke harness. --- ### Task 1: Add Unused-Pool Review Artifact Tests **Files:** - Modify: `tools/prompt_smoke.py` - Test: `python tools/prompt_smoke.py --case normal_camera_unused_pool_review_artifacts --quiet` - [ ] **Step 1: Add failing smoke coverage** Add a smoke case that imports `normal_camera_atlas_prep`, calls `build_unused_pool_backlog(limit=5)`, `build_review_manifest("reverse cowgirl", page_size=40)`, and `build_contact_sheet_html("reverse cowgirl", page_size=40)`, then asserts: ```python backlog = prep_module.build_unused_pool_backlog(limit=5) _expect(backlog.get("schema") == "sxcp_normal_camera_unused_pool_backlog_v1", "Normal camera unused-pool backlog schema changed") _expect(backlog.get("no_generation") is True, "Normal camera unused-pool backlog must stay no-generation") _expect((backlog.get("folders") or [])[0].get("folder") == "reverse cowgirl", "Reverse cowgirl should be the first unused-pool tranche") manifest = prep_module.build_review_manifest("reverse cowgirl", page_size=40) _expect(manifest.get("schema") == "sxcp_normal_camera_review_manifest_v1", "Normal camera review manifest schema changed") _expect(manifest.get("folder") == "reverse cowgirl", "Review manifest should target reverse cowgirl") _expect(manifest.get("image_count") == 240, "Reverse cowgirl review should cover all 240 JPGs") _expect(len(manifest.get("contact_sheet_pages") or []) == 6, "Reverse cowgirl review should be paged at 40 images per sheet") _expect("back_view" in manifest.get("review_bucket_values", {}), "Review buckets lost back-view routing") html = prep_module.build_contact_sheet_html("reverse cowgirl", page_size=40) _expect("reverse cowgirl/0001.jpg" in html, "Contact sheet lost first reverse-cowgirl image") _expect("data-review-bucket" in html, "Contact sheet should expose review buckets") ``` - [ ] **Step 2: Register the new smoke case** Add `("normal_camera_unused_pool_review_artifacts", smoke_normal_camera_unused_pool_review_artifacts)` after the existing normal-camera prep smoke case. - [ ] **Step 3: Verify the test fails** Run: ```bash python tools/prompt_smoke.py --case normal_camera_unused_pool_review_artifacts --quiet ``` Expected: failure because `build_unused_pool_backlog`, `build_review_manifest`, and `build_contact_sheet_html` do not exist yet. ### Task 2: Implement Backlog and Review Manifest Builders **Files:** - Modify: `normal_camera_atlas_prep.py` - Test: `python tools/prompt_smoke.py --case normal_camera_unused_pool_review_artifacts --quiet` - [ ] **Step 1: Add schemas and review buckets** Add constants: ```python UNUSED_POOL_BACKLOG_SCHEMA = "sxcp_normal_camera_unused_pool_backlog_v1" REVIEW_MANIFEST_SCHEMA = "sxcp_normal_camera_review_manifest_v1" DEFAULT_REVIEW_DIR = DEFAULT_OUTPUT_DIR / "review" REVIEW_BUCKET_VALUES = { "back_view": "Rear-facing normal-camera view where back/hips face camera.", "back_three_quarter": "Rear-offset normal-camera view with enough side/torso context.", "side_view": "Profile or near-profile lateral view with the body/action axis across frame.", "front_view": "Front-facing normal-camera view where the contact plane faces camera.", "front_three_quarter": "Front-offset normal-camera view.", "top_or_low_special": "Overhead, high-downward, low-angle, or under-view special camera.", "reject_or_unclear": "POV-like, mismatched, unclear, duplicate-only, or too mixed for cue drafting.", } ``` - [ ] **Step 2: Add helper functions** Add helpers to compute selected-reference coverage and page full-folder images: ```python def _natural_sort_key(text: str) -> list[int | str]: return [int(part) if part.isdigit() else part.lower() for part in re.split(r"(\\d+)", text)] def _atlas_folder_rows() -> list[dict[str, Any]]: return list(load_atlas().get("folders") or []) def _variant_reference_map() -> dict[str, set[str]]: refs_by_folder: dict[str, set[str]] = {} for variant in load_variants().get("variants") or []: for ref in _reference_images(variant): folder = ref.rsplit("/", 1)[0] refs_by_folder.setdefault(folder, set()).add(ref) return refs_by_folder ``` - [ ] **Step 3: Implement backlog builder** Implement `build_unused_pool_backlog(limit: int | None = None)` so it ranks non-empty folders by unselected image count, with fields `folder`, `image_count`, `selected_reference_count`, `remaining_image_count`, `covered_by_variants`, `camera_view`, `action_family`, `catalog_status`, and `suggested_action`. - [ ] **Step 4: Implement review manifest and HTML builders** Implement `build_review_manifest(folder_name: str, page_size: int = 40)` and `build_contact_sheet_html(folder_name: str, page_size: int = 40)` so `reverse cowgirl` produces six pages and exposes review buckets without classifying any image as truth. - [ ] **Step 5: Verify green** Run: ```bash python tools/prompt_smoke.py --case normal_camera_unused_pool_review_artifacts --quiet ``` Expected: `OK: smoke passed (1 cases).` ### Task 3: Write Review Artifacts **Files:** - Modify: `normal_camera_atlas_prep.py` - Create: `ab_batches/normal_camera/normal_camera_unused_pool_backlog.json` - Create: `ab_batches/normal_camera/review/reverse_cowgirl_review_manifest.json` - Create: `ab_batches/normal_camera/review/reverse_cowgirl_contact_sheet.html` - Test: `python -m normal_camera_atlas_prep --write-artifacts --output-dir ab_batches/normal_camera` - [ ] **Step 1: Extend artifact writing** Update `write_artifacts()` to include the unused-pool backlog and reverse-cowgirl review artifacts. Keep existing artifact names stable. - [ ] **Step 2: Regenerate artifacts** Run: ```bash python -m normal_camera_atlas_prep --write-artifacts --output-dir ab_batches/normal_camera ``` Expected: output includes the four existing artifacts plus `unused_pool_backlog`, `reverse_cowgirl_review_manifest`, and `reverse_cowgirl_contact_sheet`. - [ ] **Step 3: Verify prep smoke** Run: ```bash python tools/prompt_smoke.py --case normal_camera_atlas_prep_artifacts --case normal_camera_unused_pool_review_artifacts --quiet ``` Expected: `OK: smoke passed (2 cases).` ### Task 4: Add Reverse-Cowgirl Catalog Source Pool **Files:** - Modify: `categories/normal_camera_variants.json` - Modify: `tools/prompt_smoke.py` - Test: `python tools/prompt_smoke.py --case normal_camera_atlas_catalog --quiet` - [ ] **Step 1: Add failing catalog expectation** Extend `required_variants` in `smoke_normal_camera_atlas_catalog()` with `normal_reverse_cowgirl_mixed_camera_folder_pool`. - [ ] **Step 2: Verify red** Run: ```bash python tools/prompt_smoke.py --case normal_camera_atlas_catalog --quiet ``` Expected: failure because the mixed source-pool variant does not exist. - [ ] **Step 3: Add the source-pool variant** Add a `needs_samples` variant after the existing labeled reverse-cowgirl variants: ```json { "key": "normal_reverse_cowgirl_mixed_camera_folder_pool", "family": "reverse_cowgirl", "status": "needs_samples", "atlas_folders": ["reverse cowgirl"], "camera_view": "mixed_or_unspecified", "action_family": "reverse_cowgirl", "canonical_geometry": "Large reverse-cowgirl source pool with normal-camera examples but no single locked camera view until contact-sheet review selects stable subsets.", "prompt_cues": [ "reverse cowgirl normal-camera source pool", "select a repeated camera family before cue drafting", "use contact-sheet evidence before fixed-seed testing" ], "avoid_cues": [ "using the full mixed folder as one locked camera preset", "POV reverse-cowgirl wording", "inventing camera cues from the folder label alone" ], "reference_images": [ "reverse cowgirl/0001.jpg", "reverse cowgirl/288.jpg", "reverse cowgirl/82.jpg" ], "generator_hook": { "module": "future normal-camera routing; likely camera_config.py / row_camera.py / krea_format_route.py", "route_terms": ["reverse cowgirl", "mixed camera source pool"], "notes": "Future hook only. This catalog does not change generator defaults, prompt routes, formatters, eval logs, or POV workflow files." }, "pre_ab_notes": "Added as the first large unused-pool review tranche. The full 240-image folder is a cue-expansion pool, not a prompt-ready route; split selected-reference subvariants only after contact-sheet evidence shows repeated non-POV camera geometry.", "folder_pool": true, "visual_review": { "reviewed_at": "2026-07-02", "scope": "Paged contact-sheet review scaffold covering 240 JPGs across atlas_folders plus representative references.", "decision": "added_as_large_unused_pool_review_tranche", "notes": "Folder is now tracked for review; selected-reference subvariants should be added only from repeated camera/pose families identified in the contact sheet." } } ``` - [ ] **Step 4: Update inventory counts** Increment `variant_count` and `needs_samples`, increment `covered_non_empty_folder_count`, decrement `uncovered_non_empty_folder_count`, and remove `reverse cowgirl` from `uncovered_non_empty_folders`. - [ ] **Step 5: Verify green** Run: ```bash python tools/prompt_smoke.py --case normal_camera_atlas_catalog --quiet ``` Expected: `OK: smoke passed (1 cases).` ### Task 5: Document and Regenerate Prep Outputs **Files:** - Modify: `docs/normal-camera-atlas.md` - Modify: `ab_batches/normal_camera/normal_camera_priority_plan.json` - Modify: `ab_batches/normal_camera/normal_camera_prompt_cue_batch.json` - Modify: `ab_batches/normal_camera/normal_camera_score_sheet.json` - Test: `python tools/prompt_smoke.py --case normal_camera_atlas_catalog --case normal_camera_atlas_prep_artifacts --case normal_camera_unused_pool_review_artifacts --quiet` - [ ] **Step 1: Update docs** Document that the unused-pool extension starts with `reverse cowgirl`, adds `normal_camera_unused_pool_backlog.json`, and keeps full mixed folders out of `pre_ab_candidate` until selected-reference subvariants exist. - [ ] **Step 2: Regenerate artifacts** Run: ```bash python -m normal_camera_atlas_prep --write-artifacts --output-dir ab_batches/normal_camera ``` - [ ] **Step 3: Verify focused smoke** Run: ```bash python tools/prompt_smoke.py --case normal_camera_atlas_catalog --case normal_camera_atlas_prep_artifacts --case normal_camera_unused_pool_review_artifacts --quiet ``` Expected: `OK: smoke passed (3 cases).` ### Task 6: Visual Split Follow-Up **Files:** - Modify later: `categories/normal_camera_variants.json` - Modify later: `docs/normal-camera-atlas.md` - Test later: focused smoke cases above - [ ] **Step 1: Review the contact sheet** Open `ab_batches/normal_camera/review/reverse_cowgirl_contact_sheet.html` or generated page images, classify repeated non-POV camera/pose families, and record selected image paths. - [ ] **Step 2: Add selected-reference subvariants only when evidence is stable** For each repeated family, add a subvariant with `source_variant: "normal_reverse_cowgirl_mixed_camera_folder_pool"`, `subset_selection.type: "review_selected_reference_images"`, positive-only cue sentences, and selected `reference_images`. - [ ] **Step 3: Leave weak groups as `needs_samples`** Do not promote one-off frames, POV-like frames, or visually mixed groups. Keep them in source-pool notes or review buckets until more evidence exists.