Add Krea2 wand atlas candidate
This commit is contained in:
@@ -217,6 +217,44 @@
|
||||
"notes": "Atlas shows a repeated open-thigh manual-contact POV layout; needs fixed-seed Krea2 tests before promotion to proven."
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "pov_wand_foreground_tool_contact",
|
||||
"family": "wand",
|
||||
"status": "candidate",
|
||||
"atlas_folders": ["wand"],
|
||||
"action_family": "toy",
|
||||
"position_keys": ["wand", "toy_contact", "open_thighs"],
|
||||
"canonical_geometry": "First-person toy-contact view: the woman reclines or sits back with thighs spread toward the camera, face and torso visible behind the open-leg frame, and the viewer hand holds a wand-style toy from the foreground with the rounded head pressed to the central contact point.",
|
||||
"prompt_cues": [
|
||||
"POV wand toy position",
|
||||
"woman reclines with thighs spread wide toward the camera",
|
||||
"viewer hand holds a wand-style toy from the foreground",
|
||||
"rounded toy head is pressed to the central contact point between her open thighs",
|
||||
"her face and torso remain visible behind the open-leg frame",
|
||||
"thighs and knees form the main frame around the foreground tool"
|
||||
],
|
||||
"avoid_cues": [
|
||||
"generic toy nearby without contact",
|
||||
"the woman holding the toy when the foreground viewer hand is intended",
|
||||
"mouth, foot, or penetration action competing with the toy contact",
|
||||
"closed legs hiding the contact point",
|
||||
"toy floating without a visible hand or handle"
|
||||
],
|
||||
"reference_images": [
|
||||
"wand/106_wand_.png",
|
||||
"wand/107_wand_.png",
|
||||
"wand/108_wand_.png"
|
||||
],
|
||||
"generator_hook": {
|
||||
"module": "krea_pov_actions.py",
|
||||
"route_terms": ["wand", "toy", "vibrator"]
|
||||
},
|
||||
"evidence": {
|
||||
"fixed_seed_tests": [],
|
||||
"guide_section": "",
|
||||
"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_spread_open_thigh_presentation",
|
||||
"family": "spread",
|
||||
|
||||
@@ -28,6 +28,11 @@ 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.
|
||||
|
||||
## Inventory
|
||||
|
||||
| Family | Pose images | Control images | First sample |
|
||||
@@ -118,6 +123,16 @@ 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.
|
||||
|
||||
### Wand / Toy Contact
|
||||
|
||||
The wand folder repeats a close first-person tool-contact layout: the woman is
|
||||
reclined or sitting back with thighs spread toward camera, face and torso visible
|
||||
behind the open-leg frame, and the viewer hand holding a wand-style toy from the
|
||||
foreground with the rounded head pressed to the central contact point. Treat
|
||||
`pov_wand_foreground_tool_contact` as a candidate until it has fixed-seed Krea2
|
||||
evidence. Keep the visible hand/handle in the wording; otherwise Krea2 may float
|
||||
the toy or transfer ownership to the visible partner.
|
||||
|
||||
### Spread / Open-Thigh Presentation
|
||||
|
||||
The spread folder is a setup/presentation family rather than a required contact
|
||||
|
||||
@@ -144,6 +144,8 @@ def atlas_coverage_summary(atlas_root: str | Path | None = None) -> dict[str, An
|
||||
|
||||
|
||||
def _suggested_variant_key(folder_name: str) -> str:
|
||||
if folder_name.lower() == "ready":
|
||||
return "pov_ejaculation_aftermath_open_thigh_candidate"
|
||||
normalized = "".join(char if char.isalnum() else "_" for char in folder_name.lower()).strip("_")
|
||||
while "__" in normalized:
|
||||
normalized = normalized.replace("__", "_")
|
||||
|
||||
+42
-6
@@ -6810,6 +6810,11 @@ def smoke_krea2_pose_variant_catalog_policy() -> None:
|
||||
manual == ["pov_fingering_reclined_open_thighs"],
|
||||
f"Krea2 pose-variant manual filtering changed unexpectedly: {manual}",
|
||||
)
|
||||
toy = krea2_pose_variant_catalog.variant_keys(action_family="toy")
|
||||
_expect(
|
||||
toy == ["pov_wand_foreground_tool_contact"],
|
||||
f"Krea2 pose-variant toy filtering changed unexpectedly: {toy}",
|
||||
)
|
||||
interaction = krea2_pose_variant_catalog.variant_keys(action_family="interaction")
|
||||
_expect(
|
||||
interaction == ["pov_spread_open_thigh_presentation"],
|
||||
@@ -6845,6 +6850,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",
|
||||
)
|
||||
wand = krea2_pose_variant_catalog.get_variant("pov_wand_foreground_tool_contact")
|
||||
_expect(wand.get("status") == "candidate", "Wand variant should remain a candidate until fixed-seed evidence exists")
|
||||
_expect(
|
||||
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",
|
||||
)
|
||||
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(
|
||||
@@ -6974,6 +6985,9 @@ 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")
|
||||
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")
|
||||
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")
|
||||
@@ -7009,12 +7023,13 @@ 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") == 14, "Krea2 tuning report candidate count changed")
|
||||
_expect(summary.get("status_counts", {}).get("candidate") == 15, "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_spread_open_thigh_presentation",
|
||||
"pov_blowjob_top_down_vertical_shaft",
|
||||
"pov_blowjob_side_profile_oral",
|
||||
@@ -7036,6 +7051,7 @@ def smoke_krea2_tuning_report_policy() -> None:
|
||||
"pov_ballsucking_low_head",
|
||||
"pov_footjob_frontal_sole_stroke",
|
||||
"pov_fingering_reclined_open_thighs",
|
||||
"pov_wand_foreground_tool_contact",
|
||||
"pov_spread_open_thigh_presentation",
|
||||
"pov_blowjob_top_down_vertical_shaft",
|
||||
"pov_blowjob_side_profile_oral",
|
||||
@@ -7082,6 +7098,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",
|
||||
)
|
||||
wand_plan = plan_by_key["pov_wand_foreground_tool_contact"]
|
||||
_expect(
|
||||
"viewer hand holds a wand-style toy from the foreground" in " ".join(wand_plan.get("prompt_cues") or []),
|
||||
"Wand test plan lost foreground tool-hold cue",
|
||||
)
|
||||
_expect(
|
||||
any(str(path).endswith("wand/106_wand_.png") for path in wand_plan.get("reference_paths") or []),
|
||||
"Wand 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 []),
|
||||
@@ -7183,38 +7208,49 @@ def smoke_krea2_tuning_report_policy() -> None:
|
||||
)
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
atlas_root = Path(tmpdir)
|
||||
for folder in ("doggy", "doggy_control", "custom_pose", "custom_pose_control", "bg", "woman", "doggy_bg"):
|
||||
for folder in ("doggy", "doggy_control", "custom_pose", "custom_pose_control", "ready", "ready_control", "bg", "woman", "doggy_bg"):
|
||||
folder_path = atlas_root / folder
|
||||
folder_path.mkdir()
|
||||
(folder_path / f"{folder}_sample.png").write_bytes(b"")
|
||||
(atlas_root / "custom_pose" / "custom_pose_b.png").write_bytes(b"")
|
||||
(atlas_root / "custom_pose_control" / "custom_pose_control_b.png").write_bytes(b"")
|
||||
(atlas_root / "ready" / "ready_b.png").write_bytes(b"")
|
||||
(atlas_root / "ready_control" / "ready_control_b.png").write_bytes(b"")
|
||||
atlas_rows = krea2_tuning_report.atlas_folder_rows(atlas_root=atlas_root)
|
||||
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("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") == 2, "Atlas report should count only pose folders")
|
||||
_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"], "Atlas report should identify unmapped pose folders")
|
||||
_expect(atlas_summary.get("unmapped_folders") == ["custom_pose", "ready"], "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"], "Atlas gap plans should follow unmapped folders")
|
||||
custom_gap = gap_plans[0]
|
||||
_expect([plan.get("folder") for plan in gap_plans] == ["custom_pose", "ready"], "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",
|
||||
"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_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")
|
||||
|
||||
Reference in New Issue
Block a user