diff --git a/docs/prompt-pool-routing-map.md b/docs/prompt-pool-routing-map.md index 7c54604..d4e0192 100644 --- a/docs/prompt-pool-routing-map.md +++ b/docs/prompt-pool-routing-map.md @@ -891,6 +891,9 @@ The script does not import ComfyUI. It parses the repo and prints: - effective category route coverage so each normalized category path has usable item, scene, expression, composition, and hardcore route metadata before runtime fallbacks can hide a gap. +- location theme camera-profile validation so `Location Theme` presets and + their scene entries resolve to structured scene-camera profiles instead of + falling back to generic camera prose. - route documentation validation so critical route modules are listed in this map and the architecture plan, and registered in `SMOKE_CASES` by their expected smoke cases. diff --git a/tools/prompt_map_audit.py b/tools/prompt_map_audit.py index 1ae1764..c9932aa 100644 --- a/tools/prompt_map_audit.py +++ b/tools/prompt_map_audit.py @@ -25,7 +25,9 @@ import category_template_metadata as template_metadata_policy # noqa: E402 import category_library as category_policy # noqa: E402 import caption_naturalizer # noqa: E402 import krea_formatter # noqa: E402 +import location_config as location_policy # noqa: E402 import prompt_builder as pb # noqa: E402 +import scene_camera_adapters as scene_camera_policy # noqa: E402 import sdxl_formatter # noqa: E402 POOL_DEFINITION_KEYS = ("scene_pools", "expression_pools", "composition_pools") @@ -513,6 +515,75 @@ def _effective_category_coverage_errors(paths: list[Path]) -> list[tuple[str, st return errors +def _location_theme_camera_profile_errors() -> list[tuple[str, str, str]]: + errors: list[tuple[str, str, str]] = [] + profile_keys = set(scene_camera_policy.SCENE_CAMERA_PROFILE_KEYS) + theme_profile_keys = scene_camera_policy.THEME_PROFILE_KEYS + + for theme_name, theme_data in location_policy.THEMATIC_LOCATION_PRESETS.items(): + theme_path = f"THEMATIC_LOCATION_PRESETS.{theme_name}" + mapped_profile_key = theme_profile_keys.get(theme_name) + if mapped_profile_key and mapped_profile_key not in profile_keys: + errors.append( + ( + "scene_camera_adapters.py", + f"THEME_PROFILE_KEYS.{theme_name}", + f"unknown scene camera profile key: {mapped_profile_key}", + ) + ) + + locations = theme_data.get("locations") if isinstance(theme_data, dict) else None + if not isinstance(locations, list) or not locations: + errors.append(("location_config.py", f"{theme_path}.locations", "theme must define non-empty locations")) + continue + for index, entry in enumerate(locations): + entry_path = f"{theme_path}.locations[{index}]" + if not isinstance(entry, dict): + errors.append(("location_config.py", entry_path, "location entry must be an object")) + continue + slug = str(entry.get("slug") or "").strip() + prompt = str(entry.get("prompt") or "").strip() + if not slug: + errors.append(("location_config.py", f"{entry_path}.slug", "missing slug")) + if not prompt: + errors.append(("location_config.py", f"{entry_path}.prompt", "missing prompt")) + continue + themed_entry = dict(entry) + themed_entry.setdefault("theme", theme_name) + profile = scene_camera_policy.scene_camera_profile( + prompt, + scene_entry=themed_entry, + theme=theme_name, + ) + if not profile: + errors.append( + ( + "scene_camera_adapters.py", + entry_path, + "themed location does not resolve to a scene camera profile", + ) + ) + continue + key = str(profile.get("key") or "").strip() + if key not in profile_keys: + errors.append( + ( + "scene_camera_adapters.py", + entry_path, + f"resolved unknown scene camera profile key: {key or '(empty)'}", + ) + ) + if mapped_profile_key and key != mapped_profile_key: + errors.append( + ( + "scene_camera_adapters.py", + entry_path, + f"theme resolved to {key}, expected {mapped_profile_key}", + ) + ) + return errors + + def _smoke_case_names(path: Path) -> set[str]: if not path.exists(): return set() @@ -883,6 +954,13 @@ def main() -> int: return 1 print("OK: category routes define effective item, scene, expression, composition, and route metadata coverage.") + print("\n# Location Theme Camera Profile Validation") + location_profile_errors = _location_theme_camera_profile_errors() + if location_profile_errors: + print_table(("Source", "Path", "Issue"), location_profile_errors) + return 1 + print("OK: location themes and themed scene entries resolve to scene camera profiles.") + print("\n# Routing Documentation Validation") routing_doc_errors = _routing_doc_errors() if routing_doc_errors: