29 KiB
Clothing Seed Axis Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Add a first-class clothing seed axis so workflows can keep content, pose, role, person, scene, expression, and composition identical while rerolling only clothing/outfit choices.
Architecture: Extend the shared seed policy first, then route clothing selections through axis_rng(..., "clothing", ...) in prompt and pair flows. Keep content responsible for content item/template choices, use outfit_seed as a clothing alias, and keep content_seed as a compatibility fallback only when no explicit clothing/outfit seed exists.
Tech Stack: Python 3, ComfyUI custom nodes, local smoke tests in tools/prompt_smoke.py, scene nodes in node_scene.py, seed policy in seed_config.py.
File Structure
- Modify
seed_config.py: add theclothingseed axis, aliases, reroll groups, lock config emission, and trace support through the existing generic functions. - Modify
prompt_builder.py: expose optionalclothing_seedandclothing_seed_modethrough the wrapper aroundseed_config.build_seed_config_json. - Modify
node_seed_resolution.py: expose clothing controls inSxCPSeedControland letSxCPSeedLockerpick up the new reroll choices fromseed_config. - Modify
node_tooltips.py: add help text for the new manual clothing seed controls and update the seed-locker tooltip. - Modify
builder_prompt_route.py: use a clothing RNG for prompt clothing mode selection. - Modify
pair_rows.py: use a clothing RNG for primary softcore outfit selection in scene pairs. - Modify
pair_cast.py: use a clothing RNG for secondary pair participant outfits. - Modify
node_scene.py: map scene layer seed axes toclothing,content_clothing, andclothing_pose. - Modify
tools/prompt_smoke.py: add red/green smoke coverage for seed vocabulary, UI inputs, routing, and scene-pair clothes-only rerolls.
Task 1: Shared Seed Vocabulary And UI Surface
Files:
-
Modify:
tools/prompt_smoke.py -
Modify:
seed_config.py -
Modify:
prompt_builder.py -
Modify:
node_seed_resolution.py -
Modify:
node_tooltips.py -
Step 1: Write the failing seed vocabulary smoke tests
In tools/prompt_smoke.py, inside smoke_seed_config_policy(), after the existing normalize_reroll_axis("content pose") assertion, add:
reroll_choices = pb.seed_reroll_axis_choices()
for expected_axis in ("clothing", "content_clothing", "clothing_pose"):
_expect(expected_axis in reroll_choices, f"seed reroll axis choices missing {expected_axis}")
_expect(pb.normalize_reroll_axis("clothing pose") == "clothing_pose", "reroll axis normalizer should accept clothing pose")
_expect(pb.normalize_reroll_axis("content clothing") == "content_clothing", "reroll axis normalizer should accept content clothing")
In the same function, replace:
parsed = pb._parse_seed_config({"item_seed": "44", "pose_seed": "55", "bad": "nope"})
_expect(parsed == {"item_seed": 44, "pose_seed": 55}, "seed parser should keep integer-like values only")
_expect(pb._configured_axis_seed(parsed, "content") == 44, "content axis should honor item_seed alias")
_expect(pb._configured_axis_seed(parsed, "role") == 55, "role axis should honor pose seed alias")
with:
parsed = pb._parse_seed_config({"item_seed": "44", "pose_seed": "55", "outfit_seed": "66", "bad": "nope"})
_expect(
parsed == {"item_seed": 44, "pose_seed": 55, "outfit_seed": 66},
"seed parser should keep integer-like values only",
)
_expect(pb._configured_axis_seed(parsed, "content") == 44, "content axis should honor item_seed alias")
_expect(pb._configured_axis_seed(parsed, "clothing") == 66, "clothing axis should honor outfit_seed alias")
_expect(
pb._configured_axis_seed({"content_seed": 77}, "clothing") == 77,
"clothing axis should keep content_seed as a legacy fallback",
)
_expect(
pb._configured_axis_seed({"content_seed": 77, "clothing_seed": 88}, "clothing") == 88,
"clothing_seed should override legacy content_seed fallback",
)
_expect(pb._configured_axis_seed(parsed, "role") == 55, "role axis should honor pose seed alias")
In the same function, after the existing locked = json.loads(...) block and its three assertions, add:
clothing_locked = json.loads(pb.build_seed_lock_config_json(base_seed=100, reroll_axis="clothing", reroll_seed=777))
_expect(clothing_locked["clothing_seed"] == 777, "clothing reroll should alter clothing seed")
_expect(clothing_locked["content_seed"] == 100, "clothing reroll should leave content locked")
_expect(clothing_locked["pose_seed"] == 100 and clothing_locked["role_seed"] == 100, "clothing reroll should leave pose and role locked")
content_clothing_locked = json.loads(
pb.build_seed_lock_config_json(base_seed=100, reroll_axis="content_clothing", reroll_seed=778)
)
_expect(content_clothing_locked["content_seed"] == 778, "content_clothing reroll should alter content seed")
_expect(content_clothing_locked["clothing_seed"] == 778, "content_clothing reroll should alter clothing seed")
_expect(content_clothing_locked["pose_seed"] == 100, "content_clothing reroll should leave pose locked")
clothing_pose_locked = json.loads(pb.build_seed_lock_config_json(base_seed=100, reroll_axis="clothing_pose", reroll_seed=779))
_expect(clothing_pose_locked["clothing_seed"] == 779, "clothing_pose reroll should alter clothing seed")
_expect(clothing_pose_locked["pose_seed"] == 779 and clothing_pose_locked["role_seed"] == 779, "clothing_pose reroll should alter pose and role seeds")
_expect(clothing_pose_locked["content_seed"] == 100, "clothing_pose reroll should leave content locked")
content_pose_locked = json.loads(pb.build_seed_lock_config_json(base_seed=100, reroll_axis="content_pose", reroll_seed=780))
_expect(content_pose_locked["clothing_seed"] == 100, "content_pose reroll should not alter clothing seed")
Change the axis_trace test block from:
axis_trace = seed_config.axis_seed_trace({"content_seed": 44}, 99, 3, axes=("content", "scene"))
to:
axis_trace = seed_config.axis_seed_trace({"content_seed": 44, "clothing_seed": 66}, 99, 3, axes=("content", "clothing", "scene"))
Then add this assertion after the existing content seed assertions:
_expect(axis_trace["clothing"]["source"] == "configured", "Seed axis trace lost clothing configured source")
_expect(axis_trace["clothing"]["seed"] == 66, "Seed axis trace lost configured clothing seed")
In tools/prompt_smoke.py, inside smoke_node_utility_registration(), after:
_expect("category_seed_mode" in seed_inputs, "Seed Control lost category seed mode input")
add:
_expect("clothing_seed_mode" in seed_inputs, "Seed Control lost clothing seed mode input")
_expect("clothing_seed" in seed_inputs, "Seed Control lost clothing seed input")
After the category_seed_tooltip assertion, add:
clothing_seed_tooltip = node_tooltips._tooltip_for_input("SxCPSeedControl", "clothing_seed_mode")
_expect("clothing/outfit" in clothing_seed_tooltip, "Node tooltip policy lost Seed Control clothing override")
After:
_expect(int(parsed_seed_control.get("content_seed", -1)) >= 0, "Seed Control random mode did not emit resolved seed")
add this assertion after updating the call in Step 3:
_expect(parsed_seed_control.get("clothing_seed") == 222, "Seed Control fixed clothing seed changed")
- Step 2: Run the focused smoke tests and verify they fail for the new behavior
Run:
python tools/prompt_smoke.py --case seed_config_policy --quiet
Expected: FAIL with seed reroll axis choices missing clothing.
Run:
python tools/prompt_smoke.py --case node_utility_registration --quiet
Expected: FAIL with Seed Control lost clothing seed mode input.
- Step 3: Implement the shared seed axis
In seed_config.py, update the top-level seed definitions:
SEED_AXIS_SALTS = {
"category": 31,
"subcategory": 37,
"content": 41,
"clothing": 41,
"person": 43,
"scene": 47,
"pose": 53,
"role": 57,
"expression": 59,
"composition": 61,
}
SEED_AXIS_ALIASES = {
"category": ("category_seed", "category"),
"subcategory": ("subcategory_seed", "subcategory"),
"content": ("content_seed", "item_seed", "sexual_pose_seed", "content"),
"clothing": ("clothing_seed", "outfit_seed", "wardrobe_seed", "content_seed", "content"),
"person": ("person_seed", "appearance_seed", "cast_seed", "person"),
"scene": ("scene_seed", "scene"),
"pose": ("pose_seed", "sexual_pose_seed", "pose"),
"role": ("role_seed", "role", "pose_seed", "sexual_pose_seed"),
"expression": ("expression_seed", "face_seed", "expression"),
"composition": ("composition_seed", "camera_seed", "composition"),
}
SEED_LOCK_AXES = (
"category",
"subcategory",
"content",
"clothing",
"person",
"scene",
"pose",
"role",
"expression",
"composition",
)
In the same file, update SEED_REROLL_GROUPS:
SEED_REROLL_GROUPS = {
"none": (),
"category": ("category",),
"subcategory": ("subcategory",),
"content": ("content",),
"clothing": ("clothing",),
"person": ("person",),
"scene": ("scene",),
"pose": ("pose", "role"),
"role": ("role",),
"expression": ("expression",),
"composition": ("composition",),
"content_pose": ("content", "pose", "role"),
"content_clothing": ("content", "clothing"),
"clothing_pose": ("clothing", "pose", "role"),
"scene_pose": ("scene", "pose", "role"),
}
Update normalize_reroll_axis() aliases:
aliases = {
"contentpose": "content_pose",
"contentclothing": "content_clothing",
"clothingpose": "clothing_pose",
"scenepose": "scene_pose",
}
Update build_seed_config_json() in seed_config.py by adding parameters between content_seed and person_seed:
clothing_seed: int = -1,
and between content_seed_mode and person_seed_mode:
clothing_seed_mode: str = "auto",
Then add the emitted field after content_seed:
"clothing_seed": axis_seed(clothing_seed, clothing_seed_mode),
In prompt_builder.py, update build_seed_config_json() with the same optional clothing_seed and clothing_seed_mode parameters, and pass them to seed_policy.build_seed_config_json(...):
clothing_seed=clothing_seed,
clothing_seed_mode=clothing_seed_mode,
In node_seed_resolution.py, update SxCPSeedControl.SEED_AXES:
SEED_AXES = (
"category",
"subcategory",
"content",
"clothing",
"person",
"scene",
"pose",
"role",
"expression",
"composition",
)
Update SxCPSeedControl.build(...) by adding clothing_seed_mode, clothing_seed after content_seed, and pass both into build_seed_config_json(...):
clothing_seed=clothing_seed,
clothing_seed_mode=clothing_seed_mode,
In tools/prompt_smoke.py, update the seed_control().build(...) call in smoke_node_utility_registration() by inserting these two arguments after the current content seed pair:
"fixed",
222,
In node_tooltips.py, update NODE_INPUT_TOOLTIPS["SxCPSeedControl"] with:
"clothing_seed_mode": "Controls clothing/outfit selection separately from content item selection.",
"clothing_seed": "Seed used when clothing_seed_mode is fixed or auto with a non-negative value.",
Update NODE_INPUT_TOOLTIPS["SxCPSeedLocker"]["reroll_axis"] to mention clothing:
"reroll_axis": "Choose the one axis to change while the rest stays locked. Use clothing for outfit-only rerolls, pose for sexual pose, scene for location, person for appearance.",
- Step 4: Run the focused smoke tests and verify they pass
Run:
python tools/prompt_smoke.py --case seed_config_policy --quiet
Expected: OK: smoke passed (1 cases).
Run:
python tools/prompt_smoke.py --case node_utility_registration --quiet
Expected: OK: smoke passed (1 cases).
- Step 5: Commit Task 1
Run:
git --git-dir=.git-real --work-tree=. add seed_config.py prompt_builder.py node_seed_resolution.py node_tooltips.py tools/prompt_smoke.py
git --git-dir=.git-real --work-tree=. commit -m "Add clothing seed axis vocabulary"
Task 2: Route Prompt And Pair Clothing Through The Clothing Axis
Files:
-
Modify:
tools/prompt_smoke.py -
Modify:
builder_prompt_route.py -
Modify:
pair_rows.py -
Modify:
pair_cast.py -
Step 1: Write the failing prompt-routing smoke test
In tools/prompt_smoke.py, inside smoke_seed_config_policy(), after the existing pose_changed assertion block, add:
clothes_base_seed = 52001
clothes_base_config = json.loads(pb.build_seed_lock_config_json(base_seed=clothes_base_seed))
def clothes_row(clothing_seed: int) -> dict[str, Any]:
seed_config_for_row = dict(clothes_base_config)
seed_config_for_row["clothing_seed"] = clothing_seed
return _prompt_row(
name=f"seed_config_policy_clothing_seed_{clothing_seed}",
category="woman",
subcategory="",
seed=clothes_base_seed,
seed_config=seed_config_for_row,
clothing="random",
minimal_clothing_ratio=0.5,
character_cast=_character_cast(),
location_config=_coworking_location_config(),
)
clothes_locked_a = clothes_row(53001)
clothes_changed = False
for clothing_seed in range(53002, 53100):
clothes_candidate = clothes_row(clothing_seed)
_expect(
clothes_candidate.get("scene_text") == clothes_locked_a.get("scene_text"),
"clothing reroll should keep scene text stable",
)
_expect(
clothes_candidate.get("pose") == clothes_locked_a.get("pose"),
"clothing reroll should keep pose stable",
)
_expect(
clothes_candidate.get("cast_descriptor_text") == clothes_locked_a.get("cast_descriptor_text"),
"clothing reroll should keep cast descriptors stable",
)
if clothes_candidate.get("clothing") != clothes_locked_a.get("clothing"):
clothes_changed = True
break
_expect(clothes_changed, "clothing_seed reroll should change prompt clothing mode")
- Step 2: Run the focused smoke test and verify it fails for the current routing
Run:
python tools/prompt_smoke.py --case seed_config_policy --quiet
Expected: FAIL with clothing_seed reroll should change prompt clothing mode.
- Step 3: Implement clothing RNG routing in normal prompt rows
In builder_prompt_route.py, inside build_prompt_result(...), replace:
content_rng = deps.axis_rng(parsed_seed_config, "content", seed, row_number)
pose_axis_rng = deps.axis_rng(parsed_seed_config, "pose", seed, row_number)
with:
content_rng = deps.axis_rng(parsed_seed_config, "content", seed, row_number)
clothing_rng = deps.axis_rng(parsed_seed_config, "clothing", seed, row_number)
pose_axis_rng = deps.axis_rng(parsed_seed_config, "pose", seed, row_number)
Then replace:
clothing = deps.pick_clothing_mode(content_rng, clothing, minimal_ratio)
with:
clothing = deps.pick_clothing_mode(clothing_rng, clothing, minimal_ratio)
- Step 4: Run the focused smoke test and verify it passes
Run:
python tools/prompt_smoke.py --case seed_config_policy --quiet
Expected: OK: smoke passed (1 cases).
- Step 5: Write the failing pair-routing smoke tests
In tools/prompt_smoke.py, inside smoke_node_scene_chain_registration(), find:
soft_content_seed_options = nodes["SxCPSceneLayerSeedOptions"]().build(
"softcore_branch",
"fixed",
6679,
"content",
"same_for_all_rows",
"replace_layer",
)[0]
Replace it with:
soft_clothing_seed_options = nodes["SxCPSceneLayerSeedOptions"]().build(
"softcore_branch",
"fixed",
6679,
"clothing",
"same_for_all_rows",
"replace_layer",
)[0]
In the same block, replace seed_options=soft_content_seed_options with:
seed_options=soft_clothing_seed_options,
Update the expected failure message from:
"Scene softcore branch content seed fixture no longer selects the expected outfit",
to:
"Scene softcore branch clothing seed fixture no longer selects the expected outfit",
After the existing soft_pose_pair assertions and before the choice-board block, add:
def _soft_clothing_pair(soft_clothing_seed: int) -> dict[str, Any]:
soft_clothing_seed_options = nodes["SxCPSceneLayerSeedOptions"]().build(
"softcore_branch",
"fixed",
soft_clothing_seed,
"clothing",
"same_for_all_rows",
"replace_layer",
)[0]
soft_scene_clothing, hard_scene_clothing, _summary, _metadata = nodes["SxCPSceneBranchPair"]().build(
scene,
"same_creator_same_room",
"hybrid",
branch_options=branch_options,
seed_options=soft_clothing_seed_options,
)
soft_scene_clothing = nodes["SxCPSoftcoreBranchOptions"]().build(
soft_scene_clothing,
"same_as_hardcore",
"lingerie_tease",
True,
0.45,
"from_camera_config",
"compact",
"",
branch_options=branch_options,
seed_options=soft_clothing_seed_options,
)[0]
hard_scene_clothing = nodes["SxCPHardcoreBranchOptions"]().build(
hard_scene_clothing,
"couple",
1,
1,
"hardcore",
True,
0.85,
"partially_removed",
"from_camera_config",
"compact",
"balanced",
"",
branch_options=branch_options,
)[0]
return json.loads(nodes["SxCPScenePairOutput"]().build(soft_scene_clothing, hard_scene_clothing)[7])
soft_clothing_pairs = [_soft_clothing_pair(seed) for seed in (6677, 6678, 6679, 6680)]
soft_clothing_items = {pair.get("softcore_row", {}).get("item") for pair in soft_clothing_pairs}
soft_clothing_poses = {pair.get("softcore_row", {}).get("pose") for pair in soft_clothing_pairs}
soft_clothing_hard_states = {pair.get("hardcore_clothing_state") for pair in soft_clothing_pairs}
_expect(len(soft_clothing_items) > 1, "Softcore branch clothing reroll should change softcore outfit")
_expect(len(soft_clothing_hard_states) > 1, "Softcore branch clothing reroll should change inherited hard clothing")
_expect(len(soft_clothing_poses) == 1, "Softcore branch clothing reroll should keep softcore pose stable")
for expected_seed, clothing_pair in zip((6677, 6678, 6679, 6680), soft_clothing_pairs):
soft_seed_config = clothing_pair.get("softcore_row", {}).get("seed_config") if isinstance(clothing_pair.get("softcore_row"), dict) else {}
hard_seed_config = clothing_pair.get("hardcore_row", {}).get("seed_config") if isinstance(clothing_pair.get("hardcore_row"), dict) else {}
_expect(
soft_seed_config.get("clothing_seed") == expected_seed,
"Softcore branch clothing seed did not reach softcore generator seed config",
)
_expect(
soft_seed_config.get("content_seed") != expected_seed,
"Softcore branch clothing seed should not overwrite content seed",
)
_expect(
hard_seed_config.get("clothing_seed") != expected_seed,
"Softcore branch clothing seed leaked into hardcore generator seed config",
)
In the content_pair assertions, add:
_expect(
content_hard_seed_config.get("clothing_seed") != 8899,
"Hardcore branch content_pose reroll should not reach hardcore clothing seed",
)
- Step 6: Run the scene-chain smoke test and verify it fails for the missing scene axis/routing
Run:
python tools/prompt_smoke.py --case node_scene_chain_registration --quiet
Expected: FAIL with either Scene softcore branch clothing seed fixture no longer selects the expected outfit or Softcore branch clothing reroll should change softcore outfit.
- Step 7: Implement clothing RNG routing in pair rows
In pair_rows.py, inside build_insta_pair_rows_result(...), replace:
soft_content_rng = axis_rng(soft_seed_config, "content", seed, row_number + 311)
soft_pose_rng = axis_rng(soft_seed_config, "pose", seed, row_number + 313)
with:
soft_content_rng = axis_rng(soft_seed_config, "content", seed, row_number + 311)
soft_clothing_rng = axis_rng(soft_seed_config, "clothing", seed, row_number + 311)
soft_pose_rng = axis_rng(soft_seed_config, "pose", seed, row_number + 313)
Then replace:
primary_softcore_outfit = slot_softcore_outfit(primary_slot, soft_content_rng)
soft_row["item"] = primary_softcore_outfit or softcore_outfit(soft_content_rng, softcore_level_key)
with:
primary_softcore_outfit = slot_softcore_outfit(primary_slot, soft_clothing_rng)
soft_row["item"] = primary_softcore_outfit or softcore_outfit(soft_clothing_rng, softcore_level_key)
In pair_cast.py, inside softcore_partner_styling(...), replace:
content_rng = axis_rng(seed_config, "content", seed, row_number + 421)
pose_rng = axis_rng(seed_config, "pose", seed, row_number + 421)
with:
content_rng = axis_rng(seed_config, "content", seed, row_number + 421)
clothing_rng = axis_rng(seed_config, "clothing", seed, row_number + 421)
pose_rng = axis_rng(seed_config, "pose", seed, row_number + 421)
Then replace both slot_softcore_outfit(..., content_rng) calls with slot_softcore_outfit(..., clothing_rng), and replace both outfit choose(content_rng, ...) calls with choose(clothing_rng, ...).
- Step 8: Run focused smoke tests and verify Task 2 behavior passes
Run:
python tools/prompt_smoke.py --case seed_config_policy --quiet
Expected: OK: smoke passed (1 cases).
Run:
python tools/prompt_smoke.py --case node_scene_chain_registration --quiet
Expected at this point: FAIL only on missing scene layer mapping, with a message involving the softcore branch clothing seed.
- Step 9: Commit Task 2
If seed_config_policy passes and node_scene_chain_registration now fails only because scene layer axes do not apply clothing, commit the prompt and pair routing work:
git --git-dir=.git-real --work-tree=. add builder_prompt_route.py pair_rows.py pair_cast.py tools/prompt_smoke.py
git --git-dir=.git-real --work-tree=. commit -m "Route clothing choices through clothing seed"
Task 3: Scene Layer Clothing Axis Mapping
Files:
-
Modify:
node_scene.py -
Modify:
tools/prompt_smoke.py -
Step 1: Write the failing scene-axis smoke assertions
In tools/prompt_smoke.py, inside smoke_node_scene_chain_registration(), replace:
wardrobe_seed_options = nodes["SxCPSceneLayerSeedOptions"]().build("wardrobe", "fixed", 9981, "content", "same_for_all_rows", "replace_layer")[0]
with:
wardrobe_seed_options = nodes["SxCPSceneLayerSeedOptions"]().build("wardrobe", "fixed", 9981, "clothing", "same_for_all_rows", "replace_layer")[0]
After:
_expect(json.loads(scene).get("seed_trace", {}).get("wardrobe", {}).get("seed") == 9981, "Scene Wardrobe seed options did not write seed trace")
add:
_expect(
json.loads(scene).get("seed_trace", {}).get("wardrobe", {}).get("axes") == ["clothing"],
"Scene Wardrobe seed options should target clothing axis",
)
- Step 2: Run scene-chain smoke and verify it fails for missing scene layer clothing mapping
Run:
python tools/prompt_smoke.py --case node_scene_chain_registration --quiet
Expected: FAIL with a message involving wardrobe or softcore branch clothing axis mapping.
- Step 3: Implement scene layer clothing mappings
In node_scene.py, update SCENE_LAYER_SEED_AXES:
SCENE_LAYER_SEED_AXES = {
"cast": ("category",),
"character": ("person",),
"wardrobe": ("clothing",),
"location": ("scene",),
"set_dressing": ("scene",),
"blocking": ("pose",),
"action": ("pose", "role"),
"performance": ("expression",),
"camera": ("composition",),
"composition": ("composition",),
"lighting": ("composition",),
"softcore_branch": ("clothing", "pose", "role"),
"hardcore_branch": ("pose", "role"),
}
In the same file, update SCENE_REROLL_GROUPS:
SCENE_REROLL_GROUPS = {
"none": (),
"category": ("category",),
"subcategory": ("subcategory",),
"content": ("content",),
"clothing": ("clothing",),
"person": ("person",),
"scene": ("scene",),
"pose": ("pose", "role"),
"role": ("role",),
"expression": ("expression",),
"composition": ("composition",),
"content_pose": ("content", "pose", "role"),
"content_clothing": ("content", "clothing"),
"clothing_pose": ("clothing", "pose", "role"),
"scene_pose": ("scene", "pose", "role"),
}
- Step 4: Run focused smoke tests and verify they pass
Run:
python tools/prompt_smoke.py --case node_scene_chain_registration --quiet
Expected: OK: smoke passed (1 cases).
Run:
python tools/prompt_smoke.py --case seed_config_policy --quiet
Expected: OK: smoke passed (1 cases).
Run:
python tools/prompt_smoke.py --case node_utility_registration --quiet
Expected: OK: smoke passed (1 cases).
- Step 5: Commit Task 3
Run:
git --git-dir=.git-real --work-tree=. add node_scene.py tools/prompt_smoke.py
git --git-dir=.git-real --work-tree=. commit -m "Map scene clothing seeds to clothing axis"
Task 4: Final Verification And Push
Files:
-
No production file edits expected.
-
Verify all files touched by Tasks 1-3.
-
Step 1: Run compilation checks
Run:
python -m py_compile seed_config.py prompt_builder.py node_seed_resolution.py node_tooltips.py builder_prompt_route.py pair_rows.py pair_cast.py node_scene.py tools/prompt_smoke.py
Expected: exit code 0.
- Step 2: Run focused smoke tests
Run:
python tools/prompt_smoke.py --case seed_config_policy --quiet
python tools/prompt_smoke.py --case node_utility_registration --quiet
python tools/prompt_smoke.py --case node_scene_chain_registration --quiet
Expected for each command: OK: smoke passed (1 cases).
- Step 3: Run the full smoke suite
Run:
python tools/prompt_smoke.py --quiet
Expected: all cases pass except the known unrelated krea2_prompt_guide_policy failure if it is still present. If any new failure mentions seed policy, scene layer seed, clothing state, prompt routing, pair rows, or node utility registration, fix it before committing or pushing.
- Step 4: Check git status
Run:
git --git-dir=.git-real --work-tree=. status --short --branch
git --git-dir=.git-real --work-tree=. log -5 --oneline
Expected: branch contains the three implementation commits from this plan and no unstaged edits.
- Step 5: Push the branch
Run:
git --git-dir=.git-real --work-tree=. push
Expected: push succeeds to origin/hardcore-interaction-expansion.
Self-Review
- Spec coverage: Task 1 covers seed vocabulary, aliases, seed-lock config, seed trace, seed-control UI, and tooltips. Task 2 covers normal prompt clothing mode routing, primary softcore outfit routing, partner outfit routing, and legacy content fallback. Task 3 covers scene layer mappings, wardrobe axis behavior, softcore branch clothing-only rerolls, hard-branch continuity, and
content_posenot touching clothing. Task 4 covers compilation, focused smoke tests, full smoke, status, and push. - Scope check: this plan avoids rewriting category data and keeps custom content item selection on the
contentaxis, matching the spec's out-of-scope section. - Type consistency: all new seed keys use
clothing_seed; all new axis names useclothing,content_clothing, andclothing_pose; compatibility aliases useoutfit_seed,wardrobe_seed, and fallbackcontent_seed.