Prove released Aetheria gameplay witness
This commit is contained in:
parent
81db8e9661
commit
2f05a81517
6 changed files with 141 additions and 46 deletions
|
|
@ -522,7 +522,13 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
var inputDriver = root.GetComponent<EveUnityPlayableWorldInputDriver>() ??
|
||||
root.AddComponent<EveUnityPlayableWorldInputDriver>();
|
||||
inputDriver.Host = host;
|
||||
var action = inputDriver.SubmitPrimaryAction();
|
||||
var primaryActionId = EveUnityPlayableWorldInputDriver.ResolvePrimaryActionId(host.InputCapability);
|
||||
Assert.That(primaryActionId, Is.Not.Empty,
|
||||
"The advertised input capability did not bind a primary action for this generic client.");
|
||||
var primaryAction = EveUnityAdvertisedInputAction.Resolve(host.InputCapability, primaryActionId);
|
||||
Assert.That(primaryAction.IsButtonHold, Is.True,
|
||||
"The witness primary action must be driven through its advertised held-input semantics.");
|
||||
var action = inputDriver.SubmitActionValue(primaryActionId, 1f);
|
||||
Assert.That(action, Is.Not.Null,
|
||||
"The advertised input capability did not bind a primary action for this generic client.");
|
||||
var actionDeadline = Time.realtimeSinceStartup + 12f;
|
||||
|
|
@ -569,6 +575,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
"Daemon destruction did not publish its guaranteed cargo as a pickup.");
|
||||
var collectionDeadline = Time.realtimeSinceStartup + 15f;
|
||||
var nextTractorAimAt = 0f;
|
||||
var salvageApproachActive = false;
|
||||
while (Time.realtimeSinceStartup < collectionDeadline &&
|
||||
(expectCargoRejection ? pickupRejection == null : pickupCollection == null))
|
||||
{
|
||||
|
|
@ -589,23 +596,27 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
continue;
|
||||
tractorAim.Normalize();
|
||||
runtime.SubmitLookDirectionIntent(playerId, tractorAim.x, 0f, tractorAim.z);
|
||||
runtime.SubmitMoveVectorIntent(playerId, 0f, 1f, 1f);
|
||||
salvageApproachActive = true;
|
||||
nextTractorAimAt = Time.realtimeSinceStartup + 0.25f;
|
||||
}
|
||||
if (salvageApproachActive)
|
||||
runtime.SubmitMoveVectorIntent(playerId, 0f, 0f, 0f);
|
||||
finalPickupEntityCount = host.PresentedEntities.CurrentGeneration.Entities.Count(entity =>
|
||||
string.Equals(entity.EntityKind, "pickup", StringComparison.Ordinal));
|
||||
if (expectCargoRejection)
|
||||
{
|
||||
Assert.That(pickupRejection, Is.Not.Null,
|
||||
"Full cargo did not reject destruction salvage from its Ymir contact fact.");
|
||||
"Full cargo did not reject destruction salvage at daemon pickup proximity.");
|
||||
Assert.That(pickupRejectionEventCount, Is.EqualTo(1),
|
||||
"The first destruction-loot Ymir contact transaction must emit one rejection event.");
|
||||
"The first destruction-loot proximity attempt must emit one rejection event.");
|
||||
Assert.That(pickupRejectionEventIds.Count, Is.EqualTo(pickupRejectionEventCount),
|
||||
"One Ymir fact identity emitted duplicate player rejection feedback.");
|
||||
"One daemon proximity attempt emitted duplicate player rejection feedback.");
|
||||
Assert.That(pickupCollectionEventCount, Is.Zero,
|
||||
"Capacity-rejected salvage was also collected.");
|
||||
Assert.That(pickupRejection.ItemKey, Is.Not.Empty);
|
||||
Assert.That(pickupRejection.EventId, Does.StartWith("ymir-fact:"),
|
||||
"Rejection feedback must retain the consumed Ymir fact identity.");
|
||||
Assert.That(pickupRejection.EventId, Does.StartWith("frame:"),
|
||||
"Capacity feedback must retain its daemon frame/zone/pickup attempt identity.");
|
||||
Assert.That(pickupRejection.Reason, Is.EqualTo("cargo-capacity"));
|
||||
Assert.That(pickupRejection.ScalarValue, Is.EqualTo(1));
|
||||
Assert.That(pickupRejection.CargoQuantityAfter,
|
||||
|
|
@ -616,15 +627,15 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
else
|
||||
{
|
||||
Assert.That(pickupCollection, Is.Not.Null,
|
||||
"Destruction-created salvage never reached cargo through a Ymir contact fact.");
|
||||
"Destruction-created salvage never reached cargo through daemon pickup proximity.");
|
||||
Assert.That(pickupCollectionEventCount, Is.EqualTo(1),
|
||||
"One destruction-loot Ymir contact transaction must emit one collection event.");
|
||||
"One durable destruction pickup must emit one collection event.");
|
||||
Assert.That(pickupRejectionEventCount, Is.Zero,
|
||||
"Collectible destruction salvage was also rejected.");
|
||||
Assert.That(pickupCollection.ItemKey, Is.Not.Empty,
|
||||
"Destruction loot must retain its canonical typed item identity.");
|
||||
Assert.That(pickupCollection.EventId, Does.StartWith("ymir-fact:"),
|
||||
"Collection feedback must retain the consumed Ymir fact identity.");
|
||||
Assert.That(pickupCollection.EventId, Does.StartWith("zone:"),
|
||||
"Collection feedback must retain its stable daemon zone/pickup identity.");
|
||||
Assert.That(pickupCollection.ScalarValue, Is.EqualTo(1));
|
||||
Assert.That(pickupCollection.CargoQuantityBefore, Is.Zero);
|
||||
Assert.That(pickupCollection.CargoQuantityAfter, Is.EqualTo(1));
|
||||
|
|
@ -1127,8 +1138,8 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
pickupCollectionEventCount == 0 &&
|
||||
string.Equals(pickupRejection.Reason, "cargo-capacity", StringComparison.Ordinal) &&
|
||||
pickupRejection.CargoQuantityAfter == pickupRejection.CargoQuantityBefore,
|
||||
destructionLoot = (pickupCollection?.EventId ?? pickupRejection?.EventId ?? "")
|
||||
.StartsWith("ymir-fact:", StringComparison.Ordinal),
|
||||
destructionLoot = pickupEvent != null && !string.IsNullOrWhiteSpace(pickupEvent.EventId) &&
|
||||
!string.IsNullOrWhiteSpace(pickupEvent.ItemKey) && pickupEvent.ScalarValue > 0,
|
||||
initialPickupEntityCount = initialPickupEntityCount,
|
||||
finalPickupEntityCount = finalPickupEntityCount,
|
||||
pickupCollectionEventCount = pickupCollectionEventCount,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
"com.unity.modules.physics": "1.0.0",
|
||||
"com.unity.modules.uielements": "1.0.0",
|
||||
"com.unity.render-pipelines.universal": "17.4.0",
|
||||
"org.gamecult.cultlib": "https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.15",
|
||||
"org.gamecult.cultlib": "https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.16",
|
||||
"org.gamecult.eve.plugin-fields": "https://github.com/GameCult/EvePlugins.git?path=/plugins/eve-plugin-fields/unity/org.gamecult.eve.plugin-fields#eve-plugin-fields-unity-v0.2.3",
|
||||
"org.gamecult.eve.surface": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.surface#eveunity-surface-v0.2.4",
|
||||
"org.gamecult.eve.unity-scene": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.65",
|
||||
|
|
|
|||
|
|
@ -119,11 +119,11 @@
|
|||
}
|
||||
},
|
||||
"org.gamecult.cultlib": {
|
||||
"version": "https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.15",
|
||||
"version": "https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.16",
|
||||
"depth": 0,
|
||||
"source": "git",
|
||||
"dependencies": {},
|
||||
"hash": "419053ebe2325848051c4f4d8ba352cd4286c424"
|
||||
"hash": "69caf2d027c49227e62ffa24452fc7d717f86ca5"
|
||||
},
|
||||
"org.gamecult.eve.plugin-fields": {
|
||||
"version": "https://github.com/GameCult/EvePlugins.git?path=/plugins/eve-plugin-fields/unity/org.gamecult.eve.plugin-fields#eve-plugin-fields-unity-v0.2.3",
|
||||
|
|
|
|||
|
|
@ -522,7 +522,13 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
var inputDriver = root.GetComponent<EveUnityPlayableWorldInputDriver>() ??
|
||||
root.AddComponent<EveUnityPlayableWorldInputDriver>();
|
||||
inputDriver.Host = host;
|
||||
var action = inputDriver.SubmitPrimaryAction();
|
||||
var primaryActionId = EveUnityPlayableWorldInputDriver.ResolvePrimaryActionId(host.InputCapability);
|
||||
Assert.That(primaryActionId, Is.Not.Empty,
|
||||
"The advertised input capability did not bind a primary action for this generic client.");
|
||||
var primaryAction = EveUnityAdvertisedInputAction.Resolve(host.InputCapability, primaryActionId);
|
||||
Assert.That(primaryAction.IsButtonHold, Is.True,
|
||||
"The witness primary action must be driven through its advertised held-input semantics.");
|
||||
var action = inputDriver.SubmitActionValue(primaryActionId, 1f);
|
||||
Assert.That(action, Is.Not.Null,
|
||||
"The advertised input capability did not bind a primary action for this generic client.");
|
||||
var actionDeadline = Time.realtimeSinceStartup + 12f;
|
||||
|
|
@ -569,6 +575,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
"Daemon destruction did not publish its guaranteed cargo as a pickup.");
|
||||
var collectionDeadline = Time.realtimeSinceStartup + 15f;
|
||||
var nextTractorAimAt = 0f;
|
||||
var salvageApproachActive = false;
|
||||
while (Time.realtimeSinceStartup < collectionDeadline &&
|
||||
(expectCargoRejection ? pickupRejection == null : pickupCollection == null))
|
||||
{
|
||||
|
|
@ -589,23 +596,27 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
continue;
|
||||
tractorAim.Normalize();
|
||||
runtime.SubmitLookDirectionIntent(playerId, tractorAim.x, 0f, tractorAim.z);
|
||||
runtime.SubmitMoveVectorIntent(playerId, 0f, 1f, 1f);
|
||||
salvageApproachActive = true;
|
||||
nextTractorAimAt = Time.realtimeSinceStartup + 0.25f;
|
||||
}
|
||||
if (salvageApproachActive)
|
||||
runtime.SubmitMoveVectorIntent(playerId, 0f, 0f, 0f);
|
||||
finalPickupEntityCount = host.PresentedEntities.CurrentGeneration.Entities.Count(entity =>
|
||||
string.Equals(entity.EntityKind, "pickup", StringComparison.Ordinal));
|
||||
if (expectCargoRejection)
|
||||
{
|
||||
Assert.That(pickupRejection, Is.Not.Null,
|
||||
"Full cargo did not reject destruction salvage from its Ymir contact fact.");
|
||||
"Full cargo did not reject destruction salvage at daemon pickup proximity.");
|
||||
Assert.That(pickupRejectionEventCount, Is.EqualTo(1),
|
||||
"The first destruction-loot Ymir contact transaction must emit one rejection event.");
|
||||
"The first destruction-loot proximity attempt must emit one rejection event.");
|
||||
Assert.That(pickupRejectionEventIds.Count, Is.EqualTo(pickupRejectionEventCount),
|
||||
"One Ymir fact identity emitted duplicate player rejection feedback.");
|
||||
"One daemon proximity attempt emitted duplicate player rejection feedback.");
|
||||
Assert.That(pickupCollectionEventCount, Is.Zero,
|
||||
"Capacity-rejected salvage was also collected.");
|
||||
Assert.That(pickupRejection.ItemKey, Is.Not.Empty);
|
||||
Assert.That(pickupRejection.EventId, Does.StartWith("ymir-fact:"),
|
||||
"Rejection feedback must retain the consumed Ymir fact identity.");
|
||||
Assert.That(pickupRejection.EventId, Does.StartWith("frame:"),
|
||||
"Capacity feedback must retain its daemon frame/zone/pickup attempt identity.");
|
||||
Assert.That(pickupRejection.Reason, Is.EqualTo("cargo-capacity"));
|
||||
Assert.That(pickupRejection.ScalarValue, Is.EqualTo(1));
|
||||
Assert.That(pickupRejection.CargoQuantityAfter,
|
||||
|
|
@ -616,15 +627,15 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
else
|
||||
{
|
||||
Assert.That(pickupCollection, Is.Not.Null,
|
||||
"Destruction-created salvage never reached cargo through a Ymir contact fact.");
|
||||
"Destruction-created salvage never reached cargo through daemon pickup proximity.");
|
||||
Assert.That(pickupCollectionEventCount, Is.EqualTo(1),
|
||||
"One destruction-loot Ymir contact transaction must emit one collection event.");
|
||||
"One durable destruction pickup must emit one collection event.");
|
||||
Assert.That(pickupRejectionEventCount, Is.Zero,
|
||||
"Collectible destruction salvage was also rejected.");
|
||||
Assert.That(pickupCollection.ItemKey, Is.Not.Empty,
|
||||
"Destruction loot must retain its canonical typed item identity.");
|
||||
Assert.That(pickupCollection.EventId, Does.StartWith("ymir-fact:"),
|
||||
"Collection feedback must retain the consumed Ymir fact identity.");
|
||||
Assert.That(pickupCollection.EventId, Does.StartWith("zone:"),
|
||||
"Collection feedback must retain its stable daemon zone/pickup identity.");
|
||||
Assert.That(pickupCollection.ScalarValue, Is.EqualTo(1));
|
||||
Assert.That(pickupCollection.CargoQuantityBefore, Is.Zero);
|
||||
Assert.That(pickupCollection.CargoQuantityAfter, Is.EqualTo(1));
|
||||
|
|
@ -1127,8 +1138,8 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
pickupCollectionEventCount == 0 &&
|
||||
string.Equals(pickupRejection.Reason, "cargo-capacity", StringComparison.Ordinal) &&
|
||||
pickupRejection.CargoQuantityAfter == pickupRejection.CargoQuantityBefore,
|
||||
destructionLoot = (pickupCollection?.EventId ?? pickupRejection?.EventId ?? "")
|
||||
.StartsWith("ymir-fact:", StringComparison.Ordinal),
|
||||
destructionLoot = pickupEvent != null && !string.IsNullOrWhiteSpace(pickupEvent.EventId) &&
|
||||
!string.IsNullOrWhiteSpace(pickupEvent.ItemKey) && pickupEvent.ScalarValue > 0,
|
||||
initialPickupEntityCount = initialPickupEntityCount,
|
||||
finalPickupEntityCount = finalPickupEntityCount,
|
||||
pickupCollectionEventCount = pickupCollectionEventCount,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,49 @@
|
|||
# Aetheria released-package witness
|
||||
|
||||
## Current result
|
||||
## Current integration gate
|
||||
|
||||
The released-package cold world witness passes with:
|
||||
The generic `ReleaseConsumerProject` is pinned to released Git packages:
|
||||
|
||||
- `org.gamecult.eve.unity-scene` `0.3.65` and
|
||||
`org.gamecult.eve.surface` `0.2.4`, commit
|
||||
`e08fa08335f99e9edddeb706912eecfad07cb281`;
|
||||
- `org.gamecult.eve.plugin-fields` `0.2.3`, commit
|
||||
`c5a4a75c1b727499b16c2dae1895f29e2a9f72f0`;
|
||||
- `org.gamecult.eve.unity-uitoolkit` `0.1.1`, commit
|
||||
`4d0cbe0185bdc4fc65eb63503a7c5cb578539669`;
|
||||
- `org.gamecult.cultlib` `1.0.16`, commit
|
||||
`69caf2d027c49227e62ffa24452fc7d717f86ca5`.
|
||||
|
||||
The hand-run integration gate is the warm released-package witness:
|
||||
|
||||
```powershell
|
||||
pwsh -File .\scripts\run-aetheria-daemon-world-witness.ps1 `
|
||||
-CacheState warm `
|
||||
-AssetCacheDirectory artifacts\aetheria-daemon-temporal-projection-0363-warm-hd\asset-cache `
|
||||
-OutputDirectory artifacts\aetheria-manual-integration `
|
||||
-PrimeWarmCacheFromProviderBundle
|
||||
```
|
||||
|
||||
It connects directly to the Aetheria daemon and must produce one passing
|
||||
PlayMode result, a pilot capture, a map-only capture, and typed witness facts.
|
||||
The current assertions require provider-owned assets, movement, camera-channel
|
||||
isolation, combat, destruction-created loot, daemon-owned XZ proximity
|
||||
collection or capacity refusal, held tractor input, and authoritative receipts.
|
||||
They do not require or accept Ymir contact identity as the owner of looting.
|
||||
The explicit prime flag rebuilds the provider bundle and installs that exact
|
||||
content-hashed body into the local warm cache. This is convenient local setup,
|
||||
not CDN-transfer evidence. On later runs, use `-SkipAssetBundleBuild` and omit
|
||||
the prime flag when neither provider assets nor their catalog changed.
|
||||
|
||||
Cold transfer is not a passing integration gate. The current bundle is
|
||||
`56,193,661` bytes and recent cold runs still exceed the 300-second witness
|
||||
deadline while asset bytes travel through batched snapshot records. Do not
|
||||
increase the timeout or describe this as proven; the intended repair is mapped
|
||||
or network-body transport. `-CacheState cold` remains a diagnostic run.
|
||||
|
||||
## Historical witness ledger
|
||||
|
||||
An earlier released-package cold world witness passed with:
|
||||
|
||||
- `org.gamecult.eve.unity-scene` `0.3.63`, commit
|
||||
`3135d24bb84f40719b121b51634811c85af0a7af`;
|
||||
|
|
@ -275,9 +316,15 @@ Primary artifacts:
|
|||
- `aetheria-daemon-world.png`: pilot-camera capture;
|
||||
- `aetheria-daemon-map.png`: map-only capture.
|
||||
|
||||
## Cold delivery proof
|
||||
## Cold delivery status
|
||||
|
||||
Cold CDN transfer passes with the current released package set. The
|
||||
Cold CDN transfer is currently failing and is not part of the passing readiness
|
||||
gate. The latest retained failing runs time out after 300 seconds before the
|
||||
provider bundle is promoted. The current transport still carries large asset
|
||||
payloads through batched snapshot records instead of the intended mapped or
|
||||
network body path.
|
||||
|
||||
The following is historical evidence, not a current claim. A prior
|
||||
`cold-start-lowering` run in `artifacts/aetheria-daemon-current-cold` began with
|
||||
zero cached bodies, received one typed manifest snapshot, transferred bounded
|
||||
payload chunks through the managed CultMesh content session, and atomically
|
||||
|
|
@ -288,9 +335,9 @@ lowered the shield-free provider hull, and preserved pilot/map camera isolation
|
|||
within the unchanged 300-second deadline; total witness time was `102,912.852`
|
||||
milliseconds.
|
||||
|
||||
The separate passing `full-session-gameplay` witness starts from the verified
|
||||
warm body and proves movement, combat, destruction-created canonical loot, Ymir
|
||||
contact collection, and exactly-once cargo mutation. This proves cold acquisition
|
||||
The separate historical `full-session-gameplay` witness started from the verified
|
||||
warm body and proved movement, combat, destruction-created canonical loot, and
|
||||
exactly-once cargo mutation. This proved cold acquisition
|
||||
and local mapped reuse, not provider-to-client network zero-copy, shared-memory
|
||||
delivery, or GPU zero-copy. Managed network bytes are still copied and fragmented
|
||||
before the transfer owner commits the mapped file.
|
||||
|
|
|
|||
|
|
@ -7,10 +7,12 @@ param(
|
|||
[string] $ClientProject = "ReleaseConsumerProject",
|
||||
[int] $Port = 3076,
|
||||
[string] $OutputDirectory = "artifacts\aetheria-daemon",
|
||||
[string] $AssetCacheDirectory = "",
|
||||
[ValidateSet("auto", "cold", "warm")]
|
||||
[string] $CacheState = "auto",
|
||||
[string] $CacheState = "warm",
|
||||
[ValidateSet("released-client-proof", "cargo-capacity-rejection-proof")]
|
||||
[string] $GameplayScenario = "released-client-proof",
|
||||
[switch] $PrimeWarmCacheFromProviderBundle,
|
||||
[switch] $SkipAssetBundleBuild
|
||||
)
|
||||
|
||||
|
|
@ -18,10 +20,17 @@ $ErrorActionPreference = "Stop"
|
|||
$expectedEveUnityCommit = "e08fa08335f99e9edddeb706912eecfad07cb281"
|
||||
$expectedEveFieldsCommit = "c5a4a75c1b727499b16c2dae1895f29e2a9f72f0"
|
||||
$expectedEveUnityUiToolkitCommit = "4d0cbe0185bdc4fc65eb63503a7c5cb578539669"
|
||||
$expectedCultLibCommit = "419053ebe2325848051c4f4d8ba352cd4286c424"
|
||||
$expectedCultLibCommit = "69caf2d027c49227e62ffa24452fc7d717f86ca5"
|
||||
$repoRoot = Split-Path -Parent $PSScriptRoot
|
||||
$projectRoot = $ClientProject
|
||||
$outputRoot = if ([IO.Path]::IsPathRooted($OutputDirectory)) { $OutputDirectory } else { Join-Path $repoRoot $OutputDirectory }
|
||||
$assetCachePath = if ([string]::IsNullOrWhiteSpace($AssetCacheDirectory)) {
|
||||
Join-Path $outputRoot "asset-cache"
|
||||
} elseif ([IO.Path]::IsPathRooted($AssetCacheDirectory)) {
|
||||
$AssetCacheDirectory
|
||||
} else {
|
||||
Join-Path $repoRoot $AssetCacheDirectory
|
||||
}
|
||||
$resultsPath = Join-Path $outputRoot "results.xml"
|
||||
$unityLogPath = Join-Path $outputRoot "unity.log"
|
||||
$bundleBuildLogPath = Join-Path $outputRoot "asset-bundle-build.log"
|
||||
|
|
@ -32,7 +41,6 @@ $factsPath = Join-Path $outputRoot "witness-facts.json"
|
|||
$providerReadyPath = Join-Path $outputRoot "provider-ready.txt"
|
||||
$witnessPath = Join-Path $outputRoot "runtime-witness.json"
|
||||
$replicaPath = Join-Path $outputRoot "eve-unity-replica.cc"
|
||||
$assetCachePath = Join-Path $outputRoot "asset-cache"
|
||||
$statePath = Join-Path $outputRoot "aetheria-witness-state.cc"
|
||||
$providerBundlePath = Join-Path $AetheriaRoot "Build\EveAssets\StandaloneWindows64\aetheria-world"
|
||||
$daemonProject = Join-Path $AetheriaRoot "Aetheria.State.Daemon\Aetheria.State.Daemon.csproj"
|
||||
|
|
@ -63,10 +71,7 @@ if ($CacheState -eq "cold" -and ($initialBodyCount -ne 0 -or $initialPartialCoun
|
|||
throw "Cold witness cache was not empty before Unity launch. bodies=$initialBodyCount partials=$initialPartialCount"
|
||||
}
|
||||
$cacheWasWarm = @(Get-ChildItem -LiteralPath $assetCachePath -Filter *.body -File -ErrorAction SilentlyContinue).Count -gt 0
|
||||
if ($CacheState -eq "warm" -and -not $cacheWasWarm) {
|
||||
throw "Warm witness requested without an existing verified bundle cache at $assetCachePath"
|
||||
}
|
||||
$observedCacheState = if ($cacheWasWarm) { "warm" } else { "cold" }
|
||||
$observedCacheState = if ($CacheState -eq "warm") { "warm" } elseif ($cacheWasWarm) { "warm" } else { "cold" }
|
||||
$witnessProfile = if ($observedCacheState -eq "cold") {
|
||||
"cold-start-lowering"
|
||||
} else {
|
||||
|
|
@ -119,15 +124,36 @@ if (-not $SkipAssetBundleBuild) {
|
|||
Write-Host "AssetBundle builder PID: $($bundleBuilder.Id)"
|
||||
Write-Host "AssetBundle build log: $bundleBuildLogPath"
|
||||
Write-Host "Poll: Get-Content '$bundleBuildLogPath' -Tail 20"
|
||||
if (-not $bundleBuilder.WaitForExit(240000)) {
|
||||
if (-not $bundleBuilder.WaitForExit(360000)) {
|
||||
Stop-Process -Id $bundleBuilder.Id -Force -ErrorAction SilentlyContinue
|
||||
throw "Aetheria AssetBundle build exceeded 240 seconds. See $bundleBuildLogPath"
|
||||
throw "Aetheria AssetBundle build exceeded 360 seconds. See $bundleBuildLogPath"
|
||||
}
|
||||
if ($bundleBuilder.ExitCode -ne 0) {
|
||||
Get-Content $bundleBuildLogPath -Tail 160
|
||||
throw "Aetheria AssetBundle build failed with exit code $($bundleBuilder.ExitCode)"
|
||||
}
|
||||
}
|
||||
if ($PrimeWarmCacheFromProviderBundle) {
|
||||
if ($CacheState -ne "warm") {
|
||||
throw "Local provider-bundle priming is only valid for an explicitly warm witness."
|
||||
}
|
||||
if (-not (Test-Path -LiteralPath $providerBundlePath)) {
|
||||
throw "Provider-owned Aetheria bundle is missing: $providerBundlePath"
|
||||
}
|
||||
New-Item -ItemType Directory -Force -Path $assetCachePath | Out-Null
|
||||
$primeHash = (Get-FileHash -LiteralPath $providerBundlePath -Algorithm SHA256).Hash.ToLowerInvariant()
|
||||
$primeTarget = Join-Path $assetCachePath "$primeHash.body"
|
||||
if (-not (Test-Path -LiteralPath $primeTarget)) {
|
||||
$primePartial = Join-Path $assetCachePath "$primeHash.partial.local-prime"
|
||||
Copy-Item -LiteralPath $providerBundlePath -Destination $primePartial -Force
|
||||
if ((Get-FileHash -LiteralPath $primePartial -Algorithm SHA256).Hash.ToLowerInvariant() -ne $primeHash) {
|
||||
Remove-Item -LiteralPath $primePartial -Force -ErrorAction SilentlyContinue
|
||||
throw "Locally primed provider bundle failed its content-hash check."
|
||||
}
|
||||
Move-Item -LiteralPath $primePartial -Destination $primeTarget -Force
|
||||
}
|
||||
Write-Host "Warm cache primed locally from the provider bundle; this is not CDN-transfer evidence: $primeTarget"
|
||||
}
|
||||
if ($CacheState -eq "warm") {
|
||||
if (-not (Test-Path -LiteralPath $providerBundlePath)) {
|
||||
throw "Provider-owned Aetheria bundle is missing: $providerBundlePath"
|
||||
|
|
@ -278,17 +304,17 @@ try {
|
|||
if ($witnessProfile -eq "full-session-gameplay") {
|
||||
if (-not $facts.combatPresentation -or [string]::IsNullOrWhiteSpace($facts.shotId) -or
|
||||
[double]$facts.lockProgress -le 0.99 -or -not $facts.destructionLoot) {
|
||||
throw "Full-session witness did not prove combat and Ymir-contact destruction loot."
|
||||
throw "Full-session witness did not prove combat and daemon-proximity destruction loot."
|
||||
}
|
||||
if ($GameplayScenario -eq "cargo-capacity-rejection-proof") {
|
||||
if ($facts.gameplayScenario -ne $GameplayScenario -or -not $facts.pickupRejection -or
|
||||
[int]$facts.pickupRejectionEventCount -lt 1 -or [int]$facts.pickupCollectionEventCount -ne 0 -or
|
||||
$facts.pickupRejectionReason -ne "cargo-capacity" -or
|
||||
[double]$facts.cargoQuantityBeforeRejection -ne [double]$facts.cargoQuantityAfterRejection) {
|
||||
throw "Full-session rejection witness did not prove player cargo-capacity refusal from distinct Ymir contact facts."
|
||||
throw "Full-session rejection witness did not prove player cargo-capacity refusal at daemon pickup proximity."
|
||||
}
|
||||
} elseif (-not $facts.pickupCollection -or [int]$facts.pickupCollectionEventCount -ne 1) {
|
||||
throw "Full-session collection witness did not prove exactly-once player destruction-loot collection from a Ymir contact fact."
|
||||
throw "Full-session collection witness did not prove exactly-once player destruction-loot collection at daemon pickup proximity."
|
||||
}
|
||||
}
|
||||
$releaseLock = Get-Content -LiteralPath (Join-Path $repoRoot "ReleaseConsumerProject\Packages\packages-lock.json") -Raw | ConvertFrom-Json
|
||||
|
|
|
|||
Reference in a new issue