From 858fbe8d468d949ee62e9202fb0aa4c0f3c00dcd Mon Sep 17 00:00:00 2001 From: Ethanfel Date: Mon, 29 Jun 2026 04:52:01 +0200 Subject: [PATCH] Add Krea2 spread pose candidate --- categories/krea2_pov_pose_variants.json | 37 +++++++++++++++++++++++++ docs/krea2-pov-pose-atlas.md | 8 ++++++ tools/prompt_smoke.py | 34 +++++++++++++++++++++-- 3 files changed, 77 insertions(+), 2 deletions(-) diff --git a/categories/krea2_pov_pose_variants.json b/categories/krea2_pov_pose_variants.json index 3f17406..0b4d951 100644 --- a/categories/krea2_pov_pose_variants.json +++ b/categories/krea2_pov_pose_variants.json @@ -216,6 +216,43 @@ "guide_section": "", "notes": "Atlas shows a repeated open-thigh manual-contact POV layout; needs fixed-seed Krea2 tests before promotion to proven." } + }, + { + "key": "pov_spread_open_thigh_presentation", + "family": "spread", + "status": "candidate", + "atlas_folders": ["spread"], + "action_family": "interaction", + "position_keys": ["open_thighs", "camera_showing"], + "canonical_geometry": "Frontal open-thigh presentation view: the woman faces the camera with legs raised or knees held wide, thighs forming a wide V-frame toward the viewer, face and torso visible behind the open-leg pose, and no required partner contact.", + "prompt_cues": [ + "POV open-thigh presentation position", + "woman faces the camera with legs raised or knees held wide", + "thighs form a wide V-frame toward the viewer", + "face and torso remain visible behind the open-leg pose", + "hands may hold the knees or thighs open", + "no partner contact is required for this setup pose" + ], + "avoid_cues": [ + "adding penetration or manual contact by default", + "closed thighs hiding the open-leg geometry", + "cropping out the face and torso behind the leg frame", + "turning the pose into doggy or side-lying geometry" + ], + "reference_images": [ + "spread/100_spread_.png", + "spread/4_spread_.png", + "spread/69_spread_.png" + ], + "generator_hook": { + "module": "krea_pov_actions.py", + "route_terms": ["spread", "open thighs", "legs spread"] + }, + "evidence": { + "fixed_seed_tests": [], + "guide_section": "", + "notes": "Atlas shows a repeated open-thigh presentation/setup pose; needs fixed-seed Krea2 tests before promotion to proven." + } } ] } diff --git a/docs/krea2-pov-pose-atlas.md b/docs/krea2-pov-pose-atlas.md index a2417d8..f3249be 100644 --- a/docs/krea2-pov-pose-atlas.md +++ b/docs/krea2-pov-pose-atlas.md @@ -117,3 +117,11 @@ reclined or sitting back with thighs spread wide toward camera, her face and torso visible behind the open-leg frame, and the viewer hand entering from the foreground as the contact anchor. Treat `pov_fingering_reclined_open_thighs` as a candidate until it has fixed-seed Krea2 evidence. + +### Spread / Open-Thigh Presentation + +The spread folder is a setup/presentation family rather than a required contact +action: the woman faces the camera with legs raised or knees held wide, thighs +forming a wide V-frame, and her face and torso visible behind the open-leg pose. +Treat `pov_spread_open_thigh_presentation` as a candidate until it has +fixed-seed Krea2 evidence. diff --git a/tools/prompt_smoke.py b/tools/prompt_smoke.py index a248483..d547d41 100644 --- a/tools/prompt_smoke.py +++ b/tools/prompt_smoke.py @@ -6797,6 +6797,11 @@ def smoke_krea2_pose_variant_catalog_policy() -> None: manual == ["pov_fingering_reclined_open_thighs"], f"Krea2 pose-variant manual filtering changed unexpectedly: {manual}", ) + interaction = krea2_pose_variant_catalog.variant_keys(action_family="interaction") + _expect( + interaction == ["pov_spread_open_thigh_presentation"], + f"Krea2 pose-variant interaction filtering changed unexpectedly: {interaction}", + ) handjob = krea2_pose_variant_catalog.get_variant("pov_handjob_upright_centered") _expect( any("woman's right hand wraps" in str(cue) for cue in handjob.get("prompt_cues", [])), @@ -6817,6 +6822,12 @@ def smoke_krea2_pose_variant_catalog_policy() -> None: any("viewer hand enters from the foreground" in str(cue) for cue in fingering.get("prompt_cues", [])), "Fingering variant lost foreground-hand cue", ) + spread = krea2_pose_variant_catalog.get_variant("pov_spread_open_thigh_presentation") + _expect(spread.get("status") == "candidate", "Spread variant should remain a candidate until fixed-seed evidence exists") + _expect( + any("legs raised or knees held wide" in str(cue) for cue in spread.get("prompt_cues", [])), + "Spread variant lost open-thigh cue", + ) refs = krea2_pose_variant_catalog.reference_paths("pov_boobjob_upright_cleavage") _expect(refs and all(path.name.endswith(".png") for path in refs), "Boobjob reference paths are not image paths") _expect(all("bg" not in str(path).lower() for path in refs), "Reference paths should not include background-only atlas images") @@ -6880,21 +6891,30 @@ def smoke_krea2_tuning_report_policy() -> None: fingering = by_key.get("pov_fingering_reclined_open_thighs") or {} _expect(fingering.get("coverage_state") == "needs_fixed_seed_tests", "Fingering report should need fixed-seed tests") _expect(fingering.get("accepted_evidence_count") == 0, "Fingering report should not have accepted evidence yet") + spread = by_key.get("pov_spread_open_thigh_presentation") or {} + _expect(spread.get("coverage_state") == "needs_fixed_seed_tests", "Spread report should need fixed-seed tests") + _expect(spread.get("accepted_evidence_count") == 0, "Spread report should not have accepted evidence yet") summary = krea2_tuning_report.coverage_summary() _expect(summary.get("status_counts", {}).get("proven") == 3, "Krea2 tuning report proven count changed") - _expect(summary.get("status_counts", {}).get("candidate") == 3, "Krea2 tuning report candidate count changed") + _expect(summary.get("status_counts", {}).get("candidate") == 4, "Krea2 tuning report candidate count changed") _expect( summary.get("variants_without_accepted_evidence") == [ "pov_ballsucking_low_head", "pov_footjob_frontal_sole_stroke", "pov_fingering_reclined_open_thighs", + "pov_spread_open_thigh_presentation", ], f"Krea2 tuning report missing-evidence set changed: {summary.get('variants_without_accepted_evidence')}", ) plans = krea2_tuning_report.next_test_plans() _expect( [plan.get("key") for plan in plans] - == ["pov_ballsucking_low_head", "pov_footjob_frontal_sole_stroke", "pov_fingering_reclined_open_thighs"], + == [ + "pov_ballsucking_low_head", + "pov_footjob_frontal_sole_stroke", + "pov_fingering_reclined_open_thighs", + "pov_spread_open_thigh_presentation", + ], "Krea2 tuning report next plans changed", ) plan_by_key = {plan.get("key"): plan for plan in plans} @@ -6929,6 +6949,15 @@ def smoke_krea2_tuning_report_policy() -> None: any(str(path).endswith("fingering/103_fingering.png") for path in fingering_plan.get("reference_paths") or []), "Fingering test plan lost atlas reference path", ) + spread_plan = plan_by_key["pov_spread_open_thigh_presentation"] + _expect( + "legs raised or knees held wide" in " ".join(spread_plan.get("prompt_cues") or []), + "Spread test plan lost open-thigh cue", + ) + _expect( + any(str(path).endswith("spread/100_spread_.png") for path in spread_plan.get("reference_paths") or []), + "Spread test plan lost atlas reference path", + ) with tempfile.TemporaryDirectory() as tmpdir: atlas_root = Path(tmpdir) for folder in ("doggy", "doggy_control", "custom_pose", "custom_pose_control", "bg", "woman", "doggy_bg"): @@ -6963,6 +6992,7 @@ def smoke_krea2_tuning_report_policy() -> None: _expect("pov_ballsucking_low_head" in markdown, "Krea2 tuning report markdown lost candidate variant") _expect("pov_footjob_frontal_sole_stroke" in markdown, "Krea2 tuning report markdown lost footjob candidate variant") _expect("pov_fingering_reclined_open_thighs" in markdown, "Krea2 tuning report markdown lost fingering candidate variant") + _expect("pov_spread_open_thigh_presentation" in markdown, "Krea2 tuning report markdown lost spread candidate variant") _expect("needs_fixed_seed_tests" in markdown, "Krea2 tuning report markdown lost coverage state") _expect("Prompt cues" in markdown, "Krea2 tuning report markdown lost next-test cue section") _expect("Avoid cues" in markdown, "Krea2 tuning report markdown lost next-test avoid section")