diff --git a/.voidbot/state/aetheria.cc b/.voidbot/state/aetheria.cc index fc078b7cc..5d18650ca 100644 Binary files a/.voidbot/state/aetheria.cc and b/.voidbot/state/aetheria.cc differ diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index f7971ff3c..b1007f4c4 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -16,6 +16,7 @@ RequireMainMenuSettingsCommit(root); RequirePropertiesPanelReadOnlyInspector(root); RequireRuntimeSimulationTuningCommits(root); RequireHullConductivityCommitAuthority(root); +RequireInventoryEntityRenameCommitAuthority(root); await using var node = await AetheriaStateNode.OpenAsync(statePath, "aetheria-state-verify"); @@ -461,6 +462,7 @@ Console.WriteLine("Main-menu settings authority: gameplay and graphics settings Console.WriteLine("PropertiesPanel inspector authority: reflection inspection is read-only display"); Console.WriteLine("Runtime simulation tuning authority: UI writes flow through gameplay checkpoint commits"); Console.WriteLine("Hull conductivity authority: inventory UI toggles flow through gameplay checkpoint commits"); +Console.WriteLine("Inventory entity rename authority: UI rename flows through gameplay checkpoint commits"); static void RequireCount(AetheriaMigrationLedger ledger, string documentType, int actual) { @@ -838,6 +840,37 @@ static void RequireHullConductivityCommitAuthority(string root) } } +static void RequireInventoryEntityRenameCommitAuthority(string root) +{ + var actionGameManagerPath = Path.Combine(root, "Assets", "Scripts", "Gameplay", "ActionGameManager.cs"); + var actionGameManager = File.Exists(actionGameManagerPath) + ? File.ReadAllText(actionGameManagerPath) + : throw new InvalidOperationException("Cannot verify inventory entity rename authority; ActionGameManager.cs is missing."); + + if (!actionGameManager.Contains("CommitEntityName", StringComparison.Ordinal) || + !actionGameManager.Contains("QueueRunCheckpoint(\"entity-name\")", StringComparison.Ordinal)) + { + throw new InvalidOperationException( + "Entity rename no longer has a gameplay-owned checkpoint commit primitive."); + } + + var inventoryPanelPath = Path.Combine(root, "Assets", "Scripts", "UI", "Menu", "InventoryPanel.cs"); + var inventoryPanel = File.Exists(inventoryPanelPath) + ? File.ReadAllText(inventoryPanelPath) + : throw new InvalidOperationException("Cannot verify inventory entity rename authority; InventoryPanel.cs is missing."); + + if (inventoryPanel.Contains("_displayedEntity.Name =", StringComparison.Ordinal)) + { + throw new InvalidOperationException( + "InventoryPanel still renames entities directly instead of using the gameplay checkpoint commit primitive."); + } + + if (!inventoryPanel.Contains("GameManager.CommitEntityName", StringComparison.Ordinal)) + { + throw new InvalidOperationException("InventoryPanel no longer routes entity rename through ActionGameManager."); + } +} + static string ExtractMethodBody(string source, string methodName) { var signature = "private void " + methodName + "()"; diff --git a/Assets/Scripts/Gameplay/ActionGameManager.cs b/Assets/Scripts/Gameplay/ActionGameManager.cs index 8ff34889c..34585bae8 100644 --- a/Assets/Scripts/Gameplay/ActionGameManager.cs +++ b/Assets/Scripts/Gameplay/ActionGameManager.cs @@ -1415,6 +1415,15 @@ public class ActionGameManager : MonoBehaviour QueueRunCheckpoint("entity-override-shutdown"); } + public void CommitEntityName(Entity entity, string name) + { + if (entity == null) + return; + + entity.Name = name ?? ""; + QueueRunCheckpoint("entity-name"); + } + public void CommitEquippedItemOverrideShutdown(EquippedItem item, bool enabled) { if (item?.EquippableItem == null) diff --git a/Assets/Scripts/UI/Menu/InventoryPanel.cs b/Assets/Scripts/UI/Menu/InventoryPanel.cs index e60558d34..6a87542f7 100644 --- a/Assets/Scripts/UI/Menu/InventoryPanel.cs +++ b/Assets/Scripts/UI/Menu/InventoryPanel.cs @@ -141,7 +141,7 @@ public class InventoryPanel : MonoBehaviour, IPointerClickHandler Dialog.AddField("Name", () => entityName, s => entityName = s); Dialog.Show(() => { - _displayedEntity.Name = entityName; + GameManager.CommitEntityName(_displayedEntity, entityName); Title.text = _displayedEntity.Name; }); Dialog.MoveToCursor(); diff --git a/docs/aetheria-perfect-machine-map.md b/docs/aetheria-perfect-machine-map.md index 26535674b..aca08c753 100644 --- a/docs/aetheria-perfect-machine-map.md +++ b/docs/aetheria-perfect-machine-map.md @@ -1380,6 +1380,10 @@ First Aetheria surfaces to publish: `ActionGameManager.CommitHullConductivityToggle`; the gameplay owner mutates `Entity.HullConductivity` and queues the typed run checkpoint that already projects `hull_conductivity_x` and `hull_conductivity_y` grids. + - Done: route inventory entity renames through + `ActionGameManager.CommitEntityName`. `InventoryPanel` may collect the name + in a dialog, but gameplay owns the entity `Name` mutation and queues the + typed entity snapshot checkpoint. - Replace the next concrete uGUI screen with an Eve-owned surface. - Move the staged packages into the Eve repo once its worktree is clean, then import them back into Aetheria from Eve instead of carrying a local copy. @@ -1698,7 +1702,8 @@ tuning controls may remain temporarily on uGUI only when they delegate to gameplay-owned commit methods that queue typed checkpoint state; direct UI mutation of entity/item/behavior settings is obsolete authority. Hull conductivity changes follow the same rule: UI requests the toggle, gameplay owns -the grid mutation and checkpoint. Any +the grid mutation and checkpoint. Entity renames follow the same rule: UI +collects text, gameplay owns the name mutation and checkpoint. Any predicate that still needs legacy DTO objects must earn that dependency by using behavior objects or simulation-only methods that typed facets do not yet expose.