2026-06-13 07:54:30 +01:00
using Aetheria.State ;
using Aetheria.State.Documents ;
2026-06-14 10:46:27 +01:00
using GameCult.Aetheria.State.Unity ;
2026-06-13 07:54:30 +01:00
var root = args . Length > 0 ? Path . GetFullPath ( args [ 0 ] ) : Directory . GetCurrentDirectory ( ) ;
var statePath = args . Length > 1
? Path . GetFullPath ( args [ 1 ] )
: AetheriaStatePaths . ResolveDefaultStatePath ( root ) ;
2026-06-15 20:43:59 +01:00
RequireGameplaySourcePurity ( root ) ;
2026-06-15 20:48:49 +01:00
RequirePackageSerializerBoundary ( root ) ;
2026-06-16 09:27:19 +01:00
RequireTypedPendingCommitKeys ( root ) ;
2026-06-16 10:01:02 +01:00
RequireTypedRuntimeFactionKeys ( root ) ;
2026-06-16 10:20:36 +01:00
RequireTypedGalaxyFactionRelationships ( root ) ;
2026-06-16 10:40:39 +01:00
RequireRuntimeCatalogKeyOnlyLookups ( root ) ;
2026-06-16 11:00:56 +01:00
RequireTypedBehaviorBodyKeys ( root ) ;
2026-06-16 15:54:18 +01:00
RequireTypedOrbitTaskKeys ( root ) ;
2026-06-16 16:07:20 +01:00
RequireTypedOrbitalEntityOrbitKeys ( root ) ;
2026-06-16 16:13:54 +01:00
RequireTypedOrbitConsumerKeys ( root ) ;
2026-06-16 16:20:30 +01:00
RequireKeyedOrbitRuntimeWrappers ( root ) ;
2026-06-16 16:27:33 +01:00
RequireNativeZoneKeyResolution ( root ) ;
2026-06-16 16:48:00 +01:00
RequireTypedZoneRuntimeCollections ( root ) ;
2026-06-16 16:57:18 +01:00
RequireTypedZoneConstructionKeys ( root ) ;
2026-06-16 17:03:59 +01:00
RequireTypedZoneStateSnapshotKeys ( root ) ;
2026-06-16 16:32:31 +01:00
RequireTypedAsteroidZoneApi ( root ) ;
2026-06-16 11:22:18 +01:00
RequireTypedFactionShellLinks ( root ) ;
2026-06-16 11:43:37 +01:00
RequireFactionKeyIdentity ( root ) ;
2026-06-15 21:12:43 +01:00
RequireEveRuntimeBootstrap ( root ) ;
2026-06-15 22:00:25 +01:00
RequireNoRendererLocalConsole ( root ) ;
2026-06-15 22:26:14 +01:00
RequireNoRendererLocalDebugPanels ( root ) ;
2026-06-15 22:47:15 +01:00
RequireMainMenuSettingsCommit ( root ) ;
2026-06-16 18:09:15 +01:00
RequirePlayerSettingsEveSurface ( root ) ;
2026-06-16 06:09:46 +01:00
RequireMainMenuContinueRunState ( root ) ;
2026-06-15 23:19:41 +01:00
RequirePropertiesPanelReadOnlyInspector ( root ) ;
2026-06-16 19:55:50 +01:00
RequireTypedBehaviorMetadataCoverage ( root ) ;
2026-06-16 19:19:05 +01:00
RequireNoDeadRuntimeProjectionCaches ( root ) ;
2026-06-16 19:24:01 +01:00
RequireNoDeadInspectorMetadata ( root ) ;
2026-06-16 00:01:19 +01:00
RequireRuntimeSimulationTuningCommits ( root ) ;
2026-06-16 00:19:58 +01:00
RequireHullConductivityCommitAuthority ( root ) ;
2026-06-16 00:40:04 +01:00
RequireInventoryEntityRenameCommitAuthority ( root ) ;
2026-06-16 01:00:40 +01:00
RequireWeaponGroupCommitAuthority ( root ) ;
2026-06-16 01:59:18 +01:00
RequireInventoryDoubleClickTransferCommitAuthority ( root ) ;
2026-06-16 04:27:07 +01:00
RequireLootPickupCommitAuthority ( root ) ;
2026-06-16 04:47:42 +01:00
RequireEntityDestroyedCommitAuthority ( root ) ;
2026-06-16 05:24:11 +01:00
RequireDroppedPickupCheckpointState ( root ) ;
2026-06-16 02:57:45 +01:00
RequireTradePurchaseCommitAuthority ( root ) ;
2026-06-16 03:18:55 +01:00
RequireInventoryLoadoutRestoreCommitAuthority ( root ) ;
2026-06-16 03:43:21 +01:00
RequireDockedCurrentShipCommitAuthority ( root ) ;
2026-06-15 20:43:59 +01:00
2026-06-13 07:54:30 +01:00
await using var node = await AetheriaStateNode . OpenAsync ( statePath , "aetheria-state-verify" ) ;
var ledger = await node . GetMigrationLedgerAsync ( )
? ? throw new InvalidOperationException ( "Missing typed migration ledger." ) ;
var quarantine = await node . GetLegacyCatalogQuarantineAsync ( )
? ? throw new InvalidOperationException ( "Missing legacy catalog quarantine document." ) ;
2026-06-13 08:37:10 +01:00
var publishedSurface = await node . GetCatalogSurfaceAsync ( )
? ? throw new InvalidOperationException ( "Missing Aetheria catalog Eve surface document." ) ;
2026-06-13 07:54:30 +01:00
var items = node . Cache . GetAll < AetheriaItemDefinition > ( ) . ToArray ( ) ;
var corporations = node . Cache . GetAll < AetheriaCorporation > ( ) . ToArray ( ) ;
var nameFiles = node . Cache . GetAll < AetheriaNameFile > ( ) . ToArray ( ) ;
2026-06-13 08:24:37 +01:00
var catalog = node . ReadCatalogSnapshot ( ) ;
2026-06-13 08:37:10 +01:00
var surface = AetheriaCatalogSurfaceProjector . Build ( catalog , DateTimeOffset . UtcNow . ToString ( "O" ) ) ;
2026-06-13 07:54:30 +01:00
RequireCount ( ledger , "aetheria.item_definition.v1" , items . Length ) ;
2026-06-13 13:18:03 +01:00
RequireCount ( ledger , "aetheria.corporation.v2" , corporations . Length ) ;
2026-06-13 12:46:34 +01:00
RequireCount ( ledger , "aetheria.name_file.v2" , nameFiles . Length ) ;
2026-06-13 07:54:30 +01:00
if ( items . Length = = 0 )
{
throw new InvalidOperationException ( "Typed state has no item definitions." ) ;
}
if ( corporations . Length = = 0 )
{
throw new InvalidOperationException ( "Typed state has no corporations." ) ;
}
if ( nameFiles . Length = = 0 )
{
throw new InvalidOperationException ( "Typed state has no name files." ) ;
}
2026-06-13 12:46:34 +01:00
if ( nameFiles . Any ( nameFile = > nameFile . Names . Length = = 0 | | nameFile . Names . Length ! = nameFile . NameCount ) )
{
throw new InvalidOperationException ( "Typed name files did not import their full name arrays." ) ;
}
2026-06-13 08:09:41 +01:00
var pricedItems = items . Count ( item = > item . Price > 0 ) ;
var manufacturedItems = items . Count ( item = > ! string . IsNullOrWhiteSpace ( item . ManufacturerLegacyId ) ) ;
2026-06-14 04:35:51 +01:00
var specificHeatItems = items . Count ( item = > item . SpecificHeat > 0 ) ;
2026-06-14 05:08:39 +01:00
var conductiveItems = items . Count ( item = > item . Conductivity > 0 ) ;
2026-06-13 08:09:41 +01:00
var shapedItems = items . Count ( item = > item . ShapeWidth > 0 & & item . ShapeHeight > 0 & & item . OccupiedCells > 0 ) ;
2026-06-13 09:32:24 +01:00
var shapedMaskItems = items . Count ( item = > item . ShapeCells . Length > 0 ) ;
2026-06-13 09:47:25 +01:00
var interiorShapeItems = items . Count ( item = > item . InteriorShapeCells . Length > 0 ) ;
var hardpointHostItems = items . Count ( item = > item . Hardpoints . Length > 0 ) ;
var hardpointCount = items . Sum ( item = > item . Hardpoints . Length ) ;
2026-06-13 09:01:13 +01:00
var behaviorItems = items . Count ( item = > item . BehaviorCount > 0 & & item . BehaviorKinds . Length > 0 ) ;
2026-06-13 10:01:20 +01:00
var behaviorPayloadItems = items . Count ( item = > item . BehaviorPayloads . Length > 0 ) ;
var behaviorPayloadCount = items . Sum ( item = > item . BehaviorPayloads . Length ) ;
var behaviorFieldCount = items . SelectMany ( item = > item . BehaviorPayloads ) . Sum ( behavior = > behavior . Fields . Length ) ;
var behaviorLegacyRefCount = items
. SelectMany ( item = > item . BehaviorPayloads )
. SelectMany ( behavior = > behavior . Fields )
. Count ( field = > ContainsBehaviorValueKind ( field . Value , "legacy-id" ) ) ;
2026-06-15 16:10:13 +01:00
var behaviorItemRefsMissingItemKeys = items
. SelectMany ( item = > item . BehaviorPayloads )
. Sum ( CountRequiredBehaviorItemRefsMissingItemKeys ) ;
2026-06-13 09:01:13 +01:00
var hardpointItems = items . Count ( item = > ! string . IsNullOrWhiteSpace ( item . HardpointType ) ) ;
var hullItems = items . Count ( item = > ! string . IsNullOrWhiteSpace ( item . HullType ) ) ;
2026-06-14 03:31:08 +01:00
var hullPrefabItems = items . Count ( item = > ! string . IsNullOrWhiteSpace ( item . HullPrefab ) ) ;
2026-06-14 05:08:39 +01:00
var hullArmorItems = items . Count ( item = > ! string . IsNullOrWhiteSpace ( item . HullType ) & & item . HullArmor > 0 ) ;
var hullPhysicalFacetItems = items . Count ( item = >
! string . IsNullOrWhiteSpace ( item . HullType ) & &
item . HullArmor > 0 & &
item . HullDrag > = 0 & &
! double . IsNaN ( item . HullGridOffset ) ) ;
2026-06-14 03:52:20 +01:00
var simpleCommodityCategoryItems = items . Count ( item = > ! string . IsNullOrWhiteSpace ( item . SimpleCommodityCategory ) ) ;
var compoundCommodityCategoryItems = items . Count ( item = > ! string . IsNullOrWhiteSpace ( item . CompoundCommodityCategory ) ) ;
2026-06-13 09:01:13 +01:00
var weaponItems = items . Count ( item = >
! string . IsNullOrWhiteSpace ( item . WeaponType ) & &
! string . IsNullOrWhiteSpace ( item . WeaponRange ) & &
! string . IsNullOrWhiteSpace ( item . WeaponCaliber ) ) ;
2026-06-14 02:05:26 +01:00
var maxDurabilityItems = items
. Where ( item = > ! string . IsNullOrWhiteSpace ( item . HullType ) | | ! string . IsNullOrWhiteSpace ( item . WeaponType ) )
. ToArray ( ) ;
var durableMaxDurabilityItems = maxDurabilityItems . Count ( item = > item . Durability > 0 ) ;
2026-06-14 03:05:37 +01:00
var importedThermalRangeItems = items . Count ( item = > item . MaximumTemperature > item . MinimumTemperature ) ;
2026-06-14 03:20:13 +01:00
var importedThermalCurveItems = items . Count ( item = > item . ThermalPerformanceCurveKeys . Length > 0 ) ;
2026-06-14 06:57:53 +01:00
var thermalResilienceItems = items . Count ( item = > item . ThermalResilience > 0 ) ;
2026-06-14 07:08:06 +01:00
var audioStatItems = items . Count ( item = > item . AudioStats . Length > 0 ) ;
var audioStatCount = items . Sum ( item = > item . AudioStats . Length ) ;
2026-06-14 10:46:27 +01:00
var consumableItems = items . Count ( item = > item . Category = = AetheriaRuntimeItemCategories . Consumable ) ;
var consumableDurationItems = items . Count ( item = > item . Category = = AetheriaRuntimeItemCategories . Consumable & & item . Duration > 0 ) ;
2026-06-14 07:20:06 +01:00
var consumableEffectivenessItems = items . Count ( item = > item . EffectivenessCurveKeys . Length > 0 ) ;
2026-06-14 06:47:47 +01:00
var actionBarIconItems = items . Count ( item = > ! string . IsNullOrWhiteSpace ( item . ActionBarIcon ) ) ;
2026-06-14 10:46:27 +01:00
var dockingBayItems = items . Count ( item = > item . Category = = AetheriaRuntimeItemCategories . DockingBay ) ;
2026-06-14 05:39:15 +01:00
var dockingBayMaxSizeItems = items . Count ( item = >
2026-06-14 10:46:27 +01:00
item . Category = = AetheriaRuntimeItemCategories . DockingBay & &
2026-06-14 05:39:15 +01:00
item . DockingMaxSizeX > 0 & &
item . DockingMaxSizeY > 0 ) ;
2026-06-13 08:09:41 +01:00
var describedCorporations = corporations . Count ( corporation = > ! string . IsNullOrWhiteSpace ( corporation . Description ) ) ;
var corporationNameLinks = corporations . Count ( corporation = > ! string . IsNullOrWhiteSpace ( corporation . GeonameFileLegacyId ) ) ;
2026-06-13 13:18:03 +01:00
var corporationAllegianceEdges = corporations . Sum ( corporation = > corporation . Allegiances . Length ) ;
2026-06-15 20:33:32 +01:00
var legacyDtoCategories = items
. Where ( item = > item . Category . EndsWith ( "Data" , StringComparison . Ordinal ) )
. Select ( item = > $"{item.Name}:{item.Category}" )
. ToArray ( ) ;
2026-06-13 08:09:41 +01:00
if ( pricedItems = = 0 )
{
throw new InvalidOperationException ( "Typed item definitions did not import any prices." ) ;
}
2026-06-15 20:33:32 +01:00
if ( legacyDtoCategories . Length > 0 )
{
throw new InvalidOperationException (
"Typed item categories still contain legacy DTO class names: " +
string . Join ( ", " , legacyDtoCategories . Take ( 5 ) ) ) ;
}
2026-06-13 08:09:41 +01:00
if ( manufacturedItems = = 0 )
{
throw new InvalidOperationException ( "Typed item definitions did not import any manufacturer legacy IDs." ) ;
}
2026-06-14 04:35:51 +01:00
if ( specificHeatItems ! = items . Length )
{
throw new InvalidOperationException (
$"Typed item definitions did not import positive specific heat for every item: {specificHeatItems}/{items.Length}." ) ;
}
2026-06-14 05:08:39 +01:00
if ( conductiveItems ! = items . Length )
{
throw new InvalidOperationException (
$"Typed item definitions did not import positive conductivity for every item: {conductiveItems}/{items.Length}." ) ;
}
2026-06-14 06:57:53 +01:00
if ( thermalResilienceItems ! = items . Length )
{
throw new InvalidOperationException (
$"Typed item definitions did not import positive thermal resilience for every item: {thermalResilienceItems}/{items.Length}." ) ;
}
2026-06-13 08:09:41 +01:00
if ( shapedItems = = 0 )
{
throw new InvalidOperationException ( "Typed item definitions did not import any shape dimensions." ) ;
}
2026-06-13 09:32:24 +01:00
if ( shapedMaskItems ! = shapedItems )
{
throw new InvalidOperationException (
$"Typed item shape mask import mismatch: masks={shapedMaskItems}, shaped={shapedItems}." ) ;
}
foreach ( var item in items . Where ( item = > item . ShapeCells . Length > 0 ) )
{
if ( item . ShapeCells . Length ! = item . OccupiedCells )
{
throw new InvalidOperationException (
$"Typed item shape mask cell count mismatch for {item.Name}: cells={item.ShapeCells.Length}, occupied={item.OccupiedCells}." ) ;
}
if ( item . ShapeCells . Any ( cell = > cell . X < 0 | | cell . Y < 0 | | cell . X > = item . ShapeWidth | | cell . Y > = item . ShapeHeight ) )
{
throw new InvalidOperationException ( $"Typed item shape mask has out-of-bounds cells for {item.Name}." ) ;
}
}
2026-06-13 09:47:25 +01:00
foreach ( var item in items . Where ( item = > item . InteriorShapeCells . Length > 0 ) )
{
if ( item . InteriorShapeCells . Length ! = item . InteriorOccupiedCells )
{
throw new InvalidOperationException (
$"Typed item interior shape mask count mismatch for {item.Name}: cells={item.InteriorShapeCells.Length}, occupied={item.InteriorOccupiedCells}." ) ;
}
if ( item . InteriorShapeCells . Any ( cell = >
cell . X < 0 | | cell . Y < 0 | | cell . X > = item . InteriorShapeWidth | | cell . Y > = item . InteriorShapeHeight ) )
{
throw new InvalidOperationException ( $"Typed item interior shape mask has out-of-bounds cells for {item.Name}." ) ;
}
}
if ( interiorShapeItems = = 0 )
{
throw new InvalidOperationException ( "Typed item definitions did not import any interior shape masks." ) ;
}
if ( hardpointHostItems = = 0 | | hardpointCount = = 0 )
{
throw new InvalidOperationException ( "Typed item definitions did not import any hull hardpoints." ) ;
}
2026-06-14 02:05:26 +01:00
var missingMaxDurability = maxDurabilityItems
. Where ( item = > item . Durability < = 0 )
. Select ( item = > item . Name )
. ToArray ( ) ;
if ( missingMaxDurability . Length > 0 )
{
throw new InvalidOperationException (
$"Typed hull/weapon max durability missing for: {string.Join(" , ", missingMaxDurability)}." ) ;
}
2026-06-14 03:05:37 +01:00
if ( importedThermalRangeItems = = 0 )
{
throw new InvalidOperationException ( "Typed item definitions did not import any thermal ranges." ) ;
}
2026-06-14 03:20:13 +01:00
if ( importedThermalCurveItems = = 0 )
{
throw new InvalidOperationException ( "Typed item definitions did not import any thermal performance curves." ) ;
}
foreach ( var item in items . Where ( item = > item . ThermalPerformanceCurveKeys . Length > 0 ) )
{
if ( item . ThermalPerformanceCurveKeys . Any ( key = > key . Time < 0 | | key . Time > 1 ) )
{
throw new InvalidOperationException ( $"Typed thermal performance curve has out-of-range key time for {item.Name}." ) ;
}
}
2026-06-13 09:47:25 +01:00
foreach ( var item in items . Where ( item = > item . Hardpoints . Length > 0 ) )
{
foreach ( var hardpoint in item . Hardpoints )
{
if ( string . IsNullOrWhiteSpace ( hardpoint . Type ) )
{
throw new InvalidOperationException ( $"Typed item hardpoint has no type for {item.Name}." ) ;
}
if ( hardpoint . ShapeCells . Length ! = hardpoint . OccupiedCells )
{
throw new InvalidOperationException (
$"Typed item hardpoint shape count mismatch for {item.Name}: cells={hardpoint.ShapeCells.Length}, occupied={hardpoint.OccupiedCells}." ) ;
}
if ( hardpoint . ShapeCells . Any ( cell = >
cell . X < 0 | | cell . Y < 0 | | cell . X > = hardpoint . ShapeWidth | | cell . Y > = hardpoint . ShapeHeight ) )
{
throw new InvalidOperationException ( $"Typed item hardpoint shape has out-of-bounds cells for {item.Name}." ) ;
}
// Legacy content includes at least one overhanging hardpoint. Preserve the
// payload faithfully here; content repair belongs to a separate pass.
}
}
2026-06-13 09:01:13 +01:00
if ( behaviorItems = = 0 )
{
throw new InvalidOperationException ( "Typed item definitions did not import any behavior fingerprints." ) ;
}
2026-06-13 10:01:20 +01:00
if ( behaviorPayloadItems ! = behaviorItems | | behaviorPayloadCount = = 0 | | behaviorFieldCount = = 0 )
{
throw new InvalidOperationException (
$"Typed behavior payload import mismatch: payloadItems={behaviorPayloadItems}, behaviorItems={behaviorItems}, payloads={behaviorPayloadCount}, fields={behaviorFieldCount}." ) ;
}
2026-06-15 16:10:13 +01:00
if ( behaviorItemRefsMissingItemKeys > 0 )
{
throw new InvalidOperationException (
$"Typed behavior payload item refs missing item-key projections: {behaviorItemRefsMissingItemKeys}." ) ;
}
2026-06-13 10:01:20 +01:00
foreach ( var item in items . Where ( item = > item . BehaviorPayloads . Length > 0 ) )
{
if ( item . BehaviorPayloads . Length ! = item . BehaviorCount )
{
throw new InvalidOperationException (
$"Typed item behavior payload count mismatch for {item.Name}: payloads={item.BehaviorPayloads.Length}, count={item.BehaviorCount}." ) ;
}
foreach ( var behavior in item . BehaviorPayloads )
{
if ( string . IsNullOrWhiteSpace ( behavior . Kind ) | | behavior . UnionKey < 0 | | behavior . Fields . Length = = 0 )
{
throw new InvalidOperationException ( $"Typed item behavior payload is incomplete for {item.Name}." ) ;
}
}
}
2026-06-13 09:01:13 +01:00
if ( hardpointItems = = 0 )
{
throw new InvalidOperationException ( "Typed item definitions did not import any hardpoint types." ) ;
}
if ( hullItems = = 0 )
{
throw new InvalidOperationException ( "Typed item definitions did not import any hull types." ) ;
}
2026-06-14 03:31:08 +01:00
if ( hullPrefabItems ! = hullItems )
{
throw new InvalidOperationException ( $"Typed hull prefab import mismatch: hulls={hullItems}, prefabs={hullPrefabItems}." ) ;
}
2026-06-14 05:08:39 +01:00
if ( hullArmorItems ! = hullItems | | hullPhysicalFacetItems ! = hullItems )
{
throw new InvalidOperationException (
$"Typed hull physical facet import mismatch: hulls={hullItems}, armor={hullArmorItems}, physical={hullPhysicalFacetItems}." ) ;
}
2026-06-14 03:52:20 +01:00
if ( simpleCommodityCategoryItems = = 0 )
{
throw new InvalidOperationException ( "Typed simple commodity category import produced no categories." ) ;
}
if ( compoundCommodityCategoryItems = = 0 )
{
throw new InvalidOperationException ( "Typed compound commodity category import produced no categories." ) ;
}
2026-06-13 09:01:13 +01:00
if ( weaponItems = = 0 )
{
throw new InvalidOperationException ( "Typed item definitions did not import any weapon facets." ) ;
}
2026-06-14 05:39:15 +01:00
if ( dockingBayItems = = 0 | | dockingBayMaxSizeItems ! = dockingBayItems )
{
throw new InvalidOperationException (
$"Typed docking bay max-size import mismatch: dockingBays={dockingBayItems}, maxSizes={dockingBayMaxSizeItems}." ) ;
}
2026-06-13 08:09:41 +01:00
if ( describedCorporations = = 0 )
{
throw new InvalidOperationException ( "Typed corporations did not import descriptions from legacy key 3." ) ;
}
if ( corporationNameLinks = = 0 )
{
throw new InvalidOperationException ( "Typed corporations did not import geoname file legacy IDs." ) ;
}
2026-06-13 13:18:03 +01:00
if ( corporationAllegianceEdges = = 0 | | corporations . Any ( corporation = > corporation . Allegiances . Length ! = corporation . AllegianceCount ) )
{
throw new InvalidOperationException ( "Typed corporations did not import full allegiance edges." ) ;
}
2026-06-13 08:24:37 +01:00
var tradeItems = catalog . TradeItems . ToArray ( ) ;
if ( tradeItems . Length ! = pricedItems )
{
throw new InvalidOperationException (
$"Typed catalog trade item query mismatch: query={tradeItems.Length}, priced={pricedItems}." ) ;
}
2026-06-13 09:01:13 +01:00
var equipmentItems = catalog . EquipmentItems . ToArray ( ) ;
if ( equipmentItems . Length ! = hardpointItems )
{
throw new InvalidOperationException (
$"Typed catalog equipment item query mismatch: query={equipmentItems.Length}, hardpoint={hardpointItems}." ) ;
}
var behaviorKind = items . SelectMany ( item = > item . BehaviorKinds ) . FirstOrDefault ( )
? ? throw new InvalidOperationException ( "Cannot verify typed catalog behavior query: no behavior kinds." ) ;
if ( ! catalog . FindItemsByBehavior ( behaviorKind ) . Any ( ) )
{
throw new InvalidOperationException ( $"Typed catalog behavior query failed for {behaviorKind}." ) ;
}
var hardpointType = items . FirstOrDefault ( item = > ! string . IsNullOrWhiteSpace ( item . HardpointType ) ) ? . HardpointType
? ? throw new InvalidOperationException ( "Cannot verify typed catalog hardpoint query: no hardpoint types." ) ;
if ( ! catalog . FindItemsByHardpoint ( hardpointType ) . Any ( ) )
{
throw new InvalidOperationException ( $"Typed catalog hardpoint query failed for {hardpointType}." ) ;
}
2026-06-13 08:24:37 +01:00
var manufacturedItem = items . FirstOrDefault ( item = > ! string . IsNullOrWhiteSpace ( item . ManufacturerLegacyId ) )
? ? throw new InvalidOperationException ( "Cannot verify typed catalog manufacturer lookup: no manufactured item." ) ;
2026-06-15 17:25:40 +01:00
if ( string . IsNullOrWhiteSpace ( manufacturedItem . ManufacturerKey ) | |
catalog . FindCorporation ( manufacturedItem . ManufacturerKey ) = = null | |
catalog . GetManufacturer ( manufacturedItem ) = = null )
2026-06-13 08:24:37 +01:00
{
throw new InvalidOperationException (
2026-06-15 17:25:40 +01:00
$"Typed catalog manufacturer-key lookup failed for item {manufacturedItem.Name}." ) ;
2026-06-13 08:24:37 +01:00
}
var corporationWithNames = corporations . FirstOrDefault ( corporation = >
! string . IsNullOrWhiteSpace ( corporation . GeonameFileLegacyId ) )
? ? throw new InvalidOperationException ( "Cannot verify typed catalog name-file lookup: no linked corporation." ) ;
2026-06-15 17:25:40 +01:00
if ( string . IsNullOrWhiteSpace ( corporationWithNames . GeonameFileKey ) | |
catalog . FindNameFile ( corporationWithNames . GeonameFileKey ) = = null | |
catalog . GetNameFile ( corporationWithNames ) = = null )
2026-06-13 08:24:37 +01:00
{
throw new InvalidOperationException (
2026-06-15 17:25:40 +01:00
$"Typed catalog name-file-key lookup failed for corporation {corporationWithNames.Name}." ) ;
2026-06-13 08:24:37 +01:00
}
2026-06-13 08:37:10 +01:00
if ( surface . Schema ! = "gamecult.eve.surface.v1" | |
surface . Surface . Root . Kind ! = "surface" | |
surface . Surface . Root . Children . Length = = 0 )
{
throw new InvalidOperationException ( "Aetheria catalog Eve surface projection is not renderable." ) ;
}
if ( publishedSurface . Schema ! = surface . Schema | |
publishedSurface . Surface . Id ! = AetheriaCatalogSurfaceProjector . SurfaceId | |
publishedSurface . Surface . Root . Kind ! = "surface" )
{
throw new InvalidOperationException ( "Published Aetheria catalog Eve surface is not the expected typed surface." ) ;
}
2026-06-13 07:54:30 +01:00
await RequireLegacyLookupAsync (
items [ 0 ] . LegacyId ,
( ) = > node . GetItemDefinitionByLegacyIdAsync ( items [ 0 ] . LegacyId ) ,
"item definition" ) ;
await RequireLegacyLookupAsync (
corporations [ 0 ] . LegacyId ,
( ) = > node . GetCorporationByLegacyIdAsync ( corporations [ 0 ] . LegacyId ) ,
"corporation" ) ;
await RequireLegacyLookupAsync (
nameFiles [ 0 ] . LegacyId ,
( ) = > node . GetNameFileByLegacyIdAsync ( nameFiles [ 0 ] . LegacyId ) ,
"name file" ) ;
if ( string . IsNullOrWhiteSpace ( quarantine . CatalogFingerprint ) )
{
throw new InvalidOperationException ( "Legacy catalog quarantine has no catalog fingerprint." ) ;
}
Console . WriteLine ( $"Aetheria typed state verify passed: {statePath}" ) ;
Console . WriteLine ( $"Catalog fingerprint: {quarantine.CatalogFingerprint}" ) ;
Console . WriteLine ( $"Item definitions: {items.Length}" ) ;
2026-06-14 05:08:39 +01:00
Console . WriteLine ( $"Priced/manufactured/specific-heat/conductive/shaped items: {pricedItems}/{manufacturedItems}/{specificHeatItems}/{conductiveItems}/{shapedItems}" ) ;
2026-06-14 06:57:53 +01:00
Console . WriteLine ( $"Thermal resilience items: {thermalResilienceItems}" ) ;
2026-06-14 07:08:06 +01:00
Console . WriteLine ( $"Audio stat items/stats: {audioStatItems}/{audioStatCount}" ) ;
2026-06-14 07:20:06 +01:00
Console . WriteLine ( $"Consumable duration/effectiveness items: {consumableDurationItems}/{consumableEffectivenessItems} of {consumableItems}" ) ;
2026-06-13 09:32:24 +01:00
Console . WriteLine ( $"Shape masks: {shapedMaskItems}" ) ;
2026-06-13 09:47:25 +01:00
Console . WriteLine ( $"Interior masks/hardpoint hosts/hardpoints: {interiorShapeItems}/{hardpointHostItems}/{hardpointCount}" ) ;
2026-06-13 10:01:20 +01:00
Console . WriteLine ( $"Behavior payload items/payloads/fields/legacy refs: {behaviorPayloadItems}/{behaviorPayloadCount}/{behaviorFieldCount}/{behaviorLegacyRefCount}" ) ;
2026-06-13 09:01:13 +01:00
Console . WriteLine ( $"Behavior/hardpoint/hull/weapon items: {behaviorItems}/{hardpointItems}/{hullItems}/{weaponItems}" ) ;
2026-06-14 03:31:08 +01:00
Console . WriteLine ( $"Hull prefab items: {hullPrefabItems}" ) ;
2026-06-14 05:08:39 +01:00
Console . WriteLine ( $"Hull armor/physical facet items: {hullArmorItems}/{hullPhysicalFacetItems}" ) ;
2026-06-14 03:52:20 +01:00
Console . WriteLine ( $"Simple/compound commodity category items: {simpleCommodityCategoryItems}/{compoundCommodityCategoryItems}" ) ;
2026-06-14 02:05:26 +01:00
Console . WriteLine ( $"Durable hull/weapon items: {durableMaxDurabilityItems}/{maxDurabilityItems.Length}" ) ;
2026-06-14 03:20:13 +01:00
Console . WriteLine ( $"Thermal range/curve items: {importedThermalRangeItems}/{importedThermalCurveItems}" ) ;
2026-06-14 06:47:47 +01:00
Console . WriteLine ( $"Action-bar icon items: {actionBarIconItems}" ) ;
2026-06-14 05:39:15 +01:00
Console . WriteLine ( $"Docking bay max-size items: {dockingBayMaxSizeItems}/{dockingBayItems}" ) ;
2026-06-13 08:24:37 +01:00
Console . WriteLine ( $"Typed catalog trade items: {tradeItems.Length}" ) ;
2026-06-13 08:37:10 +01:00
Console . WriteLine ( $"Eve catalog surface: {surface.Surface.Id} ({surface.Surface.Root.Children.Length} root children)" ) ;
2026-06-13 07:54:30 +01:00
Console . WriteLine ( $"Corporations: {corporations.Length}" ) ;
2026-06-13 08:09:41 +01:00
Console . WriteLine ( $"Described/geoname-linked corporations: {describedCorporations}/{corporationNameLinks}" ) ;
2026-06-13 13:18:03 +01:00
Console . WriteLine ( $"Corporation allegiance edges: {corporationAllegianceEdges}" ) ;
2026-06-13 07:54:30 +01:00
Console . WriteLine ( $"Name files: {nameFiles.Length}" ) ;
2026-06-15 20:43:59 +01:00
Console . WriteLine ( "Live gameplay source purity: no serializer or legacy database symbols in Assets/Scripts" ) ;
2026-06-15 20:48:49 +01:00
Console . WriteLine ( "Package serializer boundary: MessagePack symbols remain in named CultCache transport files only" ) ;
2026-06-15 21:12:43 +01:00
Console . WriteLine ( "Eve runtime bootstrap: operations surface mounts through UI Toolkit presenter" ) ;
2026-06-15 22:00:25 +01:00
Console . WriteLine ( "Renderer-local console authority: deleted; UI commands flow through Eve command documents" ) ;
2026-06-15 22:26:14 +01:00
Console . WriteLine ( "Renderer-local debug panels: obsolete uGUI field tester authority is deleted" ) ;
2026-06-16 19:45:39 +01:00
Console . WriteLine ( "Main-menu settings authority: player name, gameplay, and graphics settings return through typed player-settings commits" ) ;
2026-06-16 06:09:46 +01:00
Console . WriteLine ( "Main-menu Continue authority: Continue selects typed run state instead of a null button" ) ;
2026-06-16 19:38:02 +01:00
Console . WriteLine ( "PropertiesPanel inspector authority: dead generic reflection inspector path is deleted" ) ;
2026-06-16 19:55:50 +01:00
Console . WriteLine ( "Typed behavior metadata authority: live heat/mining/thermotoggle payload kinds stay owned by package metadata" ) ;
2026-06-16 00:01:19 +01:00
Console . WriteLine ( "Runtime simulation tuning authority: UI writes flow through gameplay checkpoint commits" ) ;
2026-06-16 00:19:58 +01:00
Console . WriteLine ( "Hull conductivity authority: inventory UI toggles flow through gameplay checkpoint commits" ) ;
2026-06-16 00:40:04 +01:00
Console . WriteLine ( "Inventory entity rename authority: UI rename flows through gameplay checkpoint commits" ) ;
2026-06-16 01:00:40 +01:00
Console . WriteLine ( "Weapon group authority: UI assignment flows through gameplay checkpoint commits" ) ;
2026-06-16 02:35:13 +01:00
Console . WriteLine ( "Inventory transfer authority: UI transfer and drag/drop requests flow through gameplay checkpoint commits" ) ;
2026-06-16 04:47:42 +01:00
Console . WriteLine ( "Loot pickup authority: collision pickup requests flow through gameplay checkpoint commits" ) ;
Console . WriteLine ( "Entity destruction authority: hull-death observers flow through gameplay checkpoint commits" ) ;
2026-06-16 05:51:07 +01:00
Console . WriteLine ( "Dropped pickup state: zone checkpoints carry typed dropped-pickup snapshots and keyed live lowering" ) ;
2026-06-16 02:57:45 +01:00
Console . WriteLine ( "Trade purchase authority: UI buy requests flow through gameplay checkpoint commits" ) ;
2026-06-16 03:18:55 +01:00
Console . WriteLine ( "Inventory loadout restore authority: UI restore requests flow through gameplay checkpoint commits" ) ;
2026-06-16 03:43:21 +01:00
Console . WriteLine ( "Docked current-ship authority: UI selection requests flow through gameplay checkpoint commits" ) ;
2026-06-13 07:54:30 +01:00
static void RequireCount ( AetheriaMigrationLedger ledger , string documentType , int actual )
{
var expected = ledger . Counts . FirstOrDefault ( count = > count . DocumentType = = documentType ) ? . Count ;
if ( expected = = null )
{
throw new InvalidOperationException ( $"Migration ledger is missing count for {documentType}." ) ;
}
if ( expected . Value ! = actual )
{
throw new InvalidOperationException (
$"Migration ledger count mismatch for {documentType}: ledger={expected.Value}, actual={actual}." ) ;
}
}
2026-06-15 20:43:59 +01:00
static void RequireGameplaySourcePurity ( string root )
{
var gameplayRoot = Path . Combine ( root , "Assets" , "Scripts" ) ;
if ( ! Directory . Exists ( gameplayRoot ) )
{
throw new InvalidOperationException ( $"Cannot verify live gameplay source purity; missing path: {gameplayRoot}" ) ;
}
var forbiddenSymbols = new [ ]
{
"MessagePack" ,
"MessagePackObject" ,
"MessagePackSerializer" ,
"MessagePackReader" ,
"IMessagePackFormatter" ,
"JsonConvert" ,
"Newtonsoft" ,
"JsonKnownTypes" ,
"RethinkDB" ,
"DatabaseEntry" ,
"DatabaseLink" ,
"[Union(" ,
"[Key("
} ;
var hits = Directory . EnumerateFiles ( gameplayRoot , "*.cs" , SearchOption . AllDirectories )
. SelectMany ( path = > File . ReadLines ( path )
. Select ( ( line , index ) = > new { Path = path , LineNumber = index + 1 , Line = line } ) )
. Where ( line = > forbiddenSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, line.Path)}:{line.LineNumber}: {line.Line.Trim()}" )
. Take ( 10 )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"Live gameplay source still contains serializer or legacy database symbols: " +
string . Join ( "; " , hits ) ) ;
}
}
2026-06-15 20:48:49 +01:00
static void RequirePackageSerializerBoundary ( string root )
{
var packageRuntimeRoot = Path . Combine ( root , "Packages" , "org.gamecult.aetheria.state" , "Runtime" ) ;
if ( ! Directory . Exists ( packageRuntimeRoot ) )
{
throw new InvalidOperationException ( $"Cannot verify package serializer boundary; missing path: {packageRuntimeRoot}" ) ;
}
var allowedFiles = new HashSet < string > ( StringComparer . Ordinal )
{
"AetheriaRuntimeCatalogStore.cs" ,
"AetheriaRuntimePendingCultCacheStore.cs" ,
"AetheriaRuntimeStateCommitDocument.cs" ,
"AetheriaRuntimeEveCommandDocument.cs"
} ;
var serializerSymbols = new [ ]
{
"MessagePack" ,
"MessagePackObject" ,
"MessagePackSerializer" ,
"MessagePackReader" ,
"MessagePackWriter" ,
"IMessagePackFormatter" ,
"[Union(" ,
"[Key("
} ;
var hits = Directory . EnumerateFiles ( packageRuntimeRoot , "*.cs" , SearchOption . AllDirectories )
. Where ( path = > ! allowedFiles . Contains ( Path . GetFileName ( path ) ) )
. SelectMany ( path = > File . ReadLines ( path )
. Select ( ( line , index ) = > new { Path = path , LineNumber = index + 1 , Line = line } ) )
. Where ( line = > serializerSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, line.Path)}:{line.LineNumber}: {line.Line.Trim()}" )
. Take ( 10 )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"Package serializer symbols escaped the named CultCache transport boundary: " +
string . Join ( "; " , hits ) ) ;
}
}
2026-06-16 09:27:19 +01:00
static void RequireTypedPendingCommitKeys ( string root )
{
var checkedFiles = new [ ]
{
Path . Combine ( root , "Packages" , "org.gamecult.aetheria.state" , "Runtime" , "AetheriaRuntimeStateCommitDocument.cs" ) ,
Path . Combine ( root , "Aetheria.State" , "AetheriaRuntimeCommitLogApplier.cs" )
} ;
var forbiddenSymbols = new [ ]
{
"CorporationLegacyId" ,
"OrbitLegacyId" ,
"ParentLegacyId" ,
"BodyLegacyId" ,
"ResourceScannerTargetBodyId { get; set; }" ,
"MiningToolAsteroidBeltId { get; set; }" ,
"ReferenceKey(entity.FactionKey" ,
"ReferenceKey(orbit.OrbitKey" ,
"ReferenceKey(body.BodyKey" ,
"ReferenceKey(relationship.FactionKey"
} ;
var hits = checkedFiles
. Where ( File . Exists )
. SelectMany ( path = > File . ReadLines ( path )
. Select ( ( line , index ) = > new { Path = path , LineNumber = index + 1 , Line = line } ) )
. Where ( line = > forbiddenSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, line.Path)}:{line.LineNumber}: {line.Line.Trim()}" )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"Pending runtime commit authority still accepts legacy ID fallback fields: " +
string . Join ( "; " , hits ) ) ;
}
}
2026-06-16 10:01:02 +01:00
static void RequireTypedRuntimeFactionKeys ( string root )
{
var checkedFiles = new [ ]
{
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "EntityConstructionBlueprintProjector.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "Gameplay" , "ActionGameManager.cs" )
} ;
var forbiddenSymbols = new [ ]
{
"public Guid Faction" ,
"blueprint.Faction =" ,
"blueprint.Faction)" ,
"blueprint.Faction," ,
"blueprint.Faction;" ,
"ResolveFaction(blueprint.Faction" ,
"LegacyId(blueprint.Faction" ,
"ReferenceKey(blueprint.FactionKey" ,
"CorporationKey(entity.Faction?.ID" ,
"CorporationKey(pair.Key.ID" ,
"private static string CorporationKey"
} ;
var hits = checkedFiles
. Where ( File . Exists )
. SelectMany ( path = > File . ReadLines ( path )
. Select ( ( line , index ) = > new { Path = path , LineNumber = index + 1 , Line = line } ) )
. Where ( line = > forbiddenSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, line.Path)}:{line.LineNumber}: {line.Line.Trim()}" )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"Runtime faction commits must use typed FactionKey authority, not legacy GUID fallback: " +
string . Join ( "; " , hits ) ) ;
}
}
2026-06-16 10:20:36 +01:00
static void RequireTypedGalaxyFactionRelationships ( string root )
{
var checkedFiles = new [ ]
{
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Corporations.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Galaxy.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "LoadoutGenerator.cs" )
} ;
var forbiddenSymbols = new [ ]
{
"Dictionary<Guid, float> Allegiance" ,
".Allegiance[" ,
"ContainsFaction(Guid" ,
"ResolveFaction(Guid" ,
"CorporationLegacyId" ,
"factionsByLegacyId" ,
"_containedFactions"
} ;
var hits = checkedFiles
. Where ( File . Exists )
. SelectMany ( path = > File . ReadLines ( path )
. Select ( ( line , index ) = > new { Path = path , LineNumber = index + 1 , Line = line } ) )
. Where ( line = > forbiddenSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, line.Path)}:{line.LineNumber}: {line.Line.Trim()}" )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"Galaxy faction relationships must use typed corporation keys, not legacy GUID allegiance state: " +
string . Join ( "; " , hits ) ) ;
}
}
2026-06-16 10:40:39 +01:00
static void RequireRuntimeCatalogKeyOnlyLookups ( string root )
{
var checkedFiles = new [ ]
{
Path . Combine ( root , "Packages" , "org.gamecult.aetheria.state" , "Runtime" , "AetheriaRuntimeCatalogSnapshot.cs" ) ,
2026-06-16 19:14:35 +01:00
Path . Combine ( root , "Aetheria.State.Unity.Smoke" , "Program.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "ItemManager.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "Gameplay" , "ActionGameManager.cs" )
2026-06-16 10:40:39 +01:00
} ;
var forbiddenSymbols = new [ ]
{
2026-06-16 19:14:35 +01:00
"IRuntimeItemCatalogReader" ,
"AetheriaRuntimeItemCatalog" ,
2026-06-16 10:40:39 +01:00
"_itemsByLegacyId" ,
"_corporationsByLegacyId" ,
"_nameFilesByLegacyId" ,
"FindItemByLegacyId" ,
"FindCorporationByLegacyId" ,
2026-06-16 12:59:33 +01:00
"FindNameFileByLegacyId" ,
"public string LegacyId { get; }" ,
"public string ManufacturerLegacyId" ,
"public string GeonameFileLegacyId" ,
"public string BossHullLegacyId" ,
"public string CorporationLegacyId" ,
".ManufacturerLegacyId" ,
".GeonameFileLegacyId" ,
".BossHullLegacyId" ,
".CorporationLegacyId"
2026-06-16 10:40:39 +01:00
} ;
var hits = checkedFiles
. Where ( File . Exists )
. SelectMany ( path = > File . ReadLines ( path )
. Select ( ( line , index ) = > new { Path = path , LineNumber = index + 1 , Line = line } ) )
. Where ( line = > forbiddenSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, line.Path)}:{line.LineNumber}: {line.Line.Trim()}" )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
2026-06-16 19:14:35 +01:00
"Unity runtime catalog lookup authority must stay on the typed snapshot; legacy-ID indexes and redundant catalog adapters belong to migration boundaries: " +
2026-06-16 10:40:39 +01:00
string . Join ( "; " , hits ) ) ;
}
}
2026-06-16 11:00:56 +01:00
static void RequireTypedBehaviorBodyKeys ( string root )
{
var checkedFiles = new [ ]
{
Path . Combine ( root , "Aetheria.State" , "Documents" , "AetheriaRuntimeStateDocuments.cs" ) ,
Path . Combine ( root , "Aetheria.State" , "AetheriaRuntimeCommitLogApplier.cs" ) ,
Path . Combine ( root , "Packages" , "org.gamecult.aetheria.state" , "Runtime" , "AetheriaRuntimeCatalogSnapshot.cs" ) ,
Path . Combine ( root , "Packages" , "org.gamecult.aetheria.state" , "Runtime" , "AetheriaRuntimeCatalogStore.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "Gameplay" , "ActionGameManager.cs" ) ,
Path . Combine ( root , "Aetheria.State.Smoke" , "Program.cs" ) ,
Path . Combine ( root , "Aetheria.State.Unity.Smoke" , "Program.cs" )
} ;
var forbiddenSymbols = new [ ]
{
"ResourceScannerTargetBodyId" ,
"MiningToolAsteroidBeltId" ,
"ParseLegacyGuidFromReferenceKey" ,
2026-06-16 14:22:52 +01:00
"ParseLegacyIdFromReferenceKey" ,
2026-06-16 15:08:00 +01:00
"ParseBodyGuidFromKey(" ,
2026-06-16 14:22:52 +01:00
"private static string OrbitKey(Guid" ,
"private static string BodyKey(Guid" ,
"$\"aetheria.orbit:legacy:" ,
2026-06-16 15:08:00 +01:00
"$\"aetheria.body:legacy:" ,
"public Guid ScanTarget" ,
"public Guid AsteroidBelt" ,
"RestoreRuntimeState(Guid scanTarget" ,
"RestoreRuntimeState(Guid asteroidBelt"
2026-06-16 11:00:56 +01:00
} ;
var hits = checkedFiles
. Where ( File . Exists )
. SelectMany ( path = > File . ReadLines ( path )
. Select ( ( line , index ) = > new { Path = path , LineNumber = index + 1 , Line = line } ) )
. Where ( line = > forbiddenSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, line.Path)}:{line.LineNumber}: {line.Line.Trim()}" )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
2026-06-16 15:08:00 +01:00
"Runtime behavior body references must stay on typed BodyKey surfaces, with Zone owning key resolution and behaviors no longer storing raw GUID body ids: " +
2026-06-16 11:00:56 +01:00
string . Join ( "; " , hits ) ) ;
}
2026-06-16 14:22:52 +01:00
var zoneSourcePath = Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Zone.cs" ) ;
var zoneSource = File . Exists ( zoneSourcePath )
? File . ReadAllText ( zoneSourcePath )
: throw new InvalidOperationException ( "Cannot verify body/orbit key ownership; Zone source is missing." ) ;
var requiredZoneSymbols = new [ ]
{
"public const string OrbitKeyPrefix" ,
"public const string BodyKeyPrefix" ,
"public string BodyKey { get; }" ,
"public string OrbitKey { get; }" ,
"public string ParentOrbitKey { get; }" ,
2026-06-16 15:08:00 +01:00
"public string GetBodyKey(Guid bodyId)" ,
"public bool TryGetPlanet(string bodyKey, out Planet planet)" ,
"public bool TryGetAsteroidBelt(string bodyKey, out AsteroidBelt belt)"
2026-06-16 14:22:52 +01:00
} ;
var missingZoneSymbols = requiredZoneSymbols
. Where ( symbol = > ! zoneSource . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingZoneSymbols . Length > 0 )
{
throw new InvalidOperationException (
"Zone runtime body/orbit objects must own typed projection key surfaces: " +
string . Join ( ", " , missingZoneSymbols ) ) ;
}
2026-06-16 15:08:00 +01:00
var requiredBehaviorSymbols = new Dictionary < string , string [ ] >
{
[Path.Combine(root, "Assets", "Scripts", "ServerShared", "Behaviors", "ResourceScanner.cs")] = new [ ]
{
"private string _scanTargetBodyKey = \"\";" ,
"public string ScanTargetBodyKey" ,
"Entity.Zone.TryGetAsteroidBelt(ScanTargetBodyKey, out var belt)" ,
"Entity.Zone.TryGetPlanet(ScanTargetBodyKey, out var planet)" ,
"RestoreRuntimeState(" ,
"string scanTargetBodyKey"
} ,
[Path.Combine(root, "Assets", "Scripts", "ServerShared", "Behaviors", "MiningTool.cs")] = new [ ]
{
"public string AsteroidBeltBodyKey = \"\";" ,
"Entity.Zone.TryGetAsteroidBelt(AsteroidBeltBodyKey, out var belt)" ,
"Entity.Zone.AsteroidExists(AsteroidBeltBodyKey, Asteroid)" ,
"Entity.Zone.MineAsteroid(" ,
"AsteroidBeltBodyKey," ,
"string asteroidBeltBodyKey"
}
} ;
var missingBehaviorSymbols = requiredBehaviorSymbols
. Where ( pair = > ! File . Exists ( pair . Key ) | | pair . Value . Any ( symbol = > ! File . ReadAllText ( pair . Key ) . Contains ( symbol , StringComparison . Ordinal ) ) )
. SelectMany ( pair = >
{
var text = File . Exists ( pair . Key ) ? File . ReadAllText ( pair . Key ) : "" ;
return pair . Value
. Where ( symbol = > ! text . Contains ( symbol , StringComparison . Ordinal ) )
. Select ( symbol = > $"{Path.GetRelativePath(root, pair.Key)}: missing {symbol}" ) ;
} )
. ToArray ( ) ;
if ( missingBehaviorSymbols . Length > 0 )
{
throw new InvalidOperationException (
"ResourceScanner and MiningTool must own typed body-key runtime references rather than raw GUID fields: " +
string . Join ( "; " , missingBehaviorSymbols ) ) ;
}
2026-06-16 11:00:56 +01:00
}
2026-06-16 19:19:05 +01:00
static void RequireNoDeadRuntimeProjectionCaches ( string root )
{
var path = Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "RuntimeProjection" , "ReflectionExtensions.cs" ) ;
if ( ! File . Exists ( path ) )
return ;
var forbiddenSymbols = new [ ]
{
"GetAllInterfaceClasses(" ,
"GetParentTypes(" ,
"GetAllChildClasses(" ,
"GetAllGenericChildClasses(" ,
"IsAssignableToGenericType(" ,
"GetFullName(" ,
"InterfaceClasses" ,
"ParentTypes" ,
"ChildClasses" ,
"GenericChildClasses" ,
"AppDomain.CurrentDomain.GetAssemblies()"
} ;
var hits = File . ReadLines ( path )
. Select ( ( line , index ) = > new { Line = line , LineNumber = index + 1 } )
. Where ( line = > forbiddenSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"Assets/Scripts/ServerShared/RuntimeProjection/ReflectionExtensions.cs:{line.LineNumber}: {line.Line.Trim()}" )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"Dead runtime-projection reflection caches should stay deleted; keep only the live string-formatting helpers: " +
string . Join ( "; " , hits ) ) ;
}
}
2026-06-16 19:24:01 +01:00
static void RequireNoDeadInspectorMetadata ( string root )
{
var checkedFiles = new [ ]
{
Path . Combine ( root , "Assets" , "Scripts" , "Gameplay" , "FieldDriver.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Corporations.cs" ) ,
2026-06-16 19:38:02 +01:00
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Behaviors" , "AetherDrive.cs" ) ,
2026-06-16 19:24:01 +01:00
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Behaviors" , "StatModifier.cs" ) ,
2026-06-16 19:38:02 +01:00
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Behaviors" , "VelocityLimit.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "ExponentialCurve.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "RuntimeGeometry.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "UI" , "Properties Panel" , "PropertiesPanel.cs" )
2026-06-16 19:24:01 +01:00
} ;
var forbiddenSymbols = new [ ]
{
2026-06-16 19:38:02 +01:00
"InspectableAttribute" ,
2026-06-16 19:24:01 +01:00
"PreferredInspectorAttribute" ,
"InspectableTextAttribute" ,
"InspectablePrefabAttribute" ,
"InspectableTextureAttribute" ,
"InspectableTextAssetAttribute" ,
"InspectableTemperatureAttribute" ,
"InspectableAnimationCurveAttribute" ,
"InspectableColorAttribute" ,
"InspectableSoundBankAttribute" ,
"InspectableAudioParameterAttribute" ,
"InspectableSchematicShapeAttribute" ,
"InspectableEnumValuesAttribute" ,
"InspectableRangedFloatAttribute" ,
"InspectableRangedIntAttribute" ,
"OrderAttribute" ,
2026-06-16 19:38:02 +01:00
"EntityTypeRestrictionAttribute" ,
2026-06-16 19:24:01 +01:00
"InspectorHeaderAttribute" ,
2026-06-16 19:38:02 +01:00
"[Inspectable" ,
2026-06-16 19:24:01 +01:00
"[InspectableText" ,
"[InspectablePrefab" ,
"[InspectableTexture" ,
"[InspectableTextAsset" ,
"[InspectableTemperature" ,
"[InspectableAnimationCurve" ,
"[InspectableColor" ,
"[InspectableSoundBank" ,
"[InspectableAudioParameter" ,
"[InspectableSchematicShape" ,
"[InspectableEnumValues" ,
"[InspectableRangedFloat" ,
"[InspectableRangedInt" ,
"[Order(" ,
2026-06-16 19:38:02 +01:00
"EntityTypeRestriction(" ,
2026-06-16 19:24:01 +01:00
"[InspectorHeader("
} ;
var hits = checkedFiles
. Where ( File . Exists )
. SelectMany ( path = > File . ReadLines ( path )
. Select ( ( line , index ) = > new { Path = path , LineNumber = index + 1 , Line = line } ) )
. Where ( line = > forbiddenSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, line.Path)}:{line.LineNumber}: {line.Line.Trim()}" )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
2026-06-16 19:38:02 +01:00
"Dead inspector-specialization metadata should stay deleted; no generic Inspectable attribute path should remain in live runtime code: " +
2026-06-16 19:24:01 +01:00
string . Join ( "; " , hits ) ) ;
}
2026-06-16 19:38:02 +01:00
var deletedFiles = new [ ]
{
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "RuntimeProjection" , "Attributes.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Attributes.cs" )
} ;
var stillPresent = deletedFiles . Where ( File . Exists ) . Select ( path = > Path . GetRelativePath ( root , path ) ) . ToArray ( ) ;
if ( stillPresent . Length > 0 )
{
throw new InvalidOperationException (
"Dead inspector attribute definition files should be deleted once the generic reflection inspector path is gone: " +
string . Join ( ", " , stillPresent ) ) ;
}
2026-06-16 19:24:01 +01:00
}
2026-06-16 15:54:18 +01:00
static void RequireTypedOrbitTaskKeys ( string root )
{
var checkedFiles = new [ ]
{
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Zone.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Agents" , "States" , "MoveTo.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Agents" , "Tasks" , "PatrolOrbits.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Agents" , "Tasks" , "StationTowing.cs" )
} ;
var forbiddenSymbols = new [ ]
{
"public Guid Orbit { get; set; }" ,
"Guid[] Circuit" ,
"public Guid OrbitParent" ,
"Select(x => x.Key)"
} ;
var hits = checkedFiles
. Where ( File . Exists )
. SelectMany ( path = > File . ReadLines ( path )
. Select ( ( line , index ) = > new { Path = path , LineNumber = index + 1 , Line = line } ) )
. Where ( line = > forbiddenSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, line.Path)}:{line.LineNumber}: {line.Line.Trim()}" )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"Orbit-targeting agent tasks and move states must stay on typed OrbitKey surfaces, with Zone owning orbit-key resolution: " +
string . Join ( "; " , hits ) ) ;
}
var zoneSourcePath = Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Zone.cs" ) ;
var zoneSource = File . Exists ( zoneSourcePath )
? File . ReadAllText ( zoneSourcePath )
: throw new InvalidOperationException ( "Cannot verify orbit-key task ownership; Zone source is missing." ) ;
var requiredZoneSymbols = new [ ]
{
"public bool TryGetOrbit(string orbitKey, out Orbit orbit)" ,
"public float2 GetOrbitPosition(string orbitKey)"
} ;
var missingZoneSymbols = requiredZoneSymbols
. Where ( symbol = > ! zoneSource . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingZoneSymbols . Length > 0 )
{
throw new InvalidOperationException (
"Zone must own typed orbit-key parsing and resolution for agent/runtime orbit movement: " +
string . Join ( ", " , missingZoneSymbols ) ) ;
}
var requiredTaskSymbols = new Dictionary < string , string [ ] >
{
[Path.Combine(root, "Assets", "Scripts", "ServerShared", "Agents", "States", "MoveTo.cs")] = new [ ]
{
"public string OrbitKey { get; set; } = \"\";" ,
"_agent.Ship.Zone.GetOrbitPosition(OrbitKey)"
} ,
[Path.Combine(root, "Assets", "Scripts", "ServerShared", "Agents", "Tasks", "PatrolOrbits.cs")] = new [ ]
{
"public string[] Circuit = Array.Empty<string>();" ,
"public string CurrentTarget" ,
"patrolMoveState.OrbitKey = CurrentTarget"
} ,
[Path.Combine(root, "Assets", "Scripts", "ServerShared", "Agents", "Tasks", "StationTowing.cs")] = new [ ]
{
"public string OrbitParentKey = \"\";"
}
} ;
var missingTaskSymbols = requiredTaskSymbols
. Where ( pair = > ! File . Exists ( pair . Key ) | | pair . Value . Any ( symbol = > ! File . ReadAllText ( pair . Key ) . Contains ( symbol , StringComparison . Ordinal ) ) )
. SelectMany ( pair = >
{
var text = File . Exists ( pair . Key ) ? File . ReadAllText ( pair . Key ) : "" ;
return pair . Value
. Where ( symbol = > ! text . Contains ( symbol , StringComparison . Ordinal ) )
. Select ( symbol = > $"{Path.GetRelativePath(root, pair.Key)}: missing {symbol}" ) ;
} )
. ToArray ( ) ;
if ( missingTaskSymbols . Length > 0 )
{
throw new InvalidOperationException (
"Orbit-targeting agent tasks must retain typed orbit keys rather than raw GUIDs: " +
string . Join ( "; " , missingTaskSymbols ) ) ;
}
}
2026-06-16 16:07:20 +01:00
static void RequireTypedOrbitalEntityOrbitKeys ( string root )
{
var checkedFiles = new [ ]
{
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "OrbitalEntity.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "EntityConstructionBlueprintProjector.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "LoadoutGenerator.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "ZoneGenerator.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "Gameplay" , "ActionGameManager.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Zone.cs" )
} ;
var forbiddenSymbols = new [ ]
{
"public Guid OrbitId;" ,
"public Guid Orbit;" ,
"Orbit = orbital.OrbitId" ,
"blueprint.Orbit," ,
"Zone.Orbits[orbital.OrbitId]" ,
"GetOrbitPosition(OrbitId)" ,
"GetOrbitVelocity(OrbitId)" ,
"new OrbitalEntity(ItemManager, null, hull, Guid.Empty"
} ;
var hits = checkedFiles
. Where ( File . Exists )
. SelectMany ( path = > File . ReadLines ( path )
. Select ( ( line , index ) = > new { Path = path , LineNumber = index + 1 , Line = line } ) )
. Where ( line = > forbiddenSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, line.Path)}:{line.LineNumber}: {line.Line.Trim()}" )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"Orbital runtime entities and construction blueprints must retain typed OrbitKey state, with Zone owning orbit-key resolution: " +
string . Join ( "; " , hits ) ) ;
}
var requiredSymbols = new Dictionary < string , string [ ] >
{
[Path.Combine(root, "Assets", "Scripts", "ServerShared", "OrbitalEntity.cs")] = new [ ]
{
"public string OrbitKey = \"\";" ,
"OrbitKey = orbitKey ?? \"\";" ,
"Zone.GetOrbitPosition(OrbitKey)" ,
"Zone.GetOrbitVelocity(OrbitKey)"
} ,
[Path.Combine(root, "Assets", "Scripts", "ServerShared", "EntityConstructionBlueprintProjector.cs")] = new [ ]
{
"OrbitKey = orbital.OrbitKey," ,
"blueprint.OrbitKey" ,
"public string OrbitKey = \"\";"
} ,
[Path.Combine(root, "Assets", "Scripts", "ServerShared", "LoadoutGenerator.cs")] = new [ ]
{
"new OrbitalEntity(ItemManager, null, hull, \"\", ItemManager.GameplaySettings.DefaultEntitySettings)"
} ,
[Path.Combine(root, "Assets", "Scripts", "ServerShared", "ZoneGenerator.cs")] = new [ ]
{
2026-06-16 16:57:18 +01:00
"turret.OrbitKey = turretOrbit.OrbitKey;" ,
"station.OrbitKey = lagrangeOrbit.OrbitKey;"
2026-06-16 16:07:20 +01:00
} ,
[Path.Combine(root, "Assets", "Scripts", "Gameplay", "ActionGameManager.cs")] = new [ ]
{
"Zone.TryGetOrbit(orbital.OrbitKey, out var orbit)" ,
"planet => planet.OrbitKey == parentOrbitKey"
} ,
[Path.Combine(root, "Assets", "Scripts", "ServerShared", "Zone.cs")] = new [ ]
{
"public float2 GetOrbitVelocity(string orbitKey)"
}
} ;
var missingSymbols = requiredSymbols
. Where ( pair = > ! File . Exists ( pair . Key ) | | pair . Value . Any ( symbol = > ! File . ReadAllText ( pair . Key ) . Contains ( symbol , StringComparison . Ordinal ) ) )
. SelectMany ( pair = >
{
var text = File . Exists ( pair . Key ) ? File . ReadAllText ( pair . Key ) : "" ;
return pair . Value
. Where ( symbol = > ! text . Contains ( symbol , StringComparison . Ordinal ) )
. Select ( symbol = > $"{Path.GetRelativePath(root, pair.Key)}: missing {symbol}" ) ;
} )
. ToArray ( ) ;
if ( missingSymbols . Length > 0 )
{
throw new InvalidOperationException (
"Orbital runtime seam must stay on typed orbit keys through the entity owner, blueprint projector, and docking path: " +
string . Join ( "; " , missingSymbols ) ) ;
}
}
2026-06-16 16:13:54 +01:00
static void RequireTypedOrbitConsumerKeys ( string root )
{
var checkedFiles = new [ ]
{
Path . Combine ( root , "Assets" , "Scripts" , "Gameplay" , "ActionGameManager.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "Zone Display" , "ZoneRenderer.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Behaviors" , "ResourceScanner.cs" )
} ;
var forbiddenSymbols = new [ ]
{
"planet => planet.OrbitId == followOrbit" ,
"planet => planet.OrbitId == rootOrbit" ,
"body => body.OrbitId == orbit.ID" ,
"body => body.Orbit == orbit.ID" ,
"GetOrbitPosition(planetInstance.OrbitId)" ,
"Zone.Orbits[planetInstance.OrbitId].Parent" ,
"zone.Orbits[belt.Orbit]" ,
"GetOrbitPosition(planet.OrbitId)"
} ;
var hits = checkedFiles
. Where ( File . Exists )
. SelectMany ( path = > File . ReadLines ( path )
. Select ( ( line , index ) = > new { Path = path , LineNumber = index + 1 , Line = line } ) )
. Where ( line = > forbiddenSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, line.Path)}:{line.LineNumber}: {line.Line.Trim()}" )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"Orbit consumer edges must read typed OrbitKey surfaces rather than wrapper GUID fields in gameplay, renderer, and sensor code: " +
string . Join ( "; " , hits ) ) ;
}
var requiredSymbols = new Dictionary < string , string [ ] >
{
[Path.Combine(root, "Assets", "Scripts", "Gameplay", "ActionGameManager.cs")] = new [ ]
{
"Zone.Orbits.Values.MinBy(orbit => lengthsq(Zone.GetOrbitPosition(orbit.OrbitKey) - entityPosition))" ,
"planet => planet.OrbitKey == followOrbit.OrbitKey" ,
"planet => planet.OrbitKey == rootOrbit.OrbitKey" ,
"Zone.TryGetOrbit(rootOrbit.ParentOrbitKey, out var parentOrbit)" ,
"Zone.GetOrbitPosition(followOrbit.OrbitKey)" ,
"Zone.GetOrbitPosition(rootOrbit.OrbitKey)"
} ,
[Path.Combine(root, "Assets", "Scripts", "Zone Display", "ZoneRenderer.cs")] = new [ ]
{
"body => body.OrbitKey == orbit.OrbitKey" ,
"Zone.GetOrbitPosition(planetInstance.OrbitKey)" ,
"Zone.GetOrbitPosition(planetInstance.Orbit.ParentOrbitKey)"
} ,
[Path.Combine(root, "Assets", "Scripts", "ServerShared", "Behaviors", "ResourceScanner.cs")] = new [ ]
{
"Entity.Zone.GetOrbitPosition(planet.OrbitKey)"
}
} ;
var missingSymbols = requiredSymbols
. Where ( pair = > ! File . Exists ( pair . Key ) | | pair . Value . Any ( symbol = > ! File . ReadAllText ( pair . Key ) . Contains ( symbol , StringComparison . Ordinal ) ) )
. SelectMany ( pair = >
{
var text = File . Exists ( pair . Key ) ? File . ReadAllText ( pair . Key ) : "" ;
return pair . Value
. Where ( symbol = > ! text . Contains ( symbol , StringComparison . Ordinal ) )
. Select ( symbol = > $"{Path.GetRelativePath(root, pair.Key)}: missing {symbol}" ) ;
} )
. ToArray ( ) ;
if ( missingSymbols . Length > 0 )
{
throw new InvalidOperationException (
"Orbit consumer edges must stay keyed at the public runtime wrapper surface: " +
string . Join ( "; " , missingSymbols ) ) ;
}
}
2026-06-16 16:20:30 +01:00
static void RequireKeyedOrbitRuntimeWrappers ( string root )
{
var zoneSourcePath = Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Zone.cs" ) ;
var zoneSource = File . Exists ( zoneSourcePath )
? File . ReadAllText ( zoneSourcePath )
: throw new InvalidOperationException ( "Cannot verify keyed orbit runtime wrappers; Zone source is missing." ) ;
var forbiddenSymbols = new [ ]
{
"public Guid OrbitId { get; }" ,
"public Guid Orbit { get; }" ,
"OrbitId = data.Orbit;" ,
"Orbit = data.Orbit;" ,
"AsteroidBelts[belt.ID] = new AsteroidBelt(belt);" ,
"var orbit = Orbits[belt.Orbit];"
} ;
var hits = forbiddenSymbols
. Where ( symbol = > zoneSource . Contains ( symbol , StringComparison . Ordinal ) )
. Select ( symbol = > $"Assets/Scripts/ServerShared/Zone.cs: contains {symbol}" )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"Planet and asteroid-belt runtime wrappers must not publish wrapper orbit GUID fields once keyed/object orbit surfaces exist: " +
string . Join ( "; " , hits ) ) ;
}
var requiredSymbols = new [ ]
{
"public Orbit Orbit;" ,
"public Orbit Orbit { get; }" ,
2026-06-16 16:57:18 +01:00
"var runtimeBelt = new AsteroidBelt(belt, Orbits[belt.OrbitKey]);" ,
2026-06-16 16:48:00 +01:00
"AsteroidBelts[runtimeBelt.BodyKey] = runtimeBelt;" ,
2026-06-16 16:20:30 +01:00
"belt.NewOrbitPosition = GetOrbitPosition(belt.Orbit.ParentOrbitKey);" ,
"public AsteroidBelt(AsteroidBeltConstructionData data, Orbit orbit)" ,
"Orbit = orbit;"
} ;
var missingSymbols = requiredSymbols
. Where ( symbol = > ! zoneSource . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingSymbols . Length > 0 )
{
throw new InvalidOperationException (
"Planet and asteroid-belt runtime wrappers must keep orbit authority on Orbit objects plus OrbitKey surfaces: " +
string . Join ( ", " , missingSymbols ) ) ;
}
}
2026-06-16 11:22:18 +01:00
static void RequireTypedFactionShellLinks ( string root )
{
var checkedFiles = new [ ]
{
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Corporations.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Galaxy.cs" )
} ;
var forbiddenSymbols = new [ ]
{
"Guid GeonameFile" ,
"Guid BossHull" ,
"GeonameFile =" ,
"BossHull =" ,
"ParseOptionalLegacyId" ,
"GeonameFileLegacyId" ,
"BossHullLegacyId" ,
2026-06-16 12:31:48 +01:00
".BossHull != Guid.Empty" ,
"public Guid ID" ,
"ID = ParseLegacyId" ,
"ParseLegacyId(corporation.LegacyId"
2026-06-16 11:22:18 +01:00
} ;
var hits = checkedFiles
. Where ( File . Exists )
. SelectMany ( path = > File . ReadLines ( path )
. Select ( ( line , index ) = > new { Path = path , LineNumber = index + 1 , Line = line } ) )
. Where ( line = > forbiddenSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, line.Path)}:{line.LineNumber}: {line.Line.Trim()}" )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"Temporary Faction shell links must use typed key fields, not geoname/boss-hull legacy GUID projections: " +
string . Join ( "; " , hits ) ) ;
}
}
2026-06-16 16:27:33 +01:00
static void RequireNativeZoneKeyResolution ( string root )
{
var zoneSourcePath = Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Zone.cs" ) ;
var zoneSource = File . Exists ( zoneSourcePath )
? File . ReadAllText ( zoneSourcePath )
: throw new InvalidOperationException ( "Cannot verify native Zone key resolution; Zone source is missing." ) ;
var forbiddenSymbols = new [ ]
{
"public static Guid ParseOrbitGuid(string orbitKey)" ,
"public static Guid ParseBodyGuid(string bodyKey)" ,
"PlanetInstances.TryGetValue(ParseBodyGuid(bodyKey), out planet)" ,
"AsteroidBelts.TryGetValue(ParseBodyGuid(bodyKey), out belt)" ,
"Orbits.TryGetValue(ParseOrbitGuid(orbitKey), out orbit)" ,
"return GetOrbitPosition(ParseOrbitGuid(orbitKey));" ,
2026-06-16 16:48:00 +01:00
"return GetOrbitVelocity(ParseOrbitGuid(orbitKey));" ,
"public float2 GetOrbitPosition(Guid orbitID)" ,
"public float2 GetOrbitVelocity(Guid orbit)"
2026-06-16 16:27:33 +01:00
} ;
var hits = forbiddenSymbols
. Where ( symbol = > zoneSource . Contains ( symbol , StringComparison . Ordinal ) )
. Select ( symbol = > $"Assets/Scripts/ServerShared/Zone.cs: contains {symbol}" )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"Zone key-facing APIs must resolve typed body/orbit keys natively instead of reparsing GUIDs from those keys: " +
string . Join ( "; " , hits ) ) ;
}
var requiredSymbols = new [ ]
{
2026-06-16 16:48:00 +01:00
"public Dictionary<string, Planet> PlanetInstances = new Dictionary<string, Planet>(StringComparer.Ordinal);" ,
"public Dictionary<string, Orbit> Orbits = new Dictionary<string, Orbit>(StringComparer.Ordinal);" ,
"public Dictionary<string, AsteroidBelt> AsteroidBelts = new Dictionary<string, AsteroidBelt>(StringComparer.Ordinal);" ,
"private readonly Dictionary<Guid, Planet> _planetsById = new Dictionary<Guid, Planet>();" ,
"private readonly Dictionary<Guid, AsteroidBelt> _asteroidBeltsById = new Dictionary<Guid, AsteroidBelt>();" ,
"PlanetInstances[runtimeSun.BodyKey] = runtimeSun;" ,
"_planetsById[runtimeSun.ID] = runtimeSun;" ,
"PlanetInstances[runtimeGas.BodyKey] = runtimeGas;" ,
"_planetsById[runtimeGas.ID] = runtimeGas;" ,
"PlanetInstances[runtimePlanet.BodyKey] = runtimePlanet;" ,
"_planetsById[runtimePlanet.ID] = runtimePlanet;" ,
"AsteroidBelts[runtimeBelt.BodyKey] = runtimeBelt;" ,
"_asteroidBeltsById[runtimeBelt.ID] = runtimeBelt;" ,
"Orbits[runtimeOrbit.OrbitKey] = runtimeOrbit;" ,
"return PlanetInstances.TryGetValue(bodyKey ?? \"\", out planet);" ,
"return AsteroidBelts.TryGetValue(bodyKey ?? \"\", out belt);" ,
"return Orbits.TryGetValue(orbitKey ?? \"\", out orbit);" ,
"if (_planetsById.TryGetValue(bodyId, out var planet))" ,
"if (_asteroidBeltsById.TryGetValue(bodyId, out var belt))" ,
"var parentPosition = string.IsNullOrWhiteSpace(orbit.ParentOrbitKey)" ,
": GetOrbitPosition(orbit.ParentOrbitKey);" ,
2026-06-16 16:57:18 +01:00
"return TryGetOrbit(orbitKey, out var orbit) ? orbit.Velocity : float2.zero;" ,
"var runtimeBelt = new AsteroidBelt(belt, Orbits[belt.OrbitKey]);" ,
"var runtimeSun = new Sun(settings, sun, Orbits[planet.OrbitKey]);" ,
"var runtimeGas = new GasGiant(settings, gas, Orbits[planet.OrbitKey]);" ,
"var runtimePlanet = new Planet(settings, planet, Orbits[planet.OrbitKey]);" ,
"BodyKey = data.BodyKey ?? \"\";" ,
"OrbitKey = data.OrbitKey ?? \"\";" ,
"ParentOrbitKey = data.ParentOrbitKey ?? \"\";"
2026-06-16 16:27:33 +01:00
} ;
var missingSymbols = requiredSymbols
. Where ( symbol = > ! zoneSource . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingSymbols . Length > 0 )
{
throw new InvalidOperationException (
"Zone must keep native key-indexed runtime lookup tables for body and orbit resolution: " +
string . Join ( ", " , missingSymbols ) ) ;
}
}
2026-06-16 16:48:00 +01:00
static void RequireTypedZoneRuntimeCollections ( string root )
{
var zoneSourcePath = Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Zone.cs" ) ;
var zoneRendererPath = Path . Combine ( root , "Assets" , "Scripts" , "Zone Display" , "ZoneRenderer.cs" ) ;
var zoneSource = File . Exists ( zoneSourcePath )
? File . ReadAllText ( zoneSourcePath )
: throw new InvalidOperationException ( "Cannot verify typed Zone runtime collections; Zone source is missing." ) ;
var zoneRenderer = File . Exists ( zoneRendererPath )
? File . ReadAllText ( zoneRendererPath )
: throw new InvalidOperationException ( "Cannot verify typed Zone runtime collections; ZoneRenderer source is missing." ) ;
var forbiddenZoneSymbols = new [ ]
{
"public Dictionary<Guid, Planet> PlanetInstances" ,
"public Dictionary<Guid, Orbit> Orbits" ,
"public Dictionary<Guid, AsteroidBelt> AsteroidBelts" ,
"private HashSet<Guid> _updatedOrbits" ,
"orbit.Value.Position = GetOrbitPosition(orbit.Key);"
} ;
var zoneHits = forbiddenZoneSymbols
. Where ( symbol = > zoneSource . Contains ( symbol , StringComparison . Ordinal ) )
. Select ( symbol = > $"Assets/Scripts/ServerShared/Zone.cs: contains {symbol}" ) ;
var forbiddenRendererSymbols = new [ ]
{
"public Dictionary<Guid, PlanetObject> Planets" ,
"private Dictionary<Guid, AsteroidBeltUI> _beltObjects" ,
"private Dictionary<Guid, InstancedMesh[]> _beltMeshes" ,
"private Dictionary<Guid, Matrix4x4[][]> _beltMatrices" ,
"_beltMeshes[runtimeBelt.ID] =" ,
"_beltObjects[runtimeBelt.ID] =" ,
"Planets[planetInstance.ID] = planet;"
} ;
var rendererHits = forbiddenRendererSymbols
. Where ( symbol = > zoneRenderer . Contains ( symbol , StringComparison . Ordinal ) )
. Select ( symbol = > $"Assets/Scripts/Zone Display/ZoneRenderer.cs: contains {symbol}" ) ;
var hits = zoneHits . Concat ( rendererHits ) . ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"Zone runtime collections and renderer caches must keep typed OrbitKey/BodyKey ownership rather than Guid dictionary keys: " +
string . Join ( "; " , hits ) ) ;
}
var requiredZoneSymbols = new [ ]
{
"public Dictionary<string, Planet> PlanetInstances = new Dictionary<string, Planet>(StringComparer.Ordinal);" ,
"public Dictionary<string, Orbit> Orbits = new Dictionary<string, Orbit>(StringComparer.Ordinal);" ,
"public Dictionary<string, AsteroidBelt> AsteroidBelts = new Dictionary<string, AsteroidBelt>(StringComparer.Ordinal);" ,
"private HashSet<string> _updatedOrbits = new HashSet<string>(StringComparer.Ordinal);" ,
"foreach (var orbit in Orbits.Values)" ,
"orbit.Position = GetOrbitPosition(orbit.OrbitKey);"
} ;
var missingZoneSymbols = requiredZoneSymbols
. Where ( symbol = > ! zoneSource . Contains ( symbol , StringComparison . Ordinal ) )
. Select ( symbol = > $"Assets/Scripts/ServerShared/Zone.cs: missing {symbol}" ) ;
var requiredRendererSymbols = new [ ]
{
"public Dictionary<string, PlanetObject> Planets = new Dictionary<string, PlanetObject>(StringComparer.Ordinal);" ,
"private Dictionary<string, AsteroidBeltUI> _beltObjects = new Dictionary<string, AsteroidBeltUI>(StringComparer.Ordinal);" ,
"private Dictionary<string, InstancedMesh[]> _beltMeshes = new Dictionary<string, InstancedMesh[]>(StringComparer.Ordinal);" ,
"private Dictionary<string, Matrix4x4[][]> _beltMatrices = new Dictionary<string, Matrix4x4[][]>(StringComparer.Ordinal);" ,
"_beltMeshes[runtimeBelt.BodyKey] = meshes.ToArray();" ,
"_beltObjects[runtimeBelt.BodyKey] = belt;" ,
"Planets[planetInstance.BodyKey] = planet;"
} ;
var missingRendererSymbols = requiredRendererSymbols
. Where ( symbol = > ! zoneRenderer . Contains ( symbol , StringComparison . Ordinal ) )
. Select ( symbol = > $"Assets/Scripts/Zone Display/ZoneRenderer.cs: missing {symbol}" ) ;
var missing = missingZoneSymbols . Concat ( missingRendererSymbols ) . ToArray ( ) ;
if ( missing . Length > 0 )
{
throw new InvalidOperationException (
"Zone runtime collections and renderer caches must expose typed keyed ownership end to end: " +
string . Join ( "; " , missing ) ) ;
}
}
2026-06-16 16:57:18 +01:00
static void RequireTypedZoneConstructionKeys ( string root )
{
var checkedFiles = new [ ]
{
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "ZoneConstructionData.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "ZoneGenerator.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Zone.cs" )
} ;
var forbiddenSymbols = new [ ]
{
"var runtimeBelt = new AsteroidBelt(belt, Orbits[OrbitKey(belt.Orbit)]);" ,
"var runtimeSun = new Sun(settings, sun, Orbits[OrbitKey(planet.Orbit)]);" ,
"var runtimeGas = new GasGiant(settings, gas, Orbits[OrbitKey(planet.Orbit)]);" ,
"var runtimePlanet = new Planet(settings, planet, Orbits[OrbitKey(planet.Orbit)]);" ,
"turret.OrbitKey = Zone.OrbitKey(turretOrbit.ID);" ,
"station.OrbitKey = Zone.OrbitKey(lagrangeOrbit.ID);"
} ;
var hits = checkedFiles
. Where ( File . Exists )
. SelectMany ( path = > File . ReadLines ( path )
. Select ( ( line , index ) = > new { Path = path , LineNumber = index + 1 , Line = line } ) )
. Where ( line = > forbiddenSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, line.Path)}:{line.LineNumber}: {line.Line.Trim()}" )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"Zone construction and generation must hand orbit/body identity through typed key fields instead of recomputing runtime authority from legacy GUID refs: " +
string . Join ( "; " , hits ) ) ;
}
var requiredSymbols = new Dictionary < string , string [ ] >
{
[Path.Combine(root, "Assets", "Scripts", "ServerShared", "ZoneConstructionData.cs")] = new [ ]
{
"public string BodyKey = \"\";" ,
"public string OrbitKey = \"\";" ,
"public string ParentOrbitKey = \"\";"
} ,
[Path.Combine(root, "Assets", "Scripts", "ServerShared", "ZoneGenerator.cs")] = new [ ]
{
"data.OrbitKey = Zone.OrbitKey(data.ID);" ,
"data.ParentOrbitKey = orbitInverseMap[data].Parent != null" ,
"planetData.BodyKey = Zone.BodyKey(planetData.ID);" ,
"planetData.OrbitKey = orbitMap[planet].OrbitKey;" ,
"lagrangeOrbit.OrbitKey = Zone.OrbitKey(lagrangeOrbit.ID);" ,
"ParentOrbitKey = baseOrbit.ParentOrbitKey," ,
"turretOrbit.OrbitKey = Zone.OrbitKey(turretOrbit.ID);" ,
"ParentOrbitKey = orbit.ParentOrbitKey," ,
"turret.OrbitKey = turretOrbit.OrbitKey;" ,
"station.OrbitKey = lagrangeOrbit.OrbitKey;"
} ,
[Path.Combine(root, "Assets", "Scripts", "ServerShared", "Zone.cs")] = new [ ]
{
"var runtimeBelt = new AsteroidBelt(belt, Orbits[belt.OrbitKey]);" ,
"var runtimeSun = new Sun(settings, sun, Orbits[planet.OrbitKey]);" ,
"var runtimeGas = new GasGiant(settings, gas, Orbits[planet.OrbitKey]);" ,
"var runtimePlanet = new Planet(settings, planet, Orbits[planet.OrbitKey]);" ,
"BodyKey = data.BodyKey ?? \"\";" ,
"OrbitKey = data.OrbitKey ?? \"\";" ,
"ParentOrbitKey = data.ParentOrbitKey ?? \"\";"
}
} ;
var missingSymbols = requiredSymbols
. Where ( pair = > ! File . Exists ( pair . Key ) | | pair . Value . Any ( symbol = > ! File . ReadAllText ( pair . Key ) . Contains ( symbol , StringComparison . Ordinal ) ) )
. SelectMany ( pair = >
{
var text = File . Exists ( pair . Key ) ? File . ReadAllText ( pair . Key ) : "" ;
return pair . Value
. Where ( symbol = > ! text . Contains ( symbol , StringComparison . Ordinal ) )
. Select ( symbol = > $"{Path.GetRelativePath(root, pair.Key)}: missing {symbol}" ) ;
} )
. ToArray ( ) ;
if ( missingSymbols . Length > 0 )
{
throw new InvalidOperationException (
"Zone construction inputs and generator seams must retain typed orbit/body keys as the handoff authority: " +
string . Join ( "; " , missingSymbols ) ) ;
}
}
2026-06-16 17:03:59 +01:00
static void RequireTypedZoneStateSnapshotKeys ( string root )
{
var checkedFiles = new [ ]
{
Path . Combine ( root , "Aetheria.State" , "Documents" , "AetheriaRuntimeStateDocuments.cs" ) ,
Path . Combine ( root , "Aetheria.State" , "AetheriaRuntimeCommitLogApplier.cs" ) ,
Path . Combine ( root , "Packages" , "org.gamecult.aetheria.state" , "Runtime" , "AetheriaRuntimeCatalogSnapshot.cs" ) ,
Path . Combine ( root , "Packages" , "org.gamecult.aetheria.state" , "Runtime" , "AetheriaRuntimeCatalogStore.cs" )
} ;
var forbiddenSymbols = new [ ]
{
"public string OrbitId { get; set; } = \"\";" ,
"public string ParentId { get; set; } = \"\";" ,
"public string BodyId { get; set; } = \"\";" ,
"public AetheriaRuntimeOrbitSnapshot(string orbitId, string parentId" ,
"string bodyId," ,
"string orbitId," ,
"OrbitId = orbit.OrbitKey ?? \"\"," ,
"ParentId = orbit.ParentOrbitKey ?? \"\"," ,
"BodyId = body.BodyKey ?? \"\"," ,
"var orbitId = ReadFieldString(ref reader, orbitFields, 0);" ,
"var parentId = ReadFieldString(ref reader, orbitFields, 1);" ,
"var bodyId = ReadFieldString(ref reader, bodyFields, 0);" ,
"var orbitId = ReadFieldString(ref reader, bodyFields, 3);"
} ;
var hits = checkedFiles
. Where ( File . Exists )
. SelectMany ( path = > File . ReadLines ( path )
. Select ( ( line , index ) = > new { Path = path , LineNumber = index + 1 , Line = line } ) )
. Where ( line = > forbiddenSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, line.Path)}:{line.LineNumber}: {line.Line.Trim()}" )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"Typed zone-state documents and runtime snapshots must name orbit/body identity as keys, not legacy ids: " +
string . Join ( "; " , hits ) ) ;
}
var requiredSymbols = new Dictionary < string , string [ ] >
{
[Path.Combine(root, "Aetheria.State", "Documents", "AetheriaRuntimeStateDocuments.cs")] = new [ ]
{
"public string OrbitKey { get; set; } = \"\";" ,
"public string ParentOrbitKey { get; set; } = \"\";" ,
"public string BodyKey { get; set; } = \"\";"
} ,
[Path.Combine(root, "Aetheria.State", "AetheriaRuntimeCommitLogApplier.cs")] = new [ ]
{
"OrbitKey = orbit.OrbitKey ?? \"\"," ,
"ParentOrbitKey = orbit.ParentOrbitKey ?? \"\"," ,
"BodyKey = body.BodyKey ?? \"\"," ,
"OrbitKey = body.OrbitKey ?? \"\","
} ,
[Path.Combine(root, "Packages", "org.gamecult.aetheria.state", "Runtime", "AetheriaRuntimeCatalogSnapshot.cs")] = new [ ]
{
"public AetheriaRuntimeOrbitSnapshot(string orbitKey, string parentOrbitKey" ,
"OrbitKey = orbitKey;" ,
"ParentOrbitKey = parentOrbitKey;" ,
"public string OrbitKey { get; }" ,
"public string ParentOrbitKey { get; }" ,
"BodyKey = bodyKey;" ,
"OrbitKey = orbitKey;" ,
"public string BodyKey { get; }" ,
"public string OrbitKey { get; }"
} ,
[Path.Combine(root, "Packages", "org.gamecult.aetheria.state", "Runtime", "AetheriaRuntimeCatalogStore.cs")] = new [ ]
{
"var orbitKey = ReadFieldString(ref reader, orbitFields, 0);" ,
"var parentOrbitKey = ReadFieldString(ref reader, orbitFields, 1);" ,
"var bodyKey = ReadFieldString(ref reader, bodyFields, 0);" ,
"var orbitKey = ReadFieldString(ref reader, bodyFields, 3);" ,
"new AetheriaRuntimeOrbitSnapshot(" ,
"new AetheriaRuntimeBodySnapshot("
}
} ;
var missingSymbols = requiredSymbols
. Where ( pair = > ! File . Exists ( pair . Key ) | | pair . Value . Any ( symbol = > ! File . ReadAllText ( pair . Key ) . Contains ( symbol , StringComparison . Ordinal ) ) )
. SelectMany ( pair = >
{
var text = File . Exists ( pair . Key ) ? File . ReadAllText ( pair . Key ) : "" ;
return pair . Value
. Where ( symbol = > ! text . Contains ( symbol , StringComparison . Ordinal ) )
. Select ( symbol = > $"{Path.GetRelativePath(root, pair.Key)}: missing {symbol}" ) ;
} )
. ToArray ( ) ;
if ( missingSymbols . Length > 0 )
{
throw new InvalidOperationException (
"Typed zone-state documents and runtime catalog readers must expose orbit/body key ownership explicitly: " +
string . Join ( "; " , missingSymbols ) ) ;
}
}
2026-06-16 16:32:31 +01:00
static void RequireTypedAsteroidZoneApi ( string root )
{
var zoneSourcePath = Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Zone.cs" ) ;
var zoneSource = File . Exists ( zoneSourcePath )
? File . ReadAllText ( zoneSourcePath )
: throw new InvalidOperationException ( "Cannot verify typed asteroid Zone API; Zone source is missing." ) ;
var forbiddenSymbols = new [ ]
{
"public int NearestAsteroid(Guid planetDataID, float2 position)" ,
"public bool AsteroidExists(Guid planetDataID, int asteroid)" ,
"public void MineAsteroid(Entity miner, Guid asteroidBelt, int asteroid, float damage, float efficiency, float penetration)" ,
"BeltUpdates.Add(Task.Run(() => UpdateAsteroidTransforms(belt.Key)));" ,
"private void UpdateAsteroidTransforms(Guid planetDataID)" ,
"MineAsteroid(miner, belt.ID, asteroid, damage, efficiency, penetration);"
} ;
var hits = forbiddenSymbols
. Where ( symbol = > zoneSource . Contains ( symbol , StringComparison . Ordinal ) )
. Select ( symbol = > $"Assets/Scripts/ServerShared/Zone.cs: contains {symbol}" )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"Zone asteroid helpers must keep typed body-key or runtime-object authority rather than Guid overloads: " +
string . Join ( "; " , hits ) ) ;
}
var requiredSymbols = new [ ]
{
"foreach (var belt in AsteroidBelts.Values)" ,
"BeltUpdates.Add(Task.Run(() => UpdateAsteroidTransforms(belt)));" ,
"public int NearestAsteroid(string asteroidBeltKey, float2 position)" ,
"if (!TryGetAsteroidBelt(asteroidBeltKey, out var belt))" ,
"public bool AsteroidExists(string asteroidBeltKey, int asteroid)" ,
"private void UpdateAsteroidTransforms(AsteroidBelt belt)" ,
"public void MineAsteroid(Entity miner, string asteroidBeltKey, int asteroid, float damage, float efficiency, float penetration)"
} ;
var missingSymbols = requiredSymbols
. Where ( symbol = > ! zoneSource . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingSymbols . Length > 0 )
{
throw new InvalidOperationException (
"Zone asteroid helpers must route through typed body keys or runtime belt objects: " +
string . Join ( ", " , missingSymbols ) ) ;
}
}
2026-06-16 11:43:37 +01:00
static void RequireFactionKeyIdentity ( string root )
{
var checkedFiles = new [ ]
{
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Corporations.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Entity.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Galaxy.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Zone.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Narrative" , "ZoneConstraints.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "Gameplay" , "ActionGameManager.cs" ) ,
2026-06-16 12:00:34 +01:00
Path . Combine ( root , "Assets" , "Scripts" , "UI" , "Menu" , "SectorRenderer.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "UI" , "Menu" , "SectorMap.cs" )
2026-06-16 11:43:37 +01:00
} ;
var forbiddenSymbols = new [ ]
{
"ID.GetHashCode" ,
"faction.ID == ID" ,
"Faction.ID ==" ,
"faction.ID ==" ,
".ID == TargetFaction" ,
".ID == GalaxyZone.Owner" ,
".ID != zone.Owner" ,
"pair.Key.ID" ,
"f.ID != zone.Owner" ,
2026-06-16 12:00:34 +01:00
"Owner.ID ==" ,
"zone.Owner == adjacentZone.Owner" ,
"zone.Owner != mega"
2026-06-16 11:43:37 +01:00
} ;
var hits = checkedFiles
. Where ( File . Exists )
. SelectMany ( path = > File . ReadLines ( path )
. Select ( ( line , index ) = > new { Path = path , LineNumber = index + 1 , Line = line } ) )
. Where ( line = > forbiddenSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, line.Path)}:{line.LineNumber}: {line.Line.Trim()}" )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"Faction identity must compare and order by FactionKey; Faction.ID is temporary projection residue only: " +
string . Join ( "; " , hits ) ) ;
}
}
2026-06-15 21:12:43 +01:00
static void RequireEveRuntimeBootstrap ( string root )
{
var bootstrapPath = Path . Combine (
root ,
"Packages" ,
"org.gamecult.aetheria.eve-runtime" ,
"Runtime" ,
"AetheriaEveRuntimeBootstrap.cs" ) ;
var presenterPath = Path . Combine (
root ,
"Packages" ,
"org.gamecult.aetheria.eve-runtime" ,
"Runtime" ,
"AetheriaEveSurfacePresenter.cs" ) ;
if ( ! File . Exists ( bootstrapPath ) )
{
throw new InvalidOperationException ( "Aetheria Eve runtime bootstrap is missing." ) ;
}
if ( ! File . Exists ( presenterPath ) )
{
throw new InvalidOperationException ( "Aetheria Eve surface presenter is missing." ) ;
}
var bootstrap = File . ReadAllText ( bootstrapPath ) ;
if ( ! bootstrap . Contains ( "RuntimeInitializeOnLoadMethod" , StringComparison . Ordinal ) | |
! bootstrap . Contains ( "DefaultSurfaceId = \"aetheria.operations\"" , StringComparison . Ordinal ) | |
! bootstrap . Contains ( "AetheriaEveSurfacePresenter" , StringComparison . Ordinal ) | |
! bootstrap . Contains ( "UIDocument" , StringComparison . Ordinal ) )
{
throw new InvalidOperationException (
"Aetheria Eve runtime bootstrap no longer mounts the operations surface through the UI Toolkit presenter." ) ;
}
var presenter = File . ReadAllText ( presenterPath ) ;
if ( ! presenter . Contains ( "AetheriaRuntimeEveCommandLog.QueueCommand" , StringComparison . Ordinal ) )
{
throw new InvalidOperationException (
"Aetheria Eve presenter no longer queues renderer commands through the typed Eve command log." ) ;
}
}
2026-06-15 22:00:25 +01:00
static void RequireNoRendererLocalConsole ( string root )
{
var consoleFiles = new [ ]
{
Path . Combine ( root , "Assets" , "Scripts" , "UI" , "ConsoleController.cs" ) ,
Path . Combine ( root , "Assets" , "Scripts" , "UI" , "ConsoleView.cs" )
} ;
var existingConsoleFiles = consoleFiles
. Where ( File . Exists )
. Select ( path = > Path . GetRelativePath ( root , path ) )
. ToArray ( ) ;
if ( existingConsoleFiles . Length > 0 )
{
throw new InvalidOperationException (
"Renderer-local console source files still exist: " +
string . Join ( ", " , existingConsoleFiles ) ) ;
}
var forbiddenSymbols = new [ ]
{
"ConsoleController" ,
"ConsoleView" ,
"AddCommand("
} ;
var hits = Directory . EnumerateFiles ( Path . Combine ( root , "Assets" ) , "*.*" , SearchOption . AllDirectories )
. Where ( path = >
path . EndsWith ( ".cs" , StringComparison . OrdinalIgnoreCase ) | |
path . EndsWith ( ".unity" , StringComparison . OrdinalIgnoreCase ) | |
path . EndsWith ( ".prefab" , StringComparison . OrdinalIgnoreCase ) )
. SelectMany ( path = > File . ReadLines ( path )
. Select ( ( line , index ) = > new { Path = path , LineNumber = index + 1 , Line = line } ) )
. Where ( line = > forbiddenSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, line.Path)}:{line.LineNumber}: {line.Line.Trim()}" )
. Take ( 10 )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"Renderer-local console authority is still wired in Assets: " +
string . Join ( "; " , hits ) ) ;
}
}
2026-06-15 22:26:14 +01:00
static void RequireNoRendererLocalDebugPanels ( string root )
{
var forbiddenFiles = new [ ]
{
Path . Combine ( root , "Assets" , "Scripts" , "UI" , "FieldTester.cs" )
} ;
var existingFiles = forbiddenFiles
. Where ( File . Exists )
. Select ( path = > Path . GetRelativePath ( root , path ) )
. ToArray ( ) ;
if ( existingFiles . Length > 0 )
{
throw new InvalidOperationException (
"Renderer-local debug panel source files still exist: " +
string . Join ( ", " , existingFiles ) ) ;
}
var hits = Directory . EnumerateFiles ( Path . Combine ( root , "Assets" ) , "*.*" , SearchOption . AllDirectories )
. Where ( path = >
path . EndsWith ( ".cs" , StringComparison . OrdinalIgnoreCase ) | |
path . EndsWith ( ".unity" , StringComparison . OrdinalIgnoreCase ) | |
path . EndsWith ( ".prefab" , StringComparison . OrdinalIgnoreCase ) )
. SelectMany ( path = > File . ReadLines ( path )
. Select ( ( line , index ) = > new { Path = path , LineNumber = index + 1 , Line = line } ) )
. Where ( line = > line . Line . Contains ( "FieldTester" , StringComparison . Ordinal ) )
. Select ( line = > $"{Path.GetRelativePath(root, line.Path)}:{line.LineNumber}: {line.Line.Trim()}" )
. Take ( 10 )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"Renderer-local FieldTester authority is still wired in Assets: " +
string . Join ( "; " , hits ) ) ;
}
}
2026-06-15 22:47:15 +01:00
static void RequireMainMenuSettingsCommit ( string root )
{
var mainMenuPath = Path . Combine ( root , "Assets" , "Scripts" , "UI" , "MainMenu.cs" ) ;
2026-06-16 18:32:19 +01:00
var sharedCommandsPath = Path . Combine (
root ,
"Packages" ,
"org.gamecult.aetheria.state" ,
"Runtime" ,
"AetheriaRuntimePlayerSettingsCommands.cs" ) ;
2026-06-16 19:05:00 +01:00
var surfaceBuilderPath = Path . Combine (
root ,
"Packages" ,
"org.gamecult.aetheria.state" ,
"Runtime" ,
"AetheriaRuntimePlayerSettingsSurfaceBuilder.cs" ) ;
2026-06-15 22:47:15 +01:00
if ( ! File . Exists ( mainMenuPath ) )
{
throw new InvalidOperationException ( "Cannot verify main-menu settings commit path; MainMenu.cs is missing." ) ;
}
2026-06-16 18:32:19 +01:00
if ( ! File . Exists ( sharedCommandsPath ) )
{
throw new InvalidOperationException (
"Cannot verify main-menu settings command contract; AetheriaRuntimePlayerSettingsCommands.cs is missing." ) ;
}
2026-06-16 19:05:00 +01:00
if ( ! File . Exists ( surfaceBuilderPath ) )
{
throw new InvalidOperationException (
"Cannot verify main-menu settings surface contract; AetheriaRuntimePlayerSettingsSurfaceBuilder.cs is missing." ) ;
}
2026-06-15 22:47:15 +01:00
var source = File . ReadAllText ( mainMenuPath ) ;
2026-06-16 18:32:19 +01:00
var sharedCommands = File . ReadAllText ( sharedCommandsPath ) ;
2026-06-16 19:05:00 +01:00
var surfaceBuilder = File . ReadAllText ( surfaceBuilderPath ) ;
2026-06-16 04:04:59 +01:00
var actionGameManagerPath = Path . Combine ( root , "Assets" , "Scripts" , "Gameplay" , "ActionGameManager.cs" ) ;
var actionGameManager = File . Exists ( actionGameManagerPath )
? File . ReadAllText ( actionGameManagerPath )
: throw new InvalidOperationException ( "Cannot verify main-menu settings authority; ActionGameManager.cs is missing." ) ;
var requiredCommits = new [ ]
{
"CommitRuntimePlayerName" ,
"CommitRuntimeTemperatureUnit" ,
"CommitRuntimeSignificantDigits" ,
"CommitRuntimeNebulaQuality" ,
2026-06-16 19:05:00 +01:00
"CommitRuntimeShowAsteroidsInMinimap" ,
"CommitRuntimePlayerSettingsCommand"
2026-06-16 04:04:59 +01:00
} ;
var missingCommits = requiredCommits
. Where ( symbol = > ! actionGameManager . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingCommits . Length > 0 )
2026-06-15 22:47:15 +01:00
{
throw new InvalidOperationException (
2026-06-16 04:04:59 +01:00
"ActionGameManager no longer owns complete runtime player-settings commit primitives: " +
string . Join ( ", " , missingCommits ) ) ;
2026-06-15 22:47:15 +01:00
}
2026-06-16 04:04:59 +01:00
var forbiddenSymbols = new [ ]
{
"ActionGameManager.RuntimePlayerSettings.Name =" ,
"ActionGameManager.RuntimePlayerSettings.GameplaySettings.TemperatureUnit =" ,
"ActionGameManager.RuntimePlayerSettings.GameplaySettings.SignificantDigits =" ,
"ActionGameManager.RuntimePlayerSettings.GraphicsSettings.NebulaQuality =" ,
"ActionGameManager.RuntimePlayerSettings.GraphicsSettings.ShowAsteroidsInMinimap ="
} ;
var hits = File . ReadLines ( mainMenuPath )
. Select ( ( line , index ) = > new { LineNumber = index + 1 , Line = line } )
. Where ( line = > forbiddenSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, mainMenuPath)}:{line.LineNumber}: {line.Line.Trim()}" )
. ToArray ( ) ;
if ( hits . Length > 0 )
2026-06-15 22:47:15 +01:00
{
throw new InvalidOperationException (
2026-06-16 04:04:59 +01:00
"MainMenu still owns direct RuntimePlayerSettings mutation: " +
string . Join ( "; " , hits ) ) ;
2026-06-15 22:47:15 +01:00
}
2026-06-16 19:05:00 +01:00
var requiredMainMenuAuthoritySymbols = new [ ]
{
"ActionGameManager.CommitRuntimePlayerSettingsCommand"
} ;
var missingUiCalls = requiredMainMenuAuthoritySymbols
. Where ( symbol = > ! source . Contains ( symbol , StringComparison . Ordinal ) )
2026-06-16 04:04:59 +01:00
. ToArray ( ) ;
if ( missingUiCalls . Length > 0 )
2026-06-15 22:47:15 +01:00
{
throw new InvalidOperationException (
2026-06-16 04:04:59 +01:00
"MainMenu no longer routes settings changes through ActionGameManager: " +
string . Join ( ", " , missingUiCalls ) ) ;
2026-06-15 22:47:15 +01:00
}
2026-06-16 18:32:19 +01:00
var requiredSharedCommands = new [ ]
{
2026-06-16 19:45:39 +01:00
"SetPlayerName" ,
2026-06-16 18:32:19 +01:00
"CycleTemperatureUnit" ,
"DecrementSignificantDigits" ,
"IncrementSignificantDigits" ,
"CycleNebulaQuality" ,
"ToggleShowAsteroidsInMinimap"
} ;
var missingSharedCommands = requiredSharedCommands
. Where ( symbol = > ! sharedCommands . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingSharedCommands . Length > 0 )
{
throw new InvalidOperationException (
"Shared player-settings Eve command contract is incomplete: " +
string . Join ( ", " , missingSharedCommands ) ) ;
}
2026-06-16 19:05:00 +01:00
var requiredSurfaceBuilderSymbols = new [ ]
{
"AetheriaRuntimePlayerSettingsSurfaceBuilder" ,
2026-06-16 19:45:39 +01:00
"AetheriaRuntimePlayerSettingsCommands.SetPlayerName" ,
"\"control.text\"" ,
2026-06-16 19:05:00 +01:00
"AetheriaRuntimePlayerSettingsCommands.CycleTemperatureUnit" ,
"AetheriaRuntimePlayerSettingsCommands.DecrementSignificantDigits" ,
"AetheriaRuntimePlayerSettingsCommands.IncrementSignificantDigits" ,
"AetheriaRuntimePlayerSettingsCommands.CycleNebulaQuality" ,
"AetheriaRuntimePlayerSettingsCommands.ToggleShowAsteroidsInMinimap"
} ;
var missingSurfaceBuilderSymbols = requiredSurfaceBuilderSymbols
. Where ( symbol = > ! surfaceBuilder . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingSurfaceBuilderSymbols . Length > 0 )
{
throw new InvalidOperationException (
"Shared player-settings Eve surface builder is incomplete: " +
string . Join ( ", " , missingSurfaceBuilderSymbols ) ) ;
}
2026-06-16 18:32:19 +01:00
var requiredMainMenuSymbols = new [ ]
{
2026-06-16 19:05:00 +01:00
"AetheriaRuntimePlayerSettingsSurfaceBuilder.Build" ,
"new EveUiToolkitSurfaceLowerer" ,
2026-06-16 19:45:39 +01:00
"ActionGameManager.CommitRuntimePlayerSettingsCommand(request.Command, request.Payload)"
2026-06-16 18:32:19 +01:00
} ;
var missingMainMenuSymbols = requiredMainMenuSymbols
. Where ( symbol = > ! source . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingMainMenuSymbols . Length > 0 )
{
throw new InvalidOperationException (
2026-06-16 19:05:00 +01:00
"MainMenu no longer lowers the shared player-settings Eve surface contract: " +
2026-06-16 18:32:19 +01:00
string . Join ( ", " , missingMainMenuSymbols ) ) ;
}
2026-06-16 19:45:39 +01:00
var forbiddenMainMenuSymbols = new [ ]
{
"new TextField(\"Name\")" ,
"ActionGameManager.CommitRuntimePlayerName(evt.newValue)"
} ;
var mainMenuHits = forbiddenMainMenuSymbols
. Where ( symbol = > source . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( mainMenuHits . Length > 0 )
{
throw new InvalidOperationException (
"MainMenu should not keep renderer-local player-name input authority outside the shared Eve surface: " +
string . Join ( ", " , mainMenuHits ) ) ;
}
2026-06-16 18:32:19 +01:00
var forbiddenUiFieldSymbols = new [ ]
{
"AddField(\"Temperature Unit\"" ,
"AddField(\"Significant Digits\"" ,
"AddField(\"Nebula Quality\"" ,
2026-06-16 19:05:00 +01:00
"AddField(\"Show Asteroids in Minimap\"" ,
"ShowGameplaySettings()" ,
"ShowGraphicsSettings()"
2026-06-16 18:32:19 +01:00
} ;
var uiFieldHits = File . ReadLines ( mainMenuPath )
. Select ( ( line , index ) = > new { LineNumber = index + 1 , Line = line } )
. Where ( line = > forbiddenUiFieldSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, mainMenuPath)}:{line.LineNumber}: {line.Line.Trim()}" )
. ToArray ( ) ;
if ( uiFieldHits . Length > 0 )
{
throw new InvalidOperationException (
"MainMenu still uses legacy field widgets for Eve-owned gameplay/graphics settings: " +
string . Join ( "; " , uiFieldHits ) ) ;
}
2026-06-15 22:47:15 +01:00
}
2026-06-16 18:09:15 +01:00
static void RequirePlayerSettingsEveSurface ( string root )
{
var projectorPath = Path . Combine ( root , "Aetheria.State" , "AetheriaPlayerSettingsSurfaceProjector.cs" ) ;
var bridgePath = Path . Combine ( root , "Aetheria.State" , "AetheriaEveCommandBridge.cs" ) ;
var providerPath = Path . Combine ( root , "Aetheria.State" , "AetheriaProviderAdvertisementProjector.cs" ) ;
var serverPath = Path . Combine ( root , "Economy.Server" , "Program.cs" ) ;
2026-06-16 18:32:19 +01:00
var sharedCommandsPath = Path . Combine (
root ,
"Packages" ,
"org.gamecult.aetheria.state" ,
"Runtime" ,
"AetheriaRuntimePlayerSettingsCommands.cs" ) ;
2026-06-16 19:05:00 +01:00
var surfaceBuilderPath = Path . Combine (
root ,
"Packages" ,
"org.gamecult.aetheria.state" ,
"Runtime" ,
"AetheriaRuntimePlayerSettingsSurfaceBuilder.cs" ) ;
2026-06-16 18:09:15 +01:00
if ( ! File . Exists ( projectorPath ) )
{
throw new InvalidOperationException ( "Player settings Eve surface projector is missing." ) ;
}
var projector = File . ReadAllText ( projectorPath ) ;
var requiredProjectorSymbols = new [ ]
{
2026-06-16 18:32:19 +01:00
"AetheriaRuntimePlayerSettingsCommands.SurfaceId" ,
2026-06-16 19:05:00 +01:00
"AetheriaRuntimePlayerSettingsSurfaceBuilder.Build" ,
"AetheriaRuntimePlayerSettingsSurfaceState" ,
"settings.ActiveRunKey"
2026-06-16 18:09:15 +01:00
} ;
var missingProjectorSymbols = requiredProjectorSymbols
. Where ( symbol = > ! projector . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingProjectorSymbols . Length > 0 )
{
throw new InvalidOperationException (
"Player settings Eve surface projector is missing required typed controls: " +
string . Join ( ", " , missingProjectorSymbols ) ) ;
}
var bridge = File . Exists ( bridgePath )
? File . ReadAllText ( bridgePath )
: throw new InvalidOperationException ( "Player settings Eve command bridge is missing." ) ;
var provider = File . Exists ( providerPath )
? File . ReadAllText ( providerPath )
: throw new InvalidOperationException ( "Player settings provider advertisement projector is missing." ) ;
var server = File . Exists ( serverPath )
? File . ReadAllText ( serverPath )
: throw new InvalidOperationException ( "Economy.Server program is missing." ) ;
2026-06-16 18:32:19 +01:00
var sharedCommands = File . Exists ( sharedCommandsPath )
? File . ReadAllText ( sharedCommandsPath )
: throw new InvalidOperationException ( "Shared player-settings Eve command contract is missing." ) ;
2026-06-16 19:05:00 +01:00
var surfaceBuilder = File . Exists ( surfaceBuilderPath )
? File . ReadAllText ( surfaceBuilderPath )
: throw new InvalidOperationException ( "Shared player-settings Eve surface builder is missing." ) ;
2026-06-16 18:09:15 +01:00
if ( ! bridge . Contains ( "AppliedPlayerSettingsCommands" , StringComparison . Ordinal ) | |
! bridge . Contains ( "ApplyPlayerSettingsCommandAsync" , StringComparison . Ordinal ) | |
2026-06-16 19:45:39 +01:00
! bridge . Contains ( "PutPlayerSettingsSurfaceAsync" , StringComparison . Ordinal ) | |
! bridge . Contains ( "SetPlayerName" , StringComparison . Ordinal ) | |
! bridge . Contains ( "command.Payload.TryGetValue(\"value\"" , StringComparison . Ordinal ) )
2026-06-16 18:09:15 +01:00
{
throw new InvalidOperationException (
"Eve command bridge no longer owns the typed player-settings surface mutation path." ) ;
}
if ( ! provider . Contains ( "AetheriaPlayerSettingsSurfaceProjector.SurfaceId" , StringComparison . Ordinal ) | |
2026-06-16 18:32:19 +01:00
! provider . Contains ( "AetheriaRuntimePlayerSettingsCommands.Refresh" , StringComparison . Ordinal ) )
2026-06-16 18:09:15 +01:00
{
throw new InvalidOperationException (
"Provider advertisement no longer publishes the player-settings Eve surface and commands." ) ;
}
if ( ! server . Contains ( "PublishPlayerSettingsSurfaceAsync" , StringComparison . Ordinal ) | |
! server . Contains ( "PutPlayerSettingsSurfaceAsync" , StringComparison . Ordinal ) )
{
throw new InvalidOperationException (
"Economy.Server no longer republishes the provider-owned player-settings Eve surface." ) ;
}
2026-06-16 18:32:19 +01:00
if ( ! sharedCommands . Contains ( "SurfaceId = \"aetheria.player_settings\"" , StringComparison . Ordinal ) | |
2026-06-16 19:45:39 +01:00
! sharedCommands . Contains ( "public static bool IsKnown" , StringComparison . Ordinal ) | |
! sharedCommands . Contains ( "SetPlayerName" , StringComparison . Ordinal ) )
2026-06-16 18:32:19 +01:00
{
throw new InvalidOperationException (
"Shared player-settings Eve command contract is missing the surface id or command registry helper." ) ;
}
2026-06-16 19:05:00 +01:00
2026-06-16 19:45:39 +01:00
if ( ! surfaceBuilder . Contains ( "public static class AetheriaRuntimePlayerSettingsSurfaceBuilder" , StringComparison . Ordinal ) | |
! surfaceBuilder . Contains ( "\"control.text\"" , StringComparison . Ordinal ) | |
! surfaceBuilder . Contains ( "SetPlayerName" , StringComparison . Ordinal ) )
2026-06-16 19:05:00 +01:00
{
throw new InvalidOperationException (
"Shared player-settings Eve surface builder no longer owns the portable settings surface contract." ) ;
}
2026-06-16 18:09:15 +01:00
}
2026-06-16 06:09:46 +01:00
static void RequireMainMenuContinueRunState ( string root )
{
var mainMenuPath = Path . Combine ( root , "Assets" , "Scripts" , "UI" , "MainMenu.cs" ) ;
var mainMenu = File . Exists ( mainMenuPath )
? File . ReadAllText ( mainMenuPath )
: throw new InvalidOperationException ( "Cannot verify main-menu Continue path; MainMenu.cs is missing." ) ;
var actionGameManagerPath = Path . Combine ( root , "Assets" , "Scripts" , "Gameplay" , "ActionGameManager.cs" ) ;
var actionGameManager = File . Exists ( actionGameManagerPath )
? File . ReadAllText ( actionGameManagerPath )
: throw new InvalidOperationException ( "Cannot verify Continue run authority; ActionGameManager.cs is missing." ) ;
2026-06-16 06:41:35 +01:00
var packageSnapshotPath = Path . Combine (
root ,
"Packages" ,
"org.gamecult.aetheria.state" ,
"Runtime" ,
"AetheriaRuntimeCatalogSnapshot.cs" ) ;
var packageSnapshot = File . Exists ( packageSnapshotPath )
? File . ReadAllText ( packageSnapshotPath )
: throw new InvalidOperationException ( "Cannot verify Continue entity identity; package runtime snapshots are missing." ) ;
var packageStorePath = Path . Combine (
root ,
"Packages" ,
"org.gamecult.aetheria.state" ,
"Runtime" ,
"AetheriaRuntimeCatalogStore.cs" ) ;
var packageStore = File . Exists ( packageStorePath )
? File . ReadAllText ( packageStorePath )
: throw new InvalidOperationException ( "Cannot verify Continue entity readback; package runtime store is missing." ) ;
2026-06-16 06:09:46 +01:00
var requiredMenuSymbols = new [ ]
{
"LatestContinueRun" ,
"AetheriaRuntimeCatalogStore" ,
"ReadRunStates(ActionGameManager.RuntimeStateFilePath)" ,
"ContinueGame(continueRun)" ,
"ActionGameManager.ContinueRunState = run" ,
"SceneManager.LoadScene(\"ARPG\")"
} ;
var missingMenuSymbols = requiredMenuSymbols
. Where ( symbol = > ! mainMenu . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingMenuSymbols . Length > 0 )
{
throw new InvalidOperationException (
"MainMenu Continue no longer selects typed run state: " +
string . Join ( ", " , missingMenuSymbols ) ) ;
}
if ( mainMenu . Contains ( "AddButton(\"Continue\", null)" , StringComparison . Ordinal ) )
{
throw new InvalidOperationException ( "MainMenu Continue regressed to a null button." ) ;
}
var requiredGameplaySymbols = new [ ]
{
"AetheriaRuntimeRunStateSnapshot ContinueRunState" ,
"ResolveStartZone(continuingRun)" ,
"if (continuingRun != null)" ,
2026-06-16 07:52:01 +01:00
"RestoreEntityGraphFromTypedRun(continuingRun)" ,
2026-06-16 06:41:35 +01:00
"ReadEntitySnapshots(RuntimeStateFilePath)" ,
"entity.RecordKey" ,
2026-06-16 17:19:58 +01:00
"run.CurrentEntityKey" ,
2026-06-16 17:27:28 +01:00
"ResolveCurrentEntityRecordKey(run)" ,
2026-06-16 07:52:01 +01:00
"ReplaceZoneEntitiesFromTypedSnapshots" ,
"Zone.Agents.Clear()" ,
2026-06-16 08:18:16 +01:00
"FlattenEntityGraph(Zone)" ,
"RestoreChildAndDockingRelationships" ,
"RestoreCurrentEntityBinding" ,
2026-06-16 07:52:01 +01:00
"RestoreEntityContactsFromTypedSnapshot" ,
"entity.Target.Value = target" ,
"string.Equals(entitySnapshot.RecordKey, currentEntityKey" ,
"BindToEntity(currentEntity)" ,
2026-06-16 07:01:50 +01:00
"RestoreActiveConsumablesFromTypedEntitySnapshot(entity, entitySnapshot)" ,
2026-06-16 09:01:05 +01:00
"RestoreRuntimeBehaviorStateFromTypedSnapshot(entity, entitySnapshot, restoredEntities)" ,
"ResolveRuntimeBehavior(entity, weaponState.OwnerKind, weaponState.OwnerIndex, weaponState.BehaviorIndex)" ,
"lockWeapon.RestoreRuntimeState(" ,
"drive.RestoreRuntimeState(" ,
"resourceScanner.RestoreRuntimeState(" ,
2026-06-16 07:18:14 +01:00
"entity.RestoreStatGrids(entitySnapshot.StatGrids)" ,
2026-06-16 07:01:50 +01:00
"RestoreThermalExposure((float)entitySnapshot.Heatstroke, (float)entitySnapshot.Hypothermia)" ,
"entity.HeatsinksEnabled = entitySnapshot.HeatsinksEnabled" ,
2026-06-16 06:09:46 +01:00
"ContinueRunState = null" ,
"RestoreDroppedPickupsFromTypedZoneState"
} ;
var missingGameplaySymbols = requiredGameplaySymbols
. Where ( symbol = > ! actionGameManager . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingGameplaySymbols . Length > 0 )
{
throw new InvalidOperationException (
"ActionGameManager no longer has the typed Continue boot path: " +
string . Join ( ", " , missingGameplaySymbols ) ) ;
}
2026-06-16 06:41:35 +01:00
2026-06-16 17:19:58 +01:00
var forbiddenGameplaySymbols = new [ ]
{
"if (run == null ||\r\n run.CurrentZoneIndex < 0 ||\r\n run.CurrentZoneEntityIndex < 0)" ,
"var currentEntityKey = $\"{zoneEntityKeyPrefix}{run.CurrentZoneEntityIndex}.v1\""
} ;
var forbiddenGameplayHits = forbiddenGameplaySymbols
. Where ( symbol = > actionGameManager . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( forbiddenGameplayHits . Length > 0 )
{
throw new InvalidOperationException (
"ActionGameManager still reconstructs Continue current-entity ownership from integer slot state: " +
string . Join ( ", " , forbiddenGameplayHits ) ) ;
}
2026-06-16 17:27:28 +01:00
var canonicalRunStatePath = Path . Combine ( root , "Aetheria.State" , "Documents" , "AetheriaRuntimeStateDocuments.cs" ) ;
var canonicalRunState = File . Exists ( canonicalRunStatePath )
? File . ReadAllText ( canonicalRunStatePath )
: throw new InvalidOperationException ( "Cannot verify canonical run-state authority; AetheriaRuntimeStateDocuments.cs is missing." ) ;
if ( canonicalRunState . Contains ( "CurrentZoneEntityIndex" , StringComparison . Ordinal ) )
{
throw new InvalidOperationException (
"Canonical typed run state still exposes integer current-entity slot authority." ) ;
}
if ( packageSnapshot . Contains ( "CurrentZoneEntityIndex" , StringComparison . Ordinal ) )
{
throw new InvalidOperationException (
"Unity package runtime run snapshot still exposes integer current-entity slot authority." ) ;
}
2026-06-16 17:44:48 +01:00
var pendingCommitPath = Path . Combine ( root , "Packages" , "org.gamecult.aetheria.state" , "Runtime" , "AetheriaRuntimeStateCommitDocument.cs" ) ;
var pendingCommit = File . Exists ( pendingCommitPath )
? File . ReadAllText ( pendingCommitPath )
: throw new InvalidOperationException ( "Cannot verify pending commit authority; AetheriaRuntimeStateCommitDocument.cs is missing." ) ;
if ( pendingCommit . Contains ( "CurrentZoneEntityIndex" , StringComparison . Ordinal ) )
{
throw new InvalidOperationException (
"Pending runtime commit transport still exposes integer current-entity slot authority." ) ;
}
2026-06-16 06:41:35 +01:00
var requiredPackageSymbols = new [ ]
{
"public string RecordKey" ,
"ReadEntitySnapshotPayload(record.Key, record.Payload)"
} ;
var missingPackageSymbols = requiredPackageSymbols
. Where ( symbol = >
! packageSnapshot . Contains ( symbol , StringComparison . Ordinal ) & &
! packageStore . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingPackageSymbols . Length > 0 )
{
throw new InvalidOperationException (
"Unity package entity readback no longer preserves record identity for Continue: " +
string . Join ( ", " , missingPackageSymbols ) ) ;
}
2026-06-16 07:01:50 +01:00
var entitySourcePath = Path . Combine ( root , "Assets" , "Scripts" , "ServerShared" , "Entity.cs" ) ;
var entitySource = File . Exists ( entitySourcePath )
? File . ReadAllText ( entitySourcePath )
: throw new InvalidOperationException ( "Cannot verify Continue entity restore ownership; Entity.cs is missing." ) ;
var requiredEntityRestoreSymbols = new [ ]
{
"RestoreThermalExposure" ,
"RestoreActiveConsumable" ,
2026-06-16 07:18:14 +01:00
"RestoreStatGrids" ,
"RestoreHullConductivityGrid" ,
2026-06-16 07:01:50 +01:00
"new ConsumableItemEffect(item, this, remainingDuration, duration)"
} ;
var missingEntityRestoreSymbols = requiredEntityRestoreSymbols
. Where ( symbol = > ! entitySource . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingEntityRestoreSymbols . Length > 0 )
{
throw new InvalidOperationException (
"Entity no longer exposes narrow runtime-owned restore primitives for typed Continue state: " +
string . Join ( ", " , missingEntityRestoreSymbols ) ) ;
}
2026-06-16 06:09:46 +01:00
}
2026-06-15 23:19:41 +01:00
static void RequirePropertiesPanelReadOnlyInspector ( string root )
{
var propertiesPanelPath = Path . Combine ( root , "Assets" , "Scripts" , "UI" , "Properties Panel" , "PropertiesPanel.cs" ) ;
if ( ! File . Exists ( propertiesPanelPath ) )
{
throw new InvalidOperationException ( "Cannot verify PropertiesPanel inspector authority; PropertiesPanel.cs is missing." ) ;
}
var source = File . ReadAllText ( propertiesPanelPath ) ;
var forbiddenSymbols = new [ ]
{
2026-06-16 19:38:02 +01:00
"Inspect(object obj" ,
"Inspect(object obj, FieldInfo field" ,
"GetCustomAttribute<InspectableAttribute>" ,
"type.GetCustomAttribute<InspectableAttribute>()" ,
"field.GetValue(obj)" ,
2026-06-15 23:19:41 +01:00
"readWrite" ,
"field.SetValue" ,
"f => field.SetValue" ,
"i => field.SetValue" ,
"b => field.SetValue"
} ;
var hits = forbiddenSymbols
. Where ( symbol = > source . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
2026-06-16 19:38:02 +01:00
"PropertiesPanel should not keep the dead generic reflection inspector path or renderer-local write authority: " +
2026-06-15 23:19:41 +01:00
string . Join ( ", " , hits ) ) ;
}
}
2026-06-16 19:55:50 +01:00
static void RequireTypedBehaviorMetadataCoverage ( string root )
{
var metadataPath = Path . Combine ( root , "Packages" , "org.gamecult.aetheria.state" , "Runtime" , "AetheriaRuntimeBehaviorMetadata.cs" ) ;
var propertiesPanelPath = Path . Combine ( root , "Assets" , "Scripts" , "UI" , "Properties Panel" , "PropertiesPanel.cs" ) ;
var tradeMenuPath = Path . Combine ( root , "Assets" , "Scripts" , "UI" , "Menu" , "TradeMenu.cs" ) ;
var metadata = File . Exists ( metadataPath )
? File . ReadAllText ( metadataPath )
: throw new InvalidOperationException ( "Cannot verify typed behavior metadata coverage; AetheriaRuntimeBehaviorMetadata.cs is missing." ) ;
var propertiesPanel = File . Exists ( propertiesPanelPath )
? File . ReadAllText ( propertiesPanelPath )
: throw new InvalidOperationException ( "Cannot verify typed behavior metadata coverage; PropertiesPanel.cs is missing." ) ;
var tradeMenu = File . Exists ( tradeMenuPath )
? File . ReadAllText ( tradeMenuPath )
: throw new InvalidOperationException ( "Cannot verify typed behavior metadata coverage; TradeMenu.cs is missing." ) ;
var requiredMetadataSymbols = new [ ]
{
"AetheriaRuntimeBehaviorFieldValueKind.Temperature" ,
"Behavior(\"Heat\", \"\", Stat(\"Heat\", 1))" ,
"Behavior(\"MiningTool\", \"\", Stat(\"DamagePerSecond\", 1), Stat(\"Efficiency\", 2), Stat(\"Penetration\", 3), Stat(\"Range\", 4))" ,
"Behavior(\"Switch\", \"\")" ,
"Behavior(\"Thermotoggle\", \"\", Temperature(\"TargetTemperature\", 1))" ,
"Behavior(\"Trigger\", \"\")" ,
"Temperature(\"TemperatureFloor\", 3)"
} ;
var missingMetadataSymbols = requiredMetadataSymbols
. Where ( symbol = > ! metadata . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingMetadataSymbols . Length > 0 )
{
throw new InvalidOperationException (
"Typed behavior metadata no longer covers live heat/mining/thermotoggle payloads and switch/trigger shells: " +
string . Join ( ", " , missingMetadataSymbols ) ) ;
}
var requiredUiSymbols = new [ ]
{
"AetheriaRuntimeBehaviorFieldValueKind.Temperature" ,
"FormatTemperature"
} ;
var missingPropertiesSymbols = requiredUiSymbols
. Where ( symbol = > ! propertiesPanel . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingPropertiesSymbols . Length > 0 )
{
throw new InvalidOperationException (
"PropertiesPanel no longer renders typed temperature-bearing behavior metadata: " +
string . Join ( ", " , missingPropertiesSymbols ) ) ;
}
var missingTradeSymbols = requiredUiSymbols
. Where ( symbol = > ! tradeMenu . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingTradeSymbols . Length > 0 )
{
throw new InvalidOperationException (
"TradeMenu no longer renders typed temperature-bearing behavior metadata: " +
string . Join ( ", " , missingTradeSymbols ) ) ;
}
}
2026-06-16 00:01:19 +01:00
static void RequireRuntimeSimulationTuningCommits ( string root )
{
var requiredActionGameManagerPath = Path . Combine ( root , "Assets" , "Scripts" , "Gameplay" , "ActionGameManager.cs" ) ;
var actionGameManager = File . Exists ( requiredActionGameManagerPath )
? File . ReadAllText ( requiredActionGameManagerPath )
: throw new InvalidOperationException ( "Cannot verify runtime simulation tuning authority; ActionGameManager.cs is missing." ) ;
var requiredCommitMethods = new [ ]
{
"CommitEntityOverrideShutdown" ,
"CommitEquippedItemOverrideShutdown" ,
"CommitThermotoggleTargetTemperature" ,
"CommitEntityShutdownPerformance"
} ;
var missingMethods = requiredCommitMethods
. Where ( method = > ! actionGameManager . Contains ( method , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingMethods . Length > 0 )
{
throw new InvalidOperationException (
"Runtime simulation tuning commit methods are missing from ActionGameManager: " +
string . Join ( ", " , missingMethods ) ) ;
}
var forbiddenUiWrites = new [ ]
{
"EquippableItem.OverrideShutdown =" ,
"thermotoggle.TargetTemperature =" ,
"Settings.ShutdownPerformance =" ,
"CurrentEntity.OverrideShutdown ="
} ;
var uiRoot = Path . Combine ( root , "Assets" , "Scripts" , "UI" ) ;
var hits = Directory . EnumerateFiles ( uiRoot , "*.cs" , SearchOption . AllDirectories )
. SelectMany ( path = > File . ReadLines ( path )
. Select ( ( line , index ) = > new { Path = path , LineNumber = index + 1 , Line = line } ) )
. Where ( line = > forbiddenUiWrites . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, line.Path)}:{line.LineNumber}: {line.Line.Trim()}" )
. Take ( 10 )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"Runtime simulation tuning still has renderer-local UI write authority: " +
string . Join ( "; " , hits ) ) ;
}
}
2026-06-16 00:19:58 +01:00
static void RequireHullConductivityCommitAuthority ( 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 hull conductivity authority; ActionGameManager.cs is missing." ) ;
if ( ! actionGameManager . Contains ( "CommitHullConductivityToggle" , StringComparison . Ordinal ) | |
! actionGameManager . Contains ( "QueueRunCheckpoint(\"hull-conductivity-toggle\")" , StringComparison . Ordinal ) )
{
throw new InvalidOperationException (
"Hull conductivity no longer has a gameplay-owned checkpoint commit primitive." ) ;
}
var uiRoot = Path . Combine ( root , "Assets" , "Scripts" , "UI" ) ;
var hits = Directory . EnumerateFiles ( uiRoot , "*.cs" , SearchOption . AllDirectories )
. SelectMany ( path = > File . ReadLines ( path )
. Select ( ( line , index ) = > new { Path = path , LineNumber = index + 1 , Line = line } ) )
. Where ( line = >
line . Line . Contains ( "HullConductivity[" , StringComparison . Ordinal ) & &
line . Line . Contains ( "=" , StringComparison . Ordinal ) & &
! line . Line . Contains ( "=>" , StringComparison . Ordinal ) )
. Select ( line = > $"{Path.GetRelativePath(root, line.Path)}:{line.LineNumber}: {line.Line.Trim()}" )
. Take ( 10 )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"Hull conductivity still has renderer-local UI write authority: " +
string . Join ( "; " , hits ) ) ;
}
}
2026-06-16 00:40:04 +01:00
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." ) ;
}
}
2026-06-16 01:00:40 +01:00
static void RequireWeaponGroupCommitAuthority ( 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 weapon group authority; ActionGameManager.cs is missing." ) ;
if ( ! actionGameManager . Contains ( "CommitWeaponGroupMembership" , StringComparison . Ordinal ) | |
! actionGameManager . Contains ( "QueueRunCheckpoint(\"weapon-group-membership\")" , StringComparison . Ordinal ) )
{
throw new InvalidOperationException (
"Weapon group membership no longer has a gameplay-owned checkpoint commit primitive." ) ;
}
var assignmentPath = Path . Combine ( root , "Assets" , "Scripts" , "UI" , "Menu" , "WeaponGroupAssignment.cs" ) ;
var assignment = File . Exists ( assignmentPath )
? File . ReadAllText ( assignmentPath )
: throw new InvalidOperationException ( "Cannot verify weapon group authority; WeaponGroupAssignment.cs is missing." ) ;
var forbiddenSymbols = new [ ]
{
".WeaponGroups[i1].items.Add" ,
".WeaponGroups[i1].items.Remove" ,
".WeaponGroups[i1].weapons.Add" ,
".WeaponGroups[i1].weapons.Remove"
} ;
var hits = forbiddenSymbols
. Where ( symbol = > assignment . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"WeaponGroupAssignment still mutates weapon groups directly: " +
string . Join ( ", " , hits ) ) ;
}
if ( ! assignment . Contains ( "CommitWeaponGroupMembership" , StringComparison . Ordinal ) )
{
throw new InvalidOperationException ( "WeaponGroupAssignment no longer routes membership changes through ActionGameManager." ) ;
}
}
2026-06-16 01:59:18 +01:00
static void RequireInventoryDoubleClickTransferCommitAuthority ( 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 transfer authority; ActionGameManager.cs is missing." ) ;
var requiredCommits = new [ ]
{
"CommitCargoItemTransfer" ,
"CommitCargoItemEquip" ,
"CommitEquippedItemStore" ,
2026-06-16 02:35:13 +01:00
"CommitEquippedItemEquip" ,
2026-06-16 01:59:18 +01:00
"QueueRunCheckpoint(\"cargo-item-transfer\")" ,
"QueueRunCheckpoint(\"cargo-item-equip\")" ,
2026-06-16 02:35:13 +01:00
"QueueRunCheckpoint(\"equipped-item-store\")" ,
"QueueRunCheckpoint(\"equipped-item-equip\")"
2026-06-16 01:59:18 +01:00
} ;
var missingCommits = requiredCommits
. Where ( symbol = > ! actionGameManager . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingCommits . Length > 0 )
{
throw new InvalidOperationException (
"Inventory transfer no longer has complete gameplay-owned checkpoint commit primitives: " +
string . Join ( ", " , missingCommits ) ) ;
}
2026-06-16 02:35:13 +01:00
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 transfer authority; InventoryPanel.cs is missing." ) ;
2026-06-16 01:59:18 +01:00
var inventoryMenuPath = Path . Combine ( root , "Assets" , "Scripts" , "UI" , "Menu" , "InventoryMenu.cs" ) ;
var inventoryMenu = File . Exists ( inventoryMenuPath )
? File . ReadAllText ( inventoryMenuPath )
: throw new InvalidOperationException ( "Cannot verify inventory transfer authority; InventoryMenu.cs is missing." ) ;
var forbiddenSymbols = new [ ]
{
".DropItem(" ,
".CargoBay.Remove(" ,
2026-06-16 02:35:13 +01:00
".TryUnequip(" ,
".TryEquip(" ,
".TryStore(" ,
".OriginInventory.Remove("
2026-06-16 01:59:18 +01:00
} ;
2026-06-16 02:35:13 +01:00
var hits = new [ ] { inventoryMenuPath , inventoryPanelPath }
. SelectMany ( path = > File . ReadLines ( path )
. Select ( ( line , index ) = > new { Path = path , LineNumber = index + 1 , Line = line } ) )
2026-06-16 01:59:18 +01:00
. Where ( line = > forbiddenSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
2026-06-16 02:35:13 +01:00
. Select ( line = > $"{Path.GetRelativePath(root, line.Path)}:{line.LineNumber}: {line.Line.Trim()}" )
2026-06-16 01:59:18 +01:00
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
2026-06-16 02:35:13 +01:00
"Inventory UI still owns direct inventory mutation: " +
2026-06-16 01:59:18 +01:00
string . Join ( "; " , hits ) ) ;
}
var requiredUiCalls = new [ ]
{
"GameManager.CommitCargoItemTransfer" ,
"GameManager.CommitCargoItemEquip" ,
2026-06-16 02:35:13 +01:00
"GameManager.CommitEquippedItemStore" ,
"GameManager.CommitEquippedItemEquip"
2026-06-16 01:59:18 +01:00
} ;
var missingUiCalls = requiredUiCalls
2026-06-16 02:35:13 +01:00
. Where ( symbol = >
! inventoryMenu . Contains ( symbol , StringComparison . Ordinal ) & &
! inventoryPanel . Contains ( symbol , StringComparison . Ordinal ) )
2026-06-16 01:59:18 +01:00
. ToArray ( ) ;
if ( missingUiCalls . Length > 0 )
{
throw new InvalidOperationException (
2026-06-16 02:35:13 +01:00
"Inventory UI no longer routes transfer requests through ActionGameManager: " +
2026-06-16 01:59:18 +01:00
string . Join ( ", " , missingUiCalls ) ) ;
}
}
2026-06-16 02:57:45 +01:00
static void RequireTradePurchaseCommitAuthority ( 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 trade purchase authority; ActionGameManager.cs is missing." ) ;
var requiredCommits = new [ ]
{
"CommitTradePurchase" ,
"QueueRunCheckpoint(\"trade-purchase\")" ,
"Credits -=" ,
"new Ship("
} ;
var missingCommits = requiredCommits
. Where ( symbol = > ! actionGameManager . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingCommits . Length > 0 )
{
throw new InvalidOperationException (
"Trade purchase no longer has a gameplay-owned checkpoint commit primitive: " +
string . Join ( ", " , missingCommits ) ) ;
}
var tradeMenuPath = Path . Combine ( root , "Assets" , "Scripts" , "UI" , "Menu" , "TradeMenu.cs" ) ;
var tradeMenu = File . Exists ( tradeMenuPath )
? File . ReadAllText ( tradeMenuPath )
: throw new InvalidOperationException ( "Cannot verify trade purchase authority; TradeMenu.cs is missing." ) ;
var forbiddenSymbols = new [ ]
{
"GameManager.Credits -=" ,
"Inventory.TryTransferItem(" ,
"new Ship(" ,
".SetParent(GameManager.DockedEntity)"
} ;
var hits = File . ReadLines ( tradeMenuPath )
. Select ( ( line , index ) = > new { LineNumber = index + 1 , Line = line } )
. Where ( line = > forbiddenSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, tradeMenuPath)}:{line.LineNumber}: {line.Line.Trim()}" )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"TradeMenu still owns direct purchase mutation: " +
string . Join ( "; " , hits ) ) ;
}
if ( ! tradeMenu . Contains ( "GameManager.CommitTradePurchase" , StringComparison . Ordinal ) )
{
throw new InvalidOperationException ( "TradeMenu no longer routes purchases through ActionGameManager." ) ;
}
}
2026-06-16 04:27:07 +01:00
static void RequireLootPickupCommitAuthority ( 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 loot pickup authority; ActionGameManager.cs is missing." ) ;
var requiredSymbols = new [ ]
{
"CommitLootPickup" ,
"QueueRunCheckpoint(\"loot-pickup\")" ,
".TryStore(item)"
} ;
var missingSymbols = requiredSymbols
. Where ( symbol = > ! actionGameManager . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingSymbols . Length > 0 )
{
throw new InvalidOperationException (
"Loot pickup no longer has a gameplay-owned checkpoint commit primitive: " +
string . Join ( ", " , missingSymbols ) ) ;
}
var shieldManagerPath = Path . Combine ( root , "Assets" , "Scripts" , "Gameplay" , "ShieldManager.cs" ) ;
var shieldManager = File . Exists ( shieldManagerPath )
? File . ReadAllText ( shieldManagerPath )
: throw new InvalidOperationException ( "Cannot verify loot pickup authority; ShieldManager.cs is missing." ) ;
var forbiddenSymbols = new [ ]
{
".TryStore(" ,
".CargoBays.Any("
} ;
var hits = File . ReadLines ( shieldManagerPath )
. Select ( ( line , index ) = > new { LineNumber = index + 1 , Line = line } )
. Where ( line = > forbiddenSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, shieldManagerPath)}:{line.LineNumber}: {line.Line.Trim()}" )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"ShieldManager still owns direct loot cargo mutation: " +
string . Join ( "; " , hits ) ) ;
}
if ( ! shieldManager . Contains ( "ActionGameManager.Instance.CommitLootPickup" , StringComparison . Ordinal ) )
{
throw new InvalidOperationException ( "ShieldManager no longer routes loot pickup through ActionGameManager." ) ;
}
}
2026-06-16 04:47:42 +01:00
static void RequireEntityDestroyedCommitAuthority ( 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 entity destruction authority; ActionGameManager.cs is missing." ) ;
var requiredSymbols = new [ ]
{
"CommitEntityDestroyed" ,
"QueueRunCheckpoint(\"entity-destroyed\")" ,
"entity.Zone.Entities.Remove(entity)" ,
"zoneRenderer.DropItem("
} ;
var missingSymbols = requiredSymbols
. Where ( symbol = > ! actionGameManager . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingSymbols . Length > 0 )
{
throw new InvalidOperationException (
"Entity destruction no longer has a gameplay-owned checkpoint commit primitive: " +
string . Join ( ", " , missingSymbols ) ) ;
}
var entityInstancePath = Path . Combine ( root , "Assets" , "Scripts" , "Gameplay" , "EntityInstance.cs" ) ;
var entityInstance = File . Exists ( entityInstancePath )
? File . ReadAllText ( entityInstancePath )
: throw new InvalidOperationException ( "Cannot verify entity destruction authority; EntityInstance.cs is missing." ) ;
var forbiddenSymbols = new [ ]
{
"ZoneRenderer.DropItem(" ,
"entity.Zone.Entities.Remove(entity)" ,
"Random.onUnitSphere" ,
"LootDropProbability"
} ;
var hits = File . ReadLines ( entityInstancePath )
. Select ( ( line , index ) = > new { LineNumber = index + 1 , Line = line } )
. Where ( line = > forbiddenSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, entityInstancePath)}:{line.LineNumber}: {line.Line.Trim()}" )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"EntityInstance still owns direct destruction/drop mutation: " +
string . Join ( "; " , hits ) ) ;
}
if ( ! entityInstance . Contains ( "ActionGameManager.Instance?.CommitEntityDestroyed" , StringComparison . Ordinal ) )
{
throw new InvalidOperationException ( "EntityInstance no longer routes destruction through ActionGameManager." ) ;
}
}
2026-06-16 05:24:11 +01:00
static void RequireDroppedPickupCheckpointState ( string root )
{
var requiredFiles = new Dictionary < string , string [ ] >
{
[Path.Combine(root, "Packages", "org.gamecult.aetheria.state", "Runtime", "AetheriaRuntimeStateCommitDocument.cs")] = new [ ]
{
"AetheriaRuntimeDroppedPickupCommit" ,
"DroppedPickups"
} ,
[Path.Combine(root, "Aetheria.State", "Documents", "AetheriaRuntimeStateDocuments.cs")] = new [ ]
{
"AetheriaDroppedPickupSnapshot" ,
"DroppedPickups"
} ,
[Path.Combine(root, "Aetheria.State", "AetheriaRuntimeCommitLogApplier.cs")] = new [ ]
{
"ToDroppedPickups" ,
"DroppedPickups = ToDroppedPickups(zone.DroppedPickups)"
} ,
[Path.Combine(root, "Packages", "org.gamecult.aetheria.state", "Runtime", "AetheriaRuntimeCatalogStore.cs")] = new [ ]
{
2026-06-16 05:51:07 +01:00
"ReadZoneStatePayload(record.Key, record.Payload)" ,
2026-06-16 05:24:11 +01:00
"ReadFieldDroppedPickups" ,
"AetheriaRuntimeDroppedPickupSnapshot"
} ,
[Path.Combine(root, "Packages", "org.gamecult.aetheria.state", "Runtime", "AetheriaRuntimeCatalogSnapshot.cs")] = new [ ]
{
2026-06-16 05:51:07 +01:00
"public string RecordKey" ,
2026-06-16 05:24:11 +01:00
"AetheriaRuntimeDroppedPickupSnapshot" ,
"public IReadOnlyList<AetheriaRuntimeDroppedPickupSnapshot> DroppedPickups"
} ,
[Path.Combine(root, "Assets", "Scripts", "Gameplay", "ActionGameManager.cs")] = new [ ]
{
"ProjectDroppedPickups" ,
2026-06-16 05:51:07 +01:00
"DroppedPickups = ProjectDroppedPickups(zone)" ,
"RestoreDroppedPickupsFromTypedZoneState" ,
"AetheriaRuntimeCatalogStore.ReadZoneStates(RuntimeStateFilePath)" ,
"ZoneRenderer.DropItem("
2026-06-16 05:24:11 +01:00
} ,
[Path.Combine(root, "Assets", "Scripts", "Zone Display", "ZoneRenderer.cs")] = new [ ]
{
"ActiveLoot"
} ,
[Path.Combine(root, "Aetheria.State.Unity.Smoke", "Program.cs")] = new [ ]
{
"new AetheriaRuntimeDroppedPickupCommit" ,
2026-06-16 05:51:07 +01:00
"packageZones[0].RecordKey" ,
2026-06-16 05:24:11 +01:00
"packageZones[0].DroppedPickups"
}
} ;
var missing = requiredFiles
. SelectMany ( pair = >
{
if ( ! File . Exists ( pair . Key ) )
return new [ ] { $"{Path.GetRelativePath(root, pair.Key)}: missing file" } ;
var text = File . ReadAllText ( pair . Key ) ;
return pair . Value
. Where ( symbol = > ! text . Contains ( symbol , StringComparison . Ordinal ) )
. Select ( symbol = > $"{Path.GetRelativePath(root, pair.Key)}: missing {symbol}" ) ;
} )
. ToArray ( ) ;
if ( missing . Length > 0 )
{
throw new InvalidOperationException (
"Dropped pickup checkpoint state is incomplete: " +
string . Join ( "; " , missing ) ) ;
}
}
2026-06-16 03:18:55 +01:00
static void RequireInventoryLoadoutRestoreCommitAuthority ( 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 loadout restore authority; ActionGameManager.cs is missing." ) ;
var requiredSymbols = new [ ]
{
"CommitRuntimeLoadoutRestore" ,
"EntityConstructionBlueprintProjector.InstantiateFromBlueprint" ,
"QueueRunCheckpoint(\"loadout-restore\")" ,
"Credits -="
} ;
var missingSymbols = requiredSymbols
. Where ( symbol = > ! actionGameManager . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingSymbols . Length > 0 )
{
throw new InvalidOperationException (
"Loadout restore no longer has a gameplay-owned checkpoint commit primitive: " +
string . Join ( ", " , missingSymbols ) ) ;
}
var inventoryPanelPath = Path . Combine ( root , "Assets" , "Scripts" , "UI" , "Menu" , "InventoryPanel.cs" ) ;
var inventoryPanel = File . Exists ( inventoryPanelPath )
? File . ReadAllText ( inventoryPanelPath )
: throw new InvalidOperationException ( "Cannot verify loadout restore authority; InventoryPanel.cs is missing." ) ;
var forbiddenSymbols = new [ ]
{
"EntityConstructionBlueprintProjector.InstantiateFromBlueprint" ,
"GameManager.Credits -=" ,
".SetParent(GameManager.DockedEntity)"
} ;
var hits = File . ReadLines ( inventoryPanelPath )
. Select ( ( line , index ) = > new { LineNumber = index + 1 , Line = line } )
. Where ( line = > forbiddenSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, inventoryPanelPath)}:{line.LineNumber}: {line.Line.Trim()}" )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"InventoryPanel still owns direct loadout restore mutation: " +
string . Join ( "; " , hits ) ) ;
}
if ( ! inventoryPanel . Contains ( "GameManager.CommitRuntimeLoadoutRestore" , StringComparison . Ordinal ) )
{
throw new InvalidOperationException ( "InventoryPanel no longer routes loadout restore through ActionGameManager." ) ;
}
}
2026-06-16 03:43:21 +01:00
static void RequireDockedCurrentShipCommitAuthority ( 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 docked current-ship authority; ActionGameManager.cs is missing." ) ;
var requiredSymbols = new [ ]
{
"CommitDockedCurrentShip" ,
"QueueRunCheckpoint(\"docked-current-ship\")" ,
"DockingBay.DockedShip = ship"
} ;
var missingSymbols = requiredSymbols
. Where ( symbol = > ! actionGameManager . Contains ( symbol , StringComparison . Ordinal ) )
. ToArray ( ) ;
if ( missingSymbols . Length > 0 )
{
throw new InvalidOperationException (
"Docked current-ship selection no longer has a gameplay-owned checkpoint commit primitive: " +
string . Join ( ", " , missingSymbols ) ) ;
}
var inventoryPanelPath = Path . Combine ( root , "Assets" , "Scripts" , "UI" , "Menu" , "InventoryPanel.cs" ) ;
var forbiddenSymbols = new [ ]
{
"GameManager.CurrentEntity =" ,
"GameManager.DockingBay.DockedShip ="
} ;
var hits = File . ReadLines ( inventoryPanelPath )
. Select ( ( line , index ) = > new { LineNumber = index + 1 , Line = line } )
. Where ( line = > forbiddenSymbols . Any ( symbol = > line . Line . Contains ( symbol , StringComparison . Ordinal ) ) )
. Select ( line = > $"{Path.GetRelativePath(root, inventoryPanelPath)}:{line.LineNumber}: {line.Line.Trim()}" )
. ToArray ( ) ;
if ( hits . Length > 0 )
{
throw new InvalidOperationException (
"InventoryPanel still owns direct docked current-ship mutation: " +
string . Join ( "; " , hits ) ) ;
}
var inventoryPanel = File . ReadAllText ( inventoryPanelPath ) ;
if ( ! inventoryPanel . Contains ( "GameManager.CommitDockedCurrentShip" , StringComparison . Ordinal ) )
{
throw new InvalidOperationException ( "InventoryPanel no longer routes current-ship selection through ActionGameManager." ) ;
}
}
2026-06-13 10:01:20 +01:00
static bool ContainsBehaviorValueKind ( AetheriaBehaviorValue value , string kind )
{
return string . Equals ( value . Kind , kind , StringComparison . OrdinalIgnoreCase ) | |
value . Children . Any ( child = > ContainsBehaviorValueKind ( child , kind ) ) | |
value . MapEntries . Any ( entry = > ContainsBehaviorValueKind ( entry . Value , kind ) ) ;
}
2026-06-15 16:10:13 +01:00
static int CountRequiredBehaviorItemRefsMissingItemKeys ( AetheriaBehaviorPayload payload )
{
return payload . Fields . Count ( field = >
IsBehaviorItemRefField ( payload . Kind , field . Key ) & &
IsNonEmptyLegacyRefMissingItemKey ( field . Value ) ) ;
}
static bool IsBehaviorItemRefField ( string behaviorKind , int fieldKey )
{
return ( string . Equals ( behaviorKind , "ItemUsage" , StringComparison . OrdinalIgnoreCase ) & & fieldKey = = 1 ) | |
( IsWeaponBehavior ( behaviorKind ) & & fieldKey = = 12 ) ;
}
static bool IsWeaponBehavior ( string behaviorKind )
{
return behaviorKind is "GuidedWeapon" or "InstantWeapon" or "ConstantWeapon" or "ChargedWeapon" or "AutoWeapon" or "LockWeapon" ;
}
static bool IsNonEmptyLegacyRefMissingItemKey ( AetheriaBehaviorValue value )
{
return string . Equals ( value . Kind , "legacy-id" , StringComparison . OrdinalIgnoreCase ) & &
! IsEmptyLegacyId ( value . LegacyIdValue ) & &
string . IsNullOrWhiteSpace ( value . ItemKeyValue ) ;
}
static bool IsEmptyLegacyId ( string legacyId )
{
return string . IsNullOrWhiteSpace ( legacyId ) | |
( Guid . TryParse ( legacyId , out var parsed ) & & parsed = = Guid . Empty ) ;
}
2026-06-13 07:54:30 +01:00
static async Task RequireLegacyLookupAsync < T > (
string legacyId ,
Func < Task < T ? > > lookup ,
string label ) where T : class
{
if ( string . IsNullOrWhiteSpace ( legacyId ) )
{
throw new InvalidOperationException ( $"Cannot verify {label}: legacy id is empty." ) ;
}
var value = await lookup ( ) . ConfigureAwait ( false ) ;
if ( value = = null )
{
throw new InvalidOperationException ( $"Typed legacy-id lookup failed for {label} {legacyId}." ) ;
}
}