Validate pair seed simulation behavior
This commit is contained in:
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user