Validate pair seed simulation behavior

This commit is contained in:
2026-06-27 19:34:43 +02:00
parent a50b9272fe
commit 098721504d
5 changed files with 173 additions and 1 deletions
+144 -1
View File
@@ -858,6 +858,29 @@ def _insta_pair_case(seed: int, *, pov: bool, position: str, focus: str, family:
)
def _pair_seed_probe(seed: int, *, reroll_axis: str = "none", reroll_seed: int = -1) -> dict[str, Any]:
return pb.build_insta_of_pair(
row_number=1,
start_index=1,
seed=seed,
ethnicity="any",
figure="random",
no_plus_women=False,
no_black=False,
trigger=TRIGGER,
prepend_trigger_to_prompt=True,
seed_config=pb.build_seed_lock_config_json(base_seed=seed, reroll_axis=reroll_axis, reroll_seed=reroll_seed),
options_json=_insta_options(),
character_cast=_random_character_cast(),
hardcore_position_config=_position_filter("penetration_only", "penetration", ["missionary", "doggy", "cowgirl"]),
location_config=_seed_probe_location_config(),
composition_config=_seed_probe_composition_config(),
camera_config=_orbit_camera(horizontal_angle=45, vertical_angle=0, zoom=6.0),
softcore_camera_config=_orbit_camera(horizontal_angle=45, vertical_angle=0, zoom=5.5),
hardcore_camera_config=_orbit_camera(horizontal_angle=135, vertical_angle=20, zoom=7.5),
)
def _seed_probe_row(seed: int, *, reroll_axis: str = "none", reroll_seed: int = -1) -> dict[str, Any]:
return pb.build_prompt(
category="Hardcore sexual poses",
@@ -903,6 +926,27 @@ def _seed_probe_snapshot(row: dict[str, Any]) -> dict[str, Any]:
}
def _pair_seed_snapshot(pair: dict[str, Any]) -> dict[str, Any]:
soft_row = pair.get("softcore_row") if isinstance(pair.get("softcore_row"), dict) else {}
hard_row = pair.get("hardcore_row") if isinstance(pair.get("hardcore_row"), dict) else {}
return {
"shared_cast_descriptors": pair.get("shared_cast_descriptors"),
"soft_cast_descriptor_text": soft_row.get("cast_descriptor_text"),
"hard_cast_descriptor_text": hard_row.get("cast_descriptor_text"),
"soft_scene_text": soft_row.get("scene_text"),
"hard_scene_text": hard_row.get("scene_text"),
"soft_item": soft_row.get("item"),
"hard_item": hard_row.get("item"),
"hard_position_key": hard_row.get("position_key"),
"hard_position_keys": hard_row.get("position_keys") or [],
"hard_source_role_graph": hard_row.get("source_role_graph"),
"soft_composition": soft_row.get("composition"),
"hard_composition": hard_row.get("composition"),
"soft_expression": soft_row.get("character_expression_text"),
"hard_expression": hard_row.get("character_expression_text"),
}
def _same_fields_issues(
name: str,
base: dict[str, Any],
@@ -926,6 +970,24 @@ def _formatter_output_texts(row: dict[str, Any]) -> dict[str, str]:
}
def _pair_formatter_output_texts(pair: dict[str, Any]) -> dict[str, str]:
texts: dict[str, str] = {}
for target in ("softcore", "hardcore"):
formatted = _format_metadata(pair, target)
texts[f"{target}.krea"] = str(
formatted["krea"].get(f"krea_{target}_prompt")
or formatted["krea"].get("krea_prompt")
or ""
)
texts[f"{target}.sdxl"] = str(
formatted["sdxl"].get(f"sdxl_{target}_prompt")
or formatted["sdxl"].get("sdxl_prompt")
or ""
)
texts[f"{target}.caption"] = str(formatted["caption"].get("natural_caption") or "")
return texts
def _seed_determinism_check(seed: int) -> dict[str, Any]:
first = _seed_probe_row(seed)
second = _seed_probe_row(seed)
@@ -942,6 +1004,22 @@ def _seed_determinism_check(seed: int) -> dict[str, Any]:
}
def _pair_seed_determinism_check(seed: int) -> dict[str, Any]:
first = _pair_seed_probe(seed)
second = _pair_seed_probe(seed)
issues: list[str] = []
if first != second:
issues.append("locked seed config did not reproduce identical pair metadata")
if _pair_formatter_output_texts(first) != _pair_formatter_output_texts(second):
issues.append("locked seed config did not reproduce identical pair formatter outputs")
return {
"name": "pair_seed.locked_determinism",
"base": _row_summary(first.get("hardcore_row") or {}),
"changed": False,
"issues": issues,
}
def _seed_reroll_check(
seed: int,
*,
@@ -982,6 +1060,51 @@ def _seed_reroll_check(
}
def _pair_seed_pose_reroll_check(seed: int) -> dict[str, Any]:
name = "pair_seed.pose_reroll"
base = _pair_seed_probe(seed)
base_snapshot = _pair_seed_snapshot(base)
changed = False
changed_seed = None
changed_field_names: list[str] = []
issues: list[str] = []
stable_fields = (
"shared_cast_descriptors",
"soft_cast_descriptor_text",
"hard_cast_descriptor_text",
"soft_scene_text",
"hard_scene_text",
"soft_item",
"soft_composition",
"hard_composition",
)
changed_fields = ("hard_position_key", "hard_item", "hard_source_role_graph")
for reroll_seed in range(seed + 1, seed + 16):
rerolled = _pair_seed_probe(seed, reroll_axis="pose", reroll_seed=reroll_seed)
rerolled_snapshot = _pair_seed_snapshot(rerolled)
field_issues = _same_fields_issues(name, base_snapshot, rerolled_snapshot, stable_fields, reroll_seed)
if field_issues:
issues.extend(field_issues)
break
changed_field_names = [
field for field in changed_fields if base_snapshot.get(field) != rerolled_snapshot.get(field)
]
if changed_field_names:
changed = True
changed_seed = reroll_seed
break
if not changed:
issues.append("pair pose reroll did not change hard_position_key, hard_item, or hard_source_role_graph within 15 attempts")
return {
"name": name,
"base": _row_summary(base.get("hardcore_row") or {}),
"changed": changed,
"changed_seed": changed_seed,
"changed_fields": changed_field_names,
"issues": issues,
}
def _seed_axis_checks(seed: int) -> list[dict[str, Any]]:
return [
_seed_determinism_check(seed),
@@ -1018,6 +1141,13 @@ def _seed_axis_checks(seed: int) -> list[dict[str, Any]]:
]
def _pair_seed_checks(seed: int) -> list[dict[str, Any]]:
return [
_pair_seed_determinism_check(seed),
_pair_seed_pose_reroll_check(seed),
]
def _route_family_coverage_check(
name: str,
*,
@@ -1100,6 +1230,7 @@ def run_simulation(seed: int = 3901, *, include_prompts: bool = False) -> dict[s
cases.extend(_pair_reports("insta_pair.pov_outercourse", pov_pair, include_prompts=include_prompts))
coverage_checks = _route_family_coverage_checks(cases)
axis_checks = _seed_axis_checks(seed + 3)
pair_seed_checks = _pair_seed_checks(seed + 4)
issues = [
{"case": case["name"], "issue": issue}
for case in cases
@@ -1115,18 +1246,25 @@ def run_simulation(seed: int = 3901, *, include_prompts: bool = False) -> dict[s
for check in axis_checks
for issue in check.get("issues", [])
)
issues.extend(
{"case": check["name"], "issue": issue}
for check in pair_seed_checks
for issue in check.get("issues", [])
)
return {
"summary": {
"seed": seed,
"cases": len(cases),
"coverage_checks": len(coverage_checks),
"axis_checks": len(axis_checks),
"pair_seed_checks": len(pair_seed_checks),
"issues": len(issues),
},
"issues": issues,
"cases": cases,
"coverage_checks": coverage_checks,
"axis_checks": axis_checks,
"pair_seed_checks": pair_seed_checks,
}
@@ -1135,7 +1273,8 @@ def _print_text_report(report: dict[str, Any]) -> None:
print(
f"Prompt route simulation: seed={summary.get('seed')} "
f"cases={summary.get('cases')} coverage_checks={summary.get('coverage_checks')} "
f"axis_checks={summary.get('axis_checks')} issues={summary.get('issues')}"
f"axis_checks={summary.get('axis_checks')} pair_seed_checks={summary.get('pair_seed_checks')} "
f"issues={summary.get('issues')}"
)
for case in report.get("cases") or []:
summary_text = case.get("summary") or {}
@@ -1154,6 +1293,10 @@ def _print_text_report(report: dict[str, Any]) -> None:
print(f"- {check.get('name')}: changed={check.get('changed')}")
for issue in check.get("issues") or []:
print(f" ISSUE {issue}")
for check in report.get("pair_seed_checks") or []:
print(f"- {check.get('name')}: changed={check.get('changed')}")
for issue in check.get("issues") or []:
print(f" ISSUE {issue}")
def main(argv: list[str] | None = None) -> int: