Audit effective category route coverage

This commit is contained in:
2026-06-27 17:37:28 +02:00
parent c59c9947b2
commit 9668bd1709
2 changed files with 143 additions and 0 deletions
+3
View File
@@ -888,6 +888,9 @@ The script does not import ComfyUI. It parses the repo and prints:
- JSON reference validation for every `scene_pools`, `expression_pools`, and - JSON reference validation for every `scene_pools`, `expression_pools`, and
`composition_pools` reference; `composition_pools` reference;
- item template validation so `{placeholder}` names resolve to `item_axes`. - item template validation so `{placeholder}` names resolve to `item_axes`.
- 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.
- route documentation validation so critical route modules are listed in this - route documentation validation so critical route modules are listed in this
map and the architecture plan, and registered in `SMOKE_CASES` by their map and the architecture plan, and registered in `SMOKE_CASES` by their
expected smoke cases. expected smoke cases.
+140
View File
@@ -22,6 +22,7 @@ if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT)) sys.path.insert(0, str(ROOT))
import category_template_metadata as template_metadata_policy # noqa: E402 import category_template_metadata as template_metadata_policy # noqa: E402
import category_library as category_policy # noqa: E402
import caption_naturalizer # noqa: E402 import caption_naturalizer # noqa: E402
import krea_formatter # noqa: E402 import krea_formatter # noqa: E402
import prompt_builder as pb # noqa: E402 import prompt_builder as pb # noqa: E402
@@ -380,6 +381,138 @@ def _hardcore_template_metadata_errors(paths: list[Path]) -> list[tuple[str, str
return errors return errors
def _item_candidates_for_coverage(subcategory: dict[str, Any]) -> list[Any]:
items = subcategory.get("items")
if isinstance(items, list) and items:
return items
return [subcategory.get("name") or subcategory.get("slug") or ""]
def _configured_pool_errors(
*,
category: dict[str, Any],
subcategory: dict[str, Any],
item: Any,
path: str,
pool_label: str,
direct_key: str,
pool_key: str,
pool_library: dict[str, list[Any]],
inherit_key: str,
) -> list[tuple[str, str, str]]:
try:
entries = category_policy.configured_pool(
category,
subcategory,
item,
direct_key,
pool_key,
pool_library,
inherit_key,
)
except Exception as exc:
return [("(category library)", f"{path}.{pool_label}", f"cannot resolve effective pool: {exc}")]
if not entries:
return [("(category library)", f"{path}.{pool_label}", "missing effective configured entries")]
return []
def _effective_category_coverage_errors(paths: list[Path]) -> list[tuple[str, str, str]]:
# `paths` is accepted to keep this check grouped with the other category
# validations. The effective route check uses the normalized loader because
# generation also consumes normalized category objects.
_ = paths
categories = category_policy.load_category_library()
scene_pools = category_policy.load_scene_pool_library()
expression_pools = category_policy.load_expression_pool_library()
composition_pools = category_policy.load_composition_pool_library()
errors: list[tuple[str, str, str]] = []
if not categories:
return [("(category library)", "categories", "no categories loaded")]
for category in categories:
category_slug = str(category.get("slug") or category.get("name") or "category")
category_path = f"categories.{category_slug}"
subject_type = str(category.get("subject_type") or "").strip()
if not subject_type:
errors.append(("(category library)", f"{category_path}.subject_type", "missing subject_type"))
subcategories = category.get("subcategories")
if not isinstance(subcategories, list) or not subcategories:
errors.append(("(category library)", f"{category_path}.subcategories", "missing subcategories"))
continue
for subcategory in subcategories:
if not isinstance(subcategory, dict):
errors.append(("(category library)", f"{category_path}.subcategories", "subcategory must be an object"))
continue
sub_slug = str(subcategory.get("slug") or subcategory.get("name") or "subcategory")
sub_path = f"{category_path}.subcategories.{sub_slug}"
effective_subject = str(subcategory.get("subject_type") or subject_type).strip()
if not effective_subject:
errors.append(("(category library)", f"{sub_path}.subject_type", "missing effective subject_type"))
has_items = isinstance(subcategory.get("items"), list) and bool(subcategory.get("items"))
has_templates = isinstance(subcategory.get("item_templates"), list) and bool(subcategory.get("item_templates"))
if not has_items and not has_templates:
errors.append(("(category library)", f"{sub_path}.items", "missing items or item_templates"))
for item_index, item in enumerate(_item_candidates_for_coverage(subcategory)):
item_path = f"{sub_path}.items[{item_index}]"
errors.extend(
_configured_pool_errors(
category=category,
subcategory=subcategory,
item=item,
path=item_path,
pool_label="scenes",
direct_key="scenes",
pool_key="scene_pools",
pool_library=scene_pools,
inherit_key="inherit_scenes",
)
)
errors.extend(
_configured_pool_errors(
category=category,
subcategory=subcategory,
item=item,
path=item_path,
pool_label="expressions",
direct_key="expressions",
pool_key="expression_pools",
pool_library=expression_pools,
inherit_key="inherit_expressions",
)
)
errors.extend(
_configured_pool_errors(
category=category,
subcategory=subcategory,
item=item,
path=item_path,
pool_label="compositions",
direct_key="compositions",
pool_key="composition_pools",
pool_library=composition_pools,
inherit_key="inherit_compositions",
)
)
if category_slug == "hardcore_sexual_poses" and has_templates:
metadata = subcategory.get("item_template_metadata")
if not isinstance(metadata, dict):
errors.append(("(category library)", f"{sub_path}.item_template_metadata", "missing route metadata"))
continue
normalized = template_metadata_policy.template_metadata(metadata)
if not template_metadata_policy.template_action_family(normalized):
errors.append(("(category library)", f"{sub_path}.item_template_metadata", "missing normalized action_family"))
if not template_metadata_policy.template_position_family(normalized):
errors.append(("(category library)", f"{sub_path}.item_template_metadata", "missing normalized position_family"))
return errors
def _smoke_case_names(path: Path) -> set[str]: def _smoke_case_names(path: Path) -> set[str]:
if not path.exists(): if not path.exists():
return set() return set()
@@ -743,6 +876,13 @@ def main() -> int:
return 1 return 1
print("OK: hardcore template subcategories define explicit route metadata defaults.") print("OK: hardcore template subcategories define explicit route metadata defaults.")
print("\n# Effective Category Route Coverage Validation")
category_coverage_errors = _effective_category_coverage_errors(category_paths)
if category_coverage_errors:
print_table(("Source", "Path", "Issue"), category_coverage_errors)
return 1
print("OK: category routes define effective item, scene, expression, composition, and route metadata coverage.")
print("\n# Routing Documentation Validation") print("\n# Routing Documentation Validation")
routing_doc_errors = _routing_doc_errors() routing_doc_errors = _routing_doc_errors()
if routing_doc_errors: if routing_doc_errors: