diff --git a/categories/krea2_pov_pose_variants.json b/categories/krea2_pov_pose_variants.json index 54082cd..edbdd61 100644 --- a/categories/krea2_pov_pose_variants.json +++ b/categories/krea2_pov_pose_variants.json @@ -255,6 +255,44 @@ "notes": "The wand folder repeats a foreground-hand toy-contact layout with open thighs and the visible partner behind the tool; needs fixed-seed Krea2 tests before promotion to proven." } }, + { + "key": "pov_ejaculation_aftermath_open_thigh_candidate", + "family": "ready", + "status": "candidate", + "atlas_folders": ["ready"], + "action_family": "climax", + "position_keys": ["open_thighs", "camera_showing"], + "canonical_geometry": "First-person aftermath view: the woman reclines or sits back facing the viewer with thighs spread open, face and torso readable behind the open-leg frame, viewer body cue or recently withdrawn foreground cue near the lower edge, and visible aftermath fluid remaining at the central contact area.", + "prompt_cues": [ + "POV ejaculation aftermath open-thigh position", + "woman reclines or sits back facing the viewer with thighs spread open", + "visible aftermath fluid remains at the central contact area between her open thighs", + "viewer body cue or recently withdrawn foreground cue stays near the lower edge", + "her face and torso remain visible behind the open-leg frame", + "thighs and knees frame the aftermath detail without hiding it" + ], + "avoid_cues": [ + "active thrusting or penetration-in-progress wording", + "turning the setup into oral, toy, or manual contact", + "generic wetness without visible aftermath fluid at the central area", + "closed thighs hiding the aftermath detail", + "cropping out the face and torso behind the open-leg frame" + ], + "reference_images": [ + "ready/105_ready_.png", + "ready/106_ready_.png", + "ready/107_ready_.png" + ], + "generator_hook": { + "module": "krea_pov_actions.py", + "route_terms": ["ejaculation aftermath", "visible aftermath fluid", "open thighs"] + }, + "evidence": { + "fixed_seed_tests": [], + "guide_section": "", + "notes": "The ready folder is post-contact open-thigh aftermath, not a neutral ready/setup pose; needs fixed-seed Krea2 tests before promotion to proven." + } + }, { "key": "pov_spread_open_thigh_presentation", "family": "spread", diff --git a/docs/krea2-pov-pose-atlas.md b/docs/krea2-pov-pose-atlas.md index 53e7074..f408899 100644 --- a/docs/krea2-pov-pose-atlas.md +++ b/docs/krea2-pov-pose-atlas.md @@ -28,10 +28,9 @@ catalog variants are proven or pending and which atlas pose folders are still unmapped by the catalog. Unmapped folders include sample pose/control image paths and a suggested candidate key to start the next catalog entry. -The `ready` folder name is misleading for prompt planning: treat it as an -aftermath/open-thigh family with visible fluid at the central contact area, not -as a neutral setup pose. The report therefore suggests an aftermath candidate -key for that folder until a proper catalog variant is added. +The `ready` folder name is misleading for prompt planning: it is mapped as +`pov_ejaculation_aftermath_open_thigh_candidate`, an aftermath/open-thigh family +with visible fluid at the central contact area, not as a neutral setup pose. ## Inventory @@ -133,6 +132,17 @@ foreground with the rounded head pressed to the central contact point. Treat evidence. Keep the visible hand/handle in the wording; otherwise Krea2 may float the toy or transfer ownership to the visible partner. +### Ready / Open-Thigh Aftermath + +The ready folder is not a neutral setup family. It repeats a first-person +aftermath view: the woman reclines or sits back facing the viewer with thighs +spread open, face and torso readable behind the open-leg frame, a viewer body cue +or recently withdrawn foreground cue near the lower edge, and visible aftermath +fluid at the central contact area. Treat +`pov_ejaculation_aftermath_open_thigh_candidate` as a candidate until it has +fixed-seed Krea2 evidence. Avoid active thrusting wording here; the key state is +post-contact visibility, not penetration-in-progress. + ### Spread / Open-Thigh Presentation The spread folder is a setup/presentation family rather than a required contact diff --git a/tools/prompt_smoke.py b/tools/prompt_smoke.py index 1699663..9588033 100644 --- a/tools/prompt_smoke.py +++ b/tools/prompt_smoke.py @@ -6815,6 +6815,11 @@ def smoke_krea2_pose_variant_catalog_policy() -> None: toy == ["pov_wand_foreground_tool_contact"], f"Krea2 pose-variant toy filtering changed unexpectedly: {toy}", ) + climax = krea2_pose_variant_catalog.variant_keys(action_family="climax") + _expect( + climax == ["pov_ejaculation_aftermath_open_thigh_candidate"], + f"Krea2 pose-variant climax filtering changed unexpectedly: {climax}", + ) interaction = krea2_pose_variant_catalog.variant_keys(action_family="interaction") _expect( interaction == ["pov_spread_open_thigh_presentation"], @@ -6856,6 +6861,12 @@ def smoke_krea2_pose_variant_catalog_policy() -> None: any("viewer hand holds a wand-style toy from the foreground" in str(cue) for cue in wand.get("prompt_cues", [])), "Wand variant lost foreground tool-hold cue", ) + ready = krea2_pose_variant_catalog.get_variant("pov_ejaculation_aftermath_open_thigh_candidate") + _expect(ready.get("status") == "candidate", "Ready aftermath variant should remain a candidate until fixed-seed evidence exists") + _expect( + any("visible aftermath fluid remains at the central contact area" in str(cue) for cue in ready.get("prompt_cues", [])), + "Ready aftermath variant lost central fluid 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( @@ -6988,6 +6999,9 @@ def smoke_krea2_tuning_report_policy() -> None: wand = by_key.get("pov_wand_foreground_tool_contact") or {} _expect(wand.get("coverage_state") == "needs_fixed_seed_tests", "Wand report should need fixed-seed tests") _expect(wand.get("accepted_evidence_count") == 0, "Wand report should not have accepted evidence yet") + ready = by_key.get("pov_ejaculation_aftermath_open_thigh_candidate") or {} + _expect(ready.get("coverage_state") == "needs_fixed_seed_tests", "Ready aftermath report should need fixed-seed tests") + _expect(ready.get("accepted_evidence_count") == 0, "Ready aftermath 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") @@ -7023,13 +7037,14 @@ def smoke_krea2_tuning_report_policy() -> None: _expect(reverse_cowgirl_alt.get("accepted_evidence_count") == 0, "Reverse cowgirl alt 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") == 15, "Krea2 tuning report candidate count changed") + _expect(summary.get("status_counts", {}).get("candidate") == 16, "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_wand_foreground_tool_contact", + "pov_ejaculation_aftermath_open_thigh_candidate", "pov_spread_open_thigh_presentation", "pov_blowjob_top_down_vertical_shaft", "pov_blowjob_side_profile_oral", @@ -7052,6 +7067,7 @@ def smoke_krea2_tuning_report_policy() -> None: "pov_footjob_frontal_sole_stroke", "pov_fingering_reclined_open_thighs", "pov_wand_foreground_tool_contact", + "pov_ejaculation_aftermath_open_thigh_candidate", "pov_spread_open_thigh_presentation", "pov_blowjob_top_down_vertical_shaft", "pov_blowjob_side_profile_oral", @@ -7107,6 +7123,15 @@ def smoke_krea2_tuning_report_policy() -> None: any(str(path).endswith("wand/106_wand_.png") for path in wand_plan.get("reference_paths") or []), "Wand test plan lost atlas reference path", ) + ready_plan = plan_by_key["pov_ejaculation_aftermath_open_thigh_candidate"] + _expect( + "visible aftermath fluid remains at the central contact area" in " ".join(ready_plan.get("prompt_cues") or []), + "Ready aftermath test plan lost central fluid cue", + ) + _expect( + any(str(path).endswith("ready/105_ready_.png") for path in ready_plan.get("reference_paths") or []), + "Ready aftermath 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 []), @@ -7220,37 +7245,36 @@ def smoke_krea2_tuning_report_policy() -> None: atlas_by_folder = {row.get("folder"): row for row in atlas_rows} _expect(atlas_by_folder.get("doggy", {}).get("mapped") is True, "Atlas report should mark catalog folders as mapped") _expect(atlas_by_folder.get("custom_pose", {}).get("mapped") is False, "Atlas report should expose unmapped pose folders") - _expect(atlas_by_folder.get("ready", {}).get("mapped") is False, "Atlas report should expose unmapped ready folder") + _expect(atlas_by_folder.get("ready", {}).get("mapped") is True, "Atlas report should mark ready as mapped once cataloged") _expect("doggy_control" not in atlas_by_folder, "Atlas report should exclude control folders") _expect("doggy_bg" not in atlas_by_folder, "Atlas report should exclude background folders") _expect("bg" not in atlas_by_folder, "Atlas report should exclude shared bg folder") _expect("woman" not in atlas_by_folder, "Atlas report should exclude non-pose woman folder") atlas_summary = krea2_tuning_report.atlas_coverage_summary(atlas_root=atlas_root) _expect(atlas_summary.get("pose_folder_count") == 3, "Atlas report should count only pose folders") - _expect(atlas_summary.get("mapped_folder_count") == 1, "Atlas report should count mapped pose folders") - _expect(atlas_summary.get("unmapped_folders") == ["custom_pose", "ready"], "Atlas report should identify unmapped pose folders") + _expect(atlas_summary.get("mapped_folder_count") == 2, "Atlas report should count mapped pose folders") + _expect(atlas_summary.get("unmapped_folders") == ["custom_pose"], "Atlas report should identify unmapped pose folders") gap_plans = krea2_tuning_report.atlas_gap_plans(atlas_root=atlas_root, sample_limit=2) - _expect([plan.get("folder") for plan in gap_plans] == ["custom_pose", "ready"], "Atlas gap plans should follow unmapped folders") + _expect([plan.get("folder") for plan in gap_plans] == ["custom_pose"], "Atlas gap plans should follow unmapped folders") gap_by_folder = {plan.get("folder"): plan for plan in gap_plans} custom_gap = gap_by_folder["custom_pose"] _expect(custom_gap.get("suggested_variant_key") == "pov_custom_pose_candidate", "Atlas gap plan should suggest stable variant key") _expect(len(custom_gap.get("sample_images") or []) == 2, "Atlas gap plan should include deterministic sample images") _expect(len(custom_gap.get("control_images") or []) == 2, "Atlas gap plan should include deterministic control images") - ready_gap = gap_by_folder["ready"] _expect( - ready_gap.get("suggested_variant_key") == "pov_ejaculation_aftermath_open_thigh_candidate", + krea2_tuning_report._suggested_variant_key("ready") == "pov_ejaculation_aftermath_open_thigh_candidate", "Atlas gap plan should not treat ready as a neutral setup pose", ) atlas_markdown = krea2_tuning_report.markdown_report(atlas_root=atlas_root) _expect("Atlas Folder Coverage" in atlas_markdown, "Krea2 tuning report markdown lost atlas coverage section") _expect("custom_pose" in atlas_markdown, "Krea2 tuning report markdown lost unmapped atlas folder") _expect("pov_custom_pose_candidate" in atlas_markdown, "Krea2 tuning report markdown lost suggested gap key") - _expect("pov_ejaculation_aftermath_open_thigh_candidate" in atlas_markdown, "Krea2 tuning report markdown lost ready aftermath suggested key") markdown = krea2_tuning_report.markdown_report() _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_wand_foreground_tool_contact" in markdown, "Krea2 tuning report markdown lost wand candidate variant") + _expect("pov_ejaculation_aftermath_open_thigh_candidate" in markdown, "Krea2 tuning report markdown lost ready aftermath candidate variant") _expect("pov_spread_open_thigh_presentation" in markdown, "Krea2 tuning report markdown lost spread candidate variant") _expect("pov_blowjob_top_down_vertical_shaft" in markdown, "Krea2 tuning report markdown lost blowjob top-view candidate variant") _expect("pov_blowjob_side_profile_oral" in markdown, "Krea2 tuning report markdown lost blowjob side candidate variant")