# Development Plan Working document for Naked Desire implementation. Tracks current state vs. the GDD (README.md) and the phased roadmap. Update this file as state changes — code is the source of truth, this file is the navigation chart. When the GDD changes, update README.md first, then revisit this plan. When this plan changes, keep phase exit criteria concrete so we know when to move on. --- ## 1. Implementation status snapshot State of the C++ module as of the latest pass. File references use `Source/NakedDesire/...` paths. ### 1.1 Implemented - **Item identity scaffold (GDD §6.1)** — `Items/ItemInstance.h` defines `UItemInstance` as an abstract `UObject` with a stable `FGuid InstanceID`, auto-assigned in `PostInitProperties` and refreshed in `PostDuplicate`. `Clothing/ClothingItemInstance.h` inherits from it and holds per-instance `Condition`, a pointer to the immutable `UClothingItem` definition, and a `StoredItems` array for container slots. - **Definition / instance split (GDD §6.1, §17.4)** — `Clothing/ClothingItem.h` is the immutable `UPrimaryDataAsset` definition with GDD-aligned fields: `Coverage`, `IsUnderwear`, `CanExpose`, `IsRestrictive`, `ContainerSlots` (typed S/M/L via `EGarmentContainerSlotType` + `FGarmentContainerSlot`), `ProgressionPath`, plus rendering data (`SkeletalMesh`, `Materials`, `StaticMesh`). - **Progression path enum (GDD §5)** — `Progression/ProgressionPath.h` defines `EProgressionPath { None, Slut, Exhibitionist, Slave }`. Used on `UClothingItem::ProgressionPath`. - **Body-part enum (GDD §6.3)** — `Clothing/BodyPart.h` defines `EBodyPart { None, Boobs, Ass, Genitals }`. Used on `UClothingItem::CanExpose`. - **Save scaffolding (GDD §16)** — `SaveGame/SaveSubsystem.h/.cpp` (`UGameInstanceSubsystem`), `SaveGame/ItemSaveRecord.h` (generic `{ InstanceId, Definition, Condition, ParentId }`). `Global/Constants.h` now uses `DefaultSaveSlotName` instead of a single `SLOT_NAME` macro. - **Observation-driven embarrassment (GDD §7.1)** — `NPC/NPCAIController.cpp:56-69` listens to `OnTargetPerceptionUpdated` and forwards bSensed transitions to `Stats/StatsManager::SetObserved`. `Stats/StatsManager::TickComponent` (`StatsManager.cpp:23-38`) now gates gain vs. decay on `ObserverCount` instead of unconditional decay. Foundation for Phase 4. - **Modular character w/ per-slot meshes** — `Player/NakedDesireCharacter.cpp:40-67` creates 14 skeletal mesh components, one per `EClothingSlotType`. Aligns with GDD §17.6. - **Equip / unequip / drop event** — `Clothing/ClothingManager.cpp:88-163` (slot-based, broadcasts `OnClothingEquip / Unequip / Dropped` with `UClothingItemInstance*`). - **Censorship toggle** — compliance feature on `NakedDesireCharacter` (`BoobL/R`, `Front/BackBottom` static meshes), driven by `UNakedDesireUserSettings`. - **AI sight + behavior tree** — `NPC/NPCAIController.cpp` runs a BT with `Player` / `TargetLocation` / `SpawnLocation` blackboard keys. `NPC/NPCSpawner.cpp` proximity-gated spawn with day / night caps. - **Mission framework** — `Mission` → `MissionGoal` → `GoalRestriction` composition (`MissionBuilder/`). Two goals (`FlashGoal`, `MinTimeGoal`), three restrictions (`EquipClothing`, `ExposeBodyPart`, `Location`). Iterate-and-mutate bug in `MissionsManager::RefreshDailyMissions` resolved (`MissionsManager.cpp:53-68`). - **Daily-mission OOB guarded** — `NakedDesireGameMode::RefreshDailyMissions` now clamps `DaysPassed` to the authored array bounds (`NakedDesireGameMode.cpp:70-71`). Still a hand-authored list (see §1.3). - **Location triggers** — `Locations/LocationTrigger`, `Locations/LocationData` via gameplay tags (GDD §10.4 area foundation). - **Movement** — `EnhancedInput`, walk / run / crouch (`NakedDesireCharacter.cpp:115-127`), stamina-gated run (`Tick` lines 91-113). - **Wardrobe interactable** — `Interactables/Wardrobe.h` holds `TArray> ClothingItems`; `NakedDesireGameMode::BuyItem` charges money and pushes into the wardrobe. ### 1.2 Partially implemented (deviates from GDD) - **Save subsystem (GDD §16)** — scaffolded but **not actually wired through gameplay**. `USaveSubsystem::SaveGame` (`SaveSubsystem.cpp:10-13`) delegates to `UGlobalSaveGameData::SaveGame`, which creates a *fresh empty* `UGlobalSaveGameData` (`GlobalSaveGameData.cpp:45-53`) and writes it — i.e., it does not capture the live player / wardrobe / world state at all. `USaveSubsystem::LoadGame` calls the static loader but discards the result without applying it (`SaveSubsystem.cpp:5-8`). `ClothingManager::HydrateClothing` (`ClothingManager.cpp:66-73`) is an empty stub with the previous logic commented out. Exit criterion of Phase 1 (round-trip an item with modified condition) is not met yet. - **Item identity → world (§6.1)** — `UItemInstance` GUIDs exist, but no item has been promoted to a world `AActor`. `ClothingManager::DropClothing` (`ClothingManager.cpp:156-163`) still only broadcasts `OnClothingDropped` — no spawn, no parent reassignment in any registry. - **Attributes (§7)** — `StatsManager` covers Embarrassment, Energy, Stamina with observation-driven gain now correctly tied to NPC perception. Missing: Lust, Pulse (new, §7.5), Recognition, Reputation, Followers, Wanted. Coverage weighting in the gain formula is stubbed at `0.0f` with a TODO marker (`StatsManager.cpp:30-32`). - **Coverage (§6.3.2)** — `UClothingItem::Coverage` and `IsUnderwear` exist on the definition, but `ClothingManager::IsBodyTypeExposed` (`ClothingManager.cpp:14-25`) is still binary. No `GetEffectiveCoverage(EBodyPart)` function, no underwear-halving, no sum-of-garments math. - **Body-part enums — duplicated** — both `Player/PrivateBodyPartType.h` (`EPrivateBodyPartType { FrontBottom, BackBottom, FrontTop }`) and `Clothing/BodyPart.h` (`EBodyPart { Boobs, Ass, Genitals }`) exist. `UClothingItem::CoveredBodyParts` uses the **old** enum; `UClothingItem::CanExpose` uses the **new** one. Half-migrated. - **Mission system** — composable goals work but lacks the typed objective steps from §13.4 (`BeFullyNaked`, `BeFullyNakedNearNPCs`, `WalkNakedDistance`, `MoveDistanceFromClothing`, `BeObservedByNPCType`, `TakePhotoAtLocation`, `DeliverItemTo`). Missions still hand-authored in `MissionsConfig::DailyMissions` keyed by day index — no procedural generation. - **Day / night** — `NPCSpawner.cpp:38-41` reads `GetCurrentTime().Hours` and gates spawn cap, but does not affect embarrassment gain, NPC type weighting, or police spawning (see §1.3). ### 1.3 Missing - **Session system (GDD §4)** — no `USessionManager`, no session start / end events, no `USessionLossResolver`. Game-over on embarrassment is a single `EndGameEmbarrassed` BP event in `NakedDesireGameMode`; none of §4.4's behavior (energy-zero cutscene to home, bag-placed-in-world loss, sleep-deterministic clothing loss) is implemented. - **Three progression paths runtime (§5)** — enum exists; no path XP, no per-path level, no path-gated unlocks at runtime, no level-up flow. - **Phone (§9)** — entire system absent: camera, gallery, livestream, bank, Feetex, maps, health tracker. - **Forum (§13)** — no `UCommissionTemplate`, no procedural generation, no weekly missions distinct from daily, no profile / followers, no posting photos. - **Photo & livestream** — absent. - **NPC types (§10.2)** — only one generic `ANPC` class. No Walker / Stalker / Blogger / Snitch / Harasser, no Police, no Wanted-poster mechanic. - **Calendar, rent, sleep (§2.4, §15.2)** — `DaysPassed` increments in `NakedDesireGameMode::OnHourChanged(4)`, but no week, no rent, no eviction, no sleep action, no apartment bed interaction. - **Item-world AActor (§6.1)** — no `AItemActor` / `AClothingPickup` base. - **Bag inventory (§6.4)** — absent. - **Theft (§6.3.4)** — new chance-based model (per-tick `P_theft` after grace period) not implemented. No theft timer / probability code at all. - **Rip & tear (§6.3.5)** — absent. `UClothingItemInstance::Condition` is read-only in code; no decrement source. - **Expose action (§6.3.6)** — `CanExpose` data exists on the definition; runtime action absent. - **Restrictive clothing (§6.3.7 / §10.4.1)** — `IsRestrictive` field exists; no enforcement of hand-action locks, no Key-based unlock flow. - **Adult shop, gym, beauty salon, cafe, convenience store** — none. - **Food / consumables (§6.7)** — absent. - **Recognition, wanted state, news (§7.6–§7.7, §11.1)** — absent. - **Underwear selling (§15.1)** — absent. - **Endless mode flag (§3.3)** — absent. - **Pulse attribute (§7.5)** — absent (new in the updated GDD). - **GAS adoption (§17.2)** — `StatsManager` is still a bespoke `UActorComponent`; no `UAttributeSet`, no `GameplayEffect`-driven modifiers. ### 1.4 Conflicts to resolve - **`SaveGame` UPROPERTY typo** — `GlobalSaveGameData.h:35` declares `UPROPERTY(SaceGame)` instead of `SaveGame` on `DaysPassed`. The field will not serialize. (Likely also blocks Unreal Header Tool warnings; needs a clean rebuild after the fix.) - **`EClothingSlotType`** (`Clothing/ClothingSlotType.h`) still includes `Nipples`, `Anal`, `Vagina` as equipment slots — those are body parts per the GDD. Slot list also lacks `Outerwear`, `Accessory`, `Restraint` (GDD §6.3 / §21 Q1). The character builds 14 skeletal mesh components against these values (`NakedDesireCharacter.cpp:40-67`), so the cleanup needs a matching content / BP pass. - **Two competing body-part enums** — `EPrivateBodyPartType` vs. `EBodyPart`. `ClothingItem::CoveredBodyParts` uses one, `ClothingItem::CanExpose` uses the other. The censorship / observation code paths in `NakedDesireCharacter` and `ClothingManager` are still on `EPrivateBodyPartType`. Pick one (recommend `EBodyPart`) and migrate. - **`USaveSubsystem::SaveGame` writes an empty save** — it does not pull state from the live world before writing (`SaveSubsystem.cpp:10-13`, `GlobalSaveGameData.cpp:45-53`). Any "save" call at present destroys progress rather than persisting it. Highest-priority correctness bug. - **`USaveSubsystem::LoadGame` ignores the loaded object** — the static returns a populated `UGlobalSaveGameData`, the subsystem stores nothing and applies nothing. - **`UClothingList`** forward-declared in `GlobalSaveGameData.h:11` and `Wardrobe` / save records no longer use it. Dead reference; remove. - **`Money` representation** — `ANakedDesireCharacter::Money` is `int` (`NakedDesireCharacter.h:132`), `UGlobalSaveGameData::Money` is `float` (`GlobalSaveGameData.h:27`). The earlier "Resolve Money duplication" commit consolidated the field locations but the type mismatch and the routing-through-save story are unfinished — verify which is authoritative before adding economy systems on top. - **`STARTING_MONEY`** macro added to `Constants.h:8` but no code references it. Either wire it into the player / save init, or remove. - **`ClothingItemInstance` has no public constructor / factory** — `ClothingItem` pointer is `protected` with no `Init(UClothingItem*)`. Wardrobe / BuyItem flows currently `EditAnywhere Instanced` populate the array at design-time, which works for the existing test level but won't support runtime purchase or save-driven hydration. - **`StatsManager::TickComponent` energy drain** — drains energy at a flat `0.9f` per tick (`StatsManager.cpp:26`) regardless of activity, indoor / outdoor, or modifiers. GDD §7.3 specifies per-activity modifiers (`energyDrainRunModifier`, etc.). - **`NPCSpawner` day window** — uses `Hours >= 9 && < 21` for "day" (`NPCSpawner.cpp:40`), GDD §10.1 says the day phase is `08:00 → 20:00`. Off-by-one and an hour offset. - **GDD shifts not yet reflected in code:** - Phase 4-era loss resolver work must avoid stripping equipped clothing — GDD §4.4 now says equipped items are **never** force-removed on loss. - Energy = 0 must trigger a "cutscene to apartment + sleep" flow, not a teleport (GDD §4.4). - Theft is now a chance-based model with grace periods (`T_grace`, `T_grace_bag`) and flat per-tick `P_theft`, not a ramping curve (GDD §6.3.4). - Sleep is the deterministic side of clothing loss — guaranteed loss of every item left outside the apartment (GDD §4.4). - No Helper NPC, no adult-shop unlock; restraint removal is Key + timed unlock only (GDD §10.4.1). - Masturbation gating is Slut-path only (GDD §5.1 / §7.2 / §14.1). - Police spawn day **and** night while `wanted` (GDD §7.7 / §10.3) — current spawner has no police path at all, but record this when it's built. --- ## 2. Architectural premise The item-identity rule (§6.1) and the save contract (§16.3) are still load-bearing. With the definition / instance split in place, the next bottleneck is **wiring serialization through gameplay**: condition mutation, world drops, container parent links, hydration on load. Until that round-trip works, content on top of the current system has no durable home. The session-system + loss resolver (Phase 3) is the second pin. Several GDD shifts (equipped-never-dropped, energy-zero cutscene, sleep-deterministic clothing loss) move complexity from §4.4 prose into a single deterministic resolver. Build it once, well. GAS adoption (§17.2) remains deferred until Phase 4. Adding new attributes to the bespoke `StatsManager` in the meantime is fine — keep them additive and easy to migrate. --- ## 3. Phased roadmap Phase estimates are rough and assume one engineer. Adjust as we go. ### Phase 1 — Finish item identity + save round-trip (1 week) Most of the structural work is done. What remains is connecting the pieces so an item modified at runtime survives a save / load cycle. - Fix the `SaceGame` UPROPERTY typo on `DaysPassed` (`GlobalSaveGameData.h:35`). - Add `UClothingItemInstance::Init(UClothingItem* Definition)` (or a static factory) so instances can be constructed at runtime — not just `Instanced` at design-time. - Make `USaveSubsystem::SaveGame` actually pull live state into a `UGlobalSaveGameData`: player money, equipped items, wardrobe items, calendar, observation-attribute snapshot. Cover `WardrobeItems` and `EquippedItems` arrays via `FItemSaveRecord` populated from current `UClothingItemInstance`s (Guid, definition soft pointer, condition, parent guid). - Make `USaveSubsystem::LoadGame` actually apply the loaded data: rebuild `UClothingItemInstance`s from records, push into the wardrobe array and `ClothingManager` slots. Replace the commented-out `ClothingManager::HydrateClothing` with the real hydration. - Unify `EPrivateBodyPartType` and `EBodyPart` (recommend keeping `EBodyPart`, retiring the legacy enum). Update `ClothingItem::CoveredBodyParts`, `ClothingManager::IsBodyTypeExposed`, censorship checks in `NakedDesireCharacter`, and the BT / observation paths. - Slot vocabulary pass: drop `Nipples` / `Anal` / `Vagina` from `EClothingSlotType`, add `Outerwear` / `Accessory` / `Restraint`. Update the character's mesh component layout and any BP references in lockstep. - Money: pick one authoritative location (`UGlobalSaveGameData` is the natural choice; `ANakedDesireCharacter::Money` becomes a cached read-through). Apply `STARTING_MONEY` at new-save creation. Convert character field to match save type. - Remove the dead `UClothingList` forward declarations. **Exit criteria:** 1. Item dropped at runtime, condition modified, save → quit → load reproduces the same `FGuid`, condition value, and slot / wardrobe membership. 2. `EBodyPart` is the only body-part enum in use. 3. Slot list matches GDD §6.3 / §21 Q1 decision. 4. A new game starts with `STARTING_MONEY` and rent / purchase flows debit the canonical money field. ### Phase 2 — World item actors + drop / pickup (1 week) - `AItemActor` base wrapping a `UItemInstance*` (in `Items/`). Spawn transform, owning instance pointer, SaveGame-tagged. - `AClothingPickup : AItemActor` with a visual representation (use `UClothingItem::StaticMesh` when set, fallback to skeletal mesh impostor). - Hook `ClothingManager::DropClothing` to spawn `AClothingPickup` at the player location with the actual instance reference — *not* a template copy. Reparent the instance from "equipped slot" to "world". - Pickup interaction via existing `UInteractionManager` + `IInteractionTarget`. Pickup re-parents the instance into wardrobe or directly into the matching slot. - `USaveSubsystem` extension: serialize `AClothingPickup`s as `FItemSaveRecord`s with world transform. **Exit criteria:** unequip → world pickup actor appears → save / reload → pickup is still there at the same transform with the same instance ID → pick up restores the same instance to the slot. ### Phase 3 — Session system + loss resolver (1 week) - `USessionManager` (subsystem on `UNakedDesireGameInstance` or a `UWorldSubsystem`). Apartment `ALocationTrigger` flag drives session start / end. Emits `OnSessionStart` / `OnSessionEnd` with cause. - `USessionLossResolver` — single class, one method `ResolveLoss(ESessionLossCause Cause)`. Implements GDD §4.4: - Equipped clothing **stays** equipped (do not strip). - Bag placed in world: mark its world record for deletion. - Loose clothing on ground: leave as-is (theft chance has been running through Phase ?-7 logic; sleep step is what finalizes). - Energy=0 path: trigger a cutscene → apartment → sleep cycle → guaranteed loss of every world clothing outside the apartment safe zone. - Embarrassment-max / police-capture path: fade to apartment, no sleep cycle, no forced clothing loss. - Police-capture: deduct money penalty, queue skipped days for the unpaid remainder, clear `wanted`. - Wire `StatsManager::IncreaseEmbarrassment` max-hit and energy-zero into `USessionLossResolver`. Replace `EndGameEmbarrassed` BP-event with the C++ path. - Add a debug overlay that shows the current loss state and what would be lost if a given cause fired. **Exit criteria:** all four code paths (safe end, embarrassment max, energy zero, police capture) produce the §4.4 outcomes deterministically. Inventory state after each loss matches the §6.6 summary table 1:1. ### Phase 4 — Attributes refactor (1–2 weeks) - Decision: GAS vs. extended `StatsManager`. Recommend GAS — the embarrassment formula now has Pulse, Recognition, Coverage, Day/Night, and per-NPC-type weights as modifiers (§7.1), which is exactly what `UGameplayEffect` is shaped for. - Add Lust (§7.2), Pulse (§7.5, **new**), Recognition (§7.6), Wanted (§7.7), Reputation (§7.8), Followers (§7.9). Money should be the only attribute that also lives in the save schema directly (since it has non-attribute side effects). - Implement `GetEffectiveCoverage(EBodyPart)` on `ClothingManager` per §6.3.2 (sum of garments covering the part, underwear halved, clamped to 1.0). Replace the `CoverageWeight = 0.0f` stub in `StatsManager::TickComponent`. - Lust → masturbate action (Slut-path gated, §7.2). Block the action in BP / quick-action when the player's Slut path level is 0. - Pulse simulation: rises with running, masturbation, exposure events; decays toward baseline at rest. Modifies embarrassment / lust gain (§7.5). - Recognition rise from Blogger photo events; face-cover bypass; reduce via news-site reporting (§11.1). - Debug overlay extension: live values + active modifier sources for every attribute. **Exit criteria:** 1. Observed-while-exposed embarrassment gain reads coverage and modifiers from the attribute system (no more `0.0f` stub). 2. Lust + Pulse simulate correctly and visibly influence embarrassment in a playtest scenario. 3. Recognition increases after a (mocked) photo event and decreases after a news-report action. ### Phase 5 — Time + calendar + rent + sleep (3–4 days) - `UTimeOfDaySubsystem` replacing the BP-implementable time on `NakedDesireGameMode`. 90-day calendar, week boundary, day phase `08:00–20:00` (fix the 09–21 mismatch in `NPCSpawner.cpp:40`). - Sleep action on apartment bed: triggers the same path as energy-zero (§4.4) for the "items left outside" cleanup, restores energy, autosaves, advances calendar. - Weekly rent transaction at week boundary; eviction if money insufficient (`game over (run)`, §3.3). - Endless-mode flag on `UGlobalSaveGameData`; rent-eviction branch checks it. **Exit criteria:** play through 7 in-game days, get charged rent at the week boundary, eviction triggers on insufficient funds, endless-mode disables eviction. ### Phase 6 — NPC types + recognition pipeline (1–2 weeks) - `ENPCType` enum, type-specific BT branches or per-type controller subclasses: Walker / Stalker / Blogger / Snitch / Harasser. **No Helper** (cuff removal is Key-only per §10.4.1). - Police as a separate AI controller / spawn pipeline. Patrols spawn day and night while `wanted` (§7.7 / §10.3). Detection logic (`face hidden?` + coverage threshold) → chase → break-LOS timer. - Wanted-poster mechanic: spawn posters in the city; tearing all down clears `wanted` (§10.3). - Recognition flow: Blogger sight + photo event → article → news-site article state → "report" reduces recognition. - Wire Snitch's "report to police" → immediate police spawn this session + sets `wanted` (§7.7). **Exit criteria:** every listed NPC type observably distinct; recognition rises after a Blogger event and can be reduced via news report; Snitch report triggers police spawn and the `wanted` tag that persists across sessions until posters torn down or capture. ### Phase 7 — Commission template system (1–2 weeks) - Replace `MissionsConfig`'s hand-authored daily list with `UCommissionTemplate` + procedural generation per §13.4. - Add typed objective steps as new `UMissionGoal` subclasses: - `BeFullyNaked(duration)` (new in §13.4) - `BeFullyNakedNearNPCs(count, duration)` - `WalkNakedDistance(meters)` - `MoveDistanceFromClothing(meters)` - `BeObservedByNPCType(type, durationOrCount)` - `TakePhotoAtLocation(locationTag)` (requires phone work from Phase 8 — gate this objective until then) - `DeliverItemTo(npcOrLocation)` - Path-tagged XP (§5). Generation weights against player path progression. - Weekly-vs-daily generation pass. **Exit criteria:** daily commissions regenerate from templates each in-game day; weekly arc is distinct; failed commissions deduct reputation. ### Phase 8 — Phone + forum UI (2–3 weeks) - Phone as an `AItemActor` (Phase 2 base) with hand / pocket / bag location semantics (§9). - Apps: Camera + Gallery, Livestream (`UStreamSession` tickable UObject — works while phone is held *or* placed, §9.1.1 exception), Bank, Feetex, Maps, Health Tracker, Forum. - Photo system: render-to-texture (§17.6 / §21 Q6 — recommended). - Wire `TakePhotoAtLocation` commission step to actual photo events. **Exit criteria:** end-to-end photo loop — equip phone, capture photo, view in gallery, post to forum, follower count updates. Livestream can be started, run while the phone is set down, and ended with payout deposited. ### Phase 9 — Path progression + content authoring (2 weeks) - Path XP per path, level gating on clothing / missions / attribute upgrades. - Author the vertical-slice content set from GDD §18.1 (15-20 clothing items, 3 bag variants, 8 food items, 20 commission templates, 1 functional district). - Masturbation gating (§5.1, §7.2) — actually hide the quick-action entry until Slut path level 1. **Exit criteria:** all three paths have at least 5 unlockable items and 3 path-specific commission templates. Slut-path-locked actions are correctly hidden / gated. ### Phase 10 — Remaining systems & polish - Bag inventory (§6.4) — uses Phase 2's `AItemActor` for world placement. - Food / cooking (§6.7) — three minigames per the GDD (slice, stir, cook). - Gym / beauty salon / adult shop / cafe / convenience store (§10.4). - Rip & tear (§6.3.5). - Theft model (§6.3.4) — implement `T_grace` / `T_grace_bag` grace timers and per-tick `P_theft` chance roll. No ramp. - Expose action (§6.3.6) — read `CanExpose` per garment, blocked by overlapping coverage. - Restrictive-clothing flow (§6.3.7 / §10.4.1) — Key + timed unlock action. Lock hand-dependent actions while restrained. - Underwear selling (§15.1) — Feetex drop-box or location drop-off variant. - Wanted-poster takedown (§10.3) — interaction + spawn placement pass. - Final tuning: `T_grace`, `T_grace_bag`, `P_theft`, embarrassment / lust / energy / pulse rates (§21). --- ## 4. Working notes Use this section for in-flight decisions, blockers, and open questions that emerge during a phase. Move resolved items into the README's §20 "Resolved Design Decisions" or into git history. - **Phase 1 critical path:** the save-write-without-state bug is the most damaging current issue — any "save" call destroys progress. Fix the SaveSubsystem before anything else builds on save behaviour. - **Body-part enum migration:** the existing censorship code in `NakedDesireCharacter::OnClothingEquip` / `OnClothingUnequip` reads `EPrivateBodyPartType`. Migration to `EBodyPart` must update that path or the censorship visibility will silently desync. - **Slot-vocabulary cleanup will break BP references** — coordinate before deleting `Nipples` / `Anal` / `Vagina` from `EClothingSlotType`. The character constructor creates skeletal-mesh components keyed to those names; expect BPs in `Content/Blueprints/Player` to need a touch. - _empty beyond this point_