Type Unity dependency ownership

This commit is contained in:
Meta Vens 2026-07-09 16:03:45 +01:00
commit 9dc4e0ef81
16 changed files with 341 additions and 25 deletions

View file

@ -557,8 +557,9 @@ Recently cut:
`testables` manifest mutation. The lifecycle smoke validates the runner
script and Aetheria project, parity compares the contract against the ledger,
and the runtime-owner consumer smoke asserts exported test fields. This is
Unity package consumption proof for CultLib-produced assemblies; CultLib
remains the owner of the .NET/NuGet dependency story.
Unity package consumption proof for CultLib-produced assemblies; the test
contract names those CultLib-owned NuGet/precompiled assembly inputs
explicitly. CultLib remains the owner of the .NET/NuGet dependency story.
- EveUnity release lifecycle now carries a structured UPM release contract.
`packages/org.gamecult.eve.unity-uitoolkit/eve-runtime-capability.json`
names the package root, version source, tag pattern, artifact kind, and
@ -566,10 +567,11 @@ Recently cut:
`tools/eveunity/eveunity-release-contract.mjs` now builds a
`gamecult.eve.runtime_release_request.v1` request from the runtime capability
manifest and UPM package manifest, deriving the `eveunity-uitoolkit-v{version}`
tag, package dependency set, and UPM artifact path. The lifecycle smoke
validates that contract against the package manifest, parity compares it
against the ledger, and the runtime-owner consumer smoke asserts the exported
release fields without pretending the tagged EveUnity release already exists.
tag, package dependency set, required package dependency owners, and UPM
artifact path. The lifecycle smoke validates that contract against the package
manifest, parity compares it against the ledger, and the runtime-owner
consumer smoke asserts the exported release fields without pretending the
tagged EveUnity release already exists.
- EveUnity capture lifecycle now carries a structured pending capture contract.
`captureContract` names the Unity UI Toolkit runtime, capture kind, PNG
artifact pattern, conformance attachment point, required Aetheria provider
@ -852,11 +854,12 @@ Recently cut:
`GameCult.Eve.UnityUIToolkit.Tests` in Unity batchmode, writes XML and log
artifacts under `artifacts/aetheria-unity-editmode`, and restores
`Packages/manifest.json` before returning. The Brokkr/CultMesh DLL references
in the Unity test asmdef are Unity package assembly plumbing: CultLib already
owns the .NET/NuGet dependency story. EveUnity's split blocker is proving how
the Unity package resolves those assemblies after it leaves Eve incubation,
not inventing a dependency system for CultLib. This proves the incubating test
lifecycle; it does not make Eve own Unity's final runtime lifecycle.
in the Unity test asmdef are now mirrored by
`testContract.managedAssemblyDependencies`, with CultLib named as the
NuGet/package owner. EveUnity's split blocker is proving how the Unity package
resolves those assemblies after it leaves Eve incubation, not inventing a
dependency system for CultLib. This proves the incubating test lifecycle; it
does not make Eve own Unity's final runtime lifecycle.
- Aetheria now has repeatable Unity package consumer-build evidence for the
Eve UI Toolkit runtime. `scripts/run-aetheria-unity-package-smoke.ps1`
verifies Aetheria's Unity `Packages/manifest.json` consumes Eve's surface and

View file

@ -404,10 +404,12 @@ exist. The current lifecycle proof is deliberately split:
- release: `tools/eveunity/eveunity-release-contract.mjs` builds a typed
`gamecult.eve.runtime_release_request.v1` request from the runtime capability
manifest and UPM package manifest; the tagged EveUnity release remains a
split blocker;
manifest and UPM package manifest, including required package dependency
owners; the tagged EveUnity release remains a split blocker;
- test: package-owned EditMode tests run through Aetheria in Unity batchmode,
and Aetheria can build the package through Unity's generated project;
and Aetheria can build the package through Unity's generated project. The
test contract names CultLib-owned NuGet/precompiled assembly inputs without
making EveUnity own CultLib package distribution;
- capture: `tools/eveunity/eveunity-capture-contract.mjs` builds a typed
`gamecult.eve.runtime_capture_request.v1` request from the runtime capability
manifest and Aetheria provider advertisement; Unity editor or batchmode PNG

View file

@ -50,16 +50,18 @@ its version from `package.json`, and uses tag pattern
`tools/eveunity/eveunity-release-contract.mjs` builds a
`gamecult.eve.runtime_release_request.v1` request from the runtime capability
manifest and UPM package manifest. The request names the package version, tag,
artifact path, dependency set, and target `GameCult/EveUnity` repository without
pretending Eve has published the tagged release.
artifact path, dependency set, required package dependency owners, and target
`GameCult/EveUnity` repository without pretending Eve has published the tagged
release.
The test stage declares the Unity EditMode runner contract: the current runner
is `scripts/run-aetheria-unity-editmode-tests.ps1`, runs
`GameCult.Eve.UnityUIToolkit.Tests` on `EditMode`, writes XML and log artifacts
under `artifacts/aetheria-unity-editmode/{stamp}`, and temporarily adds
`org.gamecult.eve.unity-uitoolkit` to Aetheria's Unity `testables`. This is a
Unity package consumption proof. CultLib still owns the .NET/NuGet dependency
story for its assemblies.
Unity package consumption proof. The test contract names the CultLib-owned
NuGet/precompiled assembly inputs Unity needs during incubation; CultLib still
owns the .NET/NuGet dependency story for its assemblies.
The capture stage declares `gamecult.eve.runtime_capture_request.v1` request
construction through `tools/eveunity/eveunity-capture-contract.mjs`. That

View file

@ -81,7 +81,16 @@
"requestSchema": "gamecult.eve.runtime_release_request.v1",
"requestBuilder": "tools/eveunity/eveunity-release-contract.mjs",
"artifactPattern": "artifacts/eveunity-uitoolkit-release/{version}/org.gamecult.eve.unity-uitoolkit-{version}.tgz",
"publishProof": "Tagged UPM release is created from the EveUnity repo and references this package root."
"publishProof": "Tagged UPM release is created from the EveUnity repo and references this package root.",
"requiredPackageDependencies": [
{
"packageName": "org.gamecult.eve.surface",
"version": "0.1.0",
"packageManager": "upm",
"ownerRepo": "Eve",
"purpose": "Shared Unity DTOs for gamecult.eve.surface.v1 documents."
}
]
},
"evidencePaths": [
"packages/org.gamecult.eve.unity-uitoolkit/package.json",
@ -110,7 +119,30 @@
"testPlatform": "EditMode",
"resultsArtifact": "artifacts/aetheria-unity-editmode/{stamp}/unity-editmode-results.xml",
"logArtifact": "artifacts/aetheria-unity-editmode/{stamp}/unity-editmode.log",
"manifestMutation": "Temporarily adds org.gamecult.eve.unity-uitoolkit to Aetheria Packages/manifest.json testables and restores the manifest after the run."
"manifestMutation": "Temporarily adds org.gamecult.eve.unity-uitoolkit to Aetheria Packages/manifest.json testables and restores the manifest after the run.",
"managedAssemblyDependencies": [
{
"assemblyName": "GameCult.Caching.dll",
"packageId": "GameCult.Caching",
"packageManager": "nuget",
"ownerRepo": "CultLib",
"resolutionMode": "Unity precompiled reference during EveUnity incubation."
},
{
"assemblyName": "GameCult.Mesh.dll",
"packageId": "GameCult.Mesh",
"packageManager": "nuget",
"ownerRepo": "CultLib",
"resolutionMode": "Unity precompiled reference during EveUnity incubation."
},
{
"assemblyName": "MessagePack.Annotations.dll",
"packageId": "MessagePack.Annotations",
"packageManager": "nuget",
"ownerRepo": "CultLib",
"resolutionMode": "Unity precompiled reference during EveUnity incubation."
}
]
},
"evidencePaths": [
"packages/org.gamecult.eve.unity-uitoolkit/Tests/Editor/GameCult.Eve.UnityUIToolkit.Tests.asmdef",

View file

@ -87,7 +87,16 @@
"requestSchema": "gamecult.eve.runtime_release_request.v1",
"requestBuilder": "tools/eveunity/eveunity-release-contract.mjs",
"artifactPattern": "artifacts/eveunity-scene-release/{version}/org.gamecult.eve.unity-scene-{version}.tgz",
"publishProof": "Tagged Unity scene package release is created from the EveUnity repo and references the provider-agnostic scene package root."
"publishProof": "Tagged Unity scene package release is created from the EveUnity repo and references the provider-agnostic scene package root.",
"requiredPackageDependencies": [
{
"packageName": "org.gamecult.eve.surface",
"version": "0.1.0",
"packageManager": "upm",
"ownerRepo": "Eve",
"purpose": "Shared Unity DTOs for gamecult.eve.surface.v1 documents."
}
]
},
"evidencePaths": [
"runtimes/incubating/eve-unity-scene/package.json",

View file

@ -254,6 +254,40 @@
"publishProof": {
"type": "string",
"minLength": 1
},
"requiredPackageDependencies": {
"type": "array",
"items": {
"type": "object",
"required": [
"packageName",
"version",
"packageManager",
"ownerRepo"
],
"properties": {
"packageName": {
"type": "string",
"minLength": 1
},
"version": {
"type": "string",
"minLength": 1
},
"packageManager": {
"type": "string",
"minLength": 1
},
"ownerRepo": {
"type": "string",
"minLength": 1
},
"purpose": {
"type": "string"
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
@ -352,6 +386,42 @@
"manifestMutation": {
"type": "string",
"minLength": 1
},
"managedAssemblyDependencies": {
"type": "array",
"items": {
"type": "object",
"required": [
"assemblyName",
"packageId",
"packageManager",
"ownerRepo",
"resolutionMode"
],
"properties": {
"assemblyName": {
"type": "string",
"minLength": 1
},
"packageId": {
"type": "string",
"minLength": 1
},
"packageManager": {
"type": "string",
"minLength": 1
},
"ownerRepo": {
"type": "string",
"minLength": 1
},
"resolutionMode": {
"type": "string",
"minLength": 1
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true

View file

@ -81,6 +81,40 @@
"dependencies": {
"type": "object"
},
"requiredPackageDependencies": {
"type": "array",
"items": {
"type": "object",
"required": [
"packageName",
"version",
"packageManager",
"ownerRepo"
],
"properties": {
"packageName": {
"type": "string",
"minLength": 1
},
"version": {
"type": "string",
"minLength": 1
},
"packageManager": {
"type": "string",
"minLength": 1
},
"ownerRepo": {
"type": "string",
"minLength": 1
},
"purpose": {
"type": "string"
}
},
"additionalProperties": true
}
},
"devDependencies": {
"type": "object"
}

View file

@ -130,6 +130,16 @@ if (-not $packageManifest.version) {
if ($packageManifest.dependencies."org.gamecult.eve.surface" -ne "0.1.0") {
throw "EveUnity package manifest missing org.gamecult.eve.surface dependency"
}
$surfaceDependency = @($releaseContract.requiredPackageDependencies) | Where-Object { $_.packageName -eq "org.gamecult.eve.surface" } | Select-Object -First 1
if (-not $surfaceDependency) {
throw "EveUnity release contract missing required org.gamecult.eve.surface dependency contract"
}
if ($surfaceDependency.ownerRepo -ne "Eve" -or $surfaceDependency.packageManager -ne "upm") {
throw "EveUnity release contract has unexpected surface dependency owner/package manager: $($surfaceDependency.ownerRepo)/$($surfaceDependency.packageManager)"
}
if ($surfaceDependency.version -ne $packageManifest.dependencies."org.gamecult.eve.surface") {
throw "EveUnity release contract surface dependency version mismatch: $($surfaceDependency.version)"
}
& (Join-Path $projectRoot "scripts\run-eveunity-release-contract-smoke.ps1")
if ($LASTEXITCODE -ne 0) {
@ -155,6 +165,25 @@ if ($testContract.testAssembly -ne "GameCult.Eve.UnityUIToolkit.Tests") {
if ($testContract.testPlatform -ne "EditMode") {
throw "EveUnity test contract has unexpected test platform: $($testContract.testPlatform)"
}
$managedDependencies = @($testContract.managedAssemblyDependencies)
$testAssemblyDefinitionPath = Join-Path $projectRoot "packages\org.gamecult.eve.unity-uitoolkit\Tests\Editor\GameCult.Eve.UnityUIToolkit.Tests.asmdef"
$testAssemblyDefinition = Get-Content -LiteralPath $testAssemblyDefinitionPath -Raw | ConvertFrom-Json
foreach ($dependency in @(
@{ assemblyName = "GameCult.Caching.dll"; packageId = "GameCult.Caching" },
@{ assemblyName = "GameCult.Mesh.dll"; packageId = "GameCult.Mesh" },
@{ assemblyName = "MessagePack.Annotations.dll"; packageId = "MessagePack.Annotations" }
)) {
$record = $managedDependencies | Where-Object { $_.assemblyName -eq $dependency.assemblyName } | Select-Object -First 1
if (-not $record) {
throw "EveUnity test contract missing managed assembly dependency: $($dependency.assemblyName)"
}
if ($record.packageId -ne $dependency.packageId -or $record.packageManager -ne "nuget" -or $record.ownerRepo -ne "CultLib") {
throw "EveUnity test contract has unexpected managed dependency record for $($dependency.assemblyName)"
}
if (-not (@($testAssemblyDefinition.precompiledReferences) -contains $dependency.assemblyName)) {
throw "EveUnity test asmdef missing managed dependency precompiled reference: $($dependency.assemblyName)"
}
}
foreach ($pathProperty in @("runnerScript", "consumerProject")) {
$candidate = $testContract.$pathProperty
if (-not $candidate) {

View file

@ -91,5 +91,15 @@ if ($request.artifactPath -ne $expectedArtifactPath) {
if ($request.dependencies."org.gamecult.eve.surface" -ne $packageManifest.dependencies."org.gamecult.eve.surface") {
throw "EveUnity release request lost org.gamecult.eve.surface dependency"
}
$surfaceDependency = @($request.requiredPackageDependencies) | Where-Object { $_.packageName -eq "org.gamecult.eve.surface" } | Select-Object -First 1
if (-not $surfaceDependency) {
throw "EveUnity release request missing required org.gamecult.eve.surface dependency contract"
}
if ($surfaceDependency.ownerRepo -ne "Eve" -or $surfaceDependency.packageManager -ne "upm") {
throw "EveUnity release request has unexpected surface dependency owner/package manager: $($surfaceDependency.ownerRepo)/$($surfaceDependency.packageManager)"
}
if ($surfaceDependency.version -ne $packageManifest.dependencies."org.gamecult.eve.surface") {
throw "EveUnity release request surface dependency version mismatch: $($surfaceDependency.version)"
}
Write-Host "EveUnity release contract smoke passed: $absoluteOutputPath"

View file

@ -164,6 +164,17 @@ foreach ($pathProperty in @("requestBuilder")) {
throw "EveUnity scene release contract $pathProperty does not exist: $relativePath"
}
}
$packageManifest = Get-Content -LiteralPath (Join-Path $projectRoot $releaseContract.versionSource) -Raw | ConvertFrom-Json
$surfaceDependency = @($releaseContract.requiredPackageDependencies) | Where-Object { $_.packageName -eq "org.gamecult.eve.surface" } | Select-Object -First 1
if (-not $surfaceDependency) {
throw "EveUnity scene release contract missing required org.gamecult.eve.surface dependency contract"
}
if ($surfaceDependency.ownerRepo -ne "Eve" -or $surfaceDependency.packageManager -ne "upm") {
throw "EveUnity scene release contract has unexpected surface dependency owner/package manager: $($surfaceDependency.ownerRepo)/$($surfaceDependency.packageManager)"
}
if ($surfaceDependency.version -ne $packageManifest.dependencies."org.gamecult.eve.surface") {
throw "EveUnity scene release contract surface dependency version mismatch: $($surfaceDependency.version)"
}
$testContract = $manifest.lifecycle.test.testContract
foreach ($field in @("ownerRepo", "runnerKind", "runnerScript", "consumerProject", "packageName", "testAssembly", "testPlatform", "resultsArtifact", "logArtifact", "manifestMutation")) {

View file

@ -94,5 +94,15 @@ if ($request.artifactPath -ne $expectedArtifactPath) {
if ($request.dependencies."org.gamecult.eve.surface" -ne $packageManifest.dependencies."org.gamecult.eve.surface") {
throw "EveUnity scene release request lost org.gamecult.eve.surface dependency"
}
$surfaceDependency = @($request.requiredPackageDependencies) | Where-Object { $_.packageName -eq "org.gamecult.eve.surface" } | Select-Object -First 1
if (-not $surfaceDependency) {
throw "EveUnity scene release request missing required org.gamecult.eve.surface dependency contract"
}
if ($surfaceDependency.ownerRepo -ne "Eve" -or $surfaceDependency.packageManager -ne "upm") {
throw "EveUnity scene release request has unexpected surface dependency owner/package manager: $($surfaceDependency.ownerRepo)/$($surfaceDependency.packageManager)"
}
if ($surfaceDependency.version -ne $packageManifest.dependencies."org.gamecult.eve.surface") {
throw "EveUnity scene release request surface dependency version mismatch: $($surfaceDependency.version)"
}
Write-Host "EveUnity scene release contract smoke passed: $absoluteOutputPath"

View file

@ -165,11 +165,17 @@ node $consumerScript $consumerExport `
--expect-runtime-lifecycle-field "unity-uitoolkit:release:releaseContract.artifactPattern:artifacts/eveunity-uitoolkit-release/{version}/org.gamecult.eve.unity-uitoolkit-{version}.tgz" `
--expect-runtime-lifecycle-field "unity-uitoolkit:release:releaseContract.tagPattern:eveunity-uitoolkit-v{version}" `
--expect-runtime-lifecycle-field "unity-uitoolkit:release:releaseContract.packageRoot:packages/org.gamecult.eve.unity-uitoolkit" `
--expect-runtime-lifecycle-field "unity-uitoolkit:release:releaseContract.requiredPackageDependencies.0.packageName:org.gamecult.eve.surface" `
--expect-runtime-lifecycle-field "unity-uitoolkit:release:releaseContract.requiredPackageDependencies.0.ownerRepo:Eve" `
--expect-runtime-lifecycle-field "unity-uitoolkit:release:releaseContract.requiredPackageDependencies.0.packageManager:upm" `
--expect-runtime-lifecycle-field "unity-uitoolkit:test:testContract.runnerKind:unity-editmode-batchmode" `
--expect-runtime-lifecycle-field "unity-uitoolkit:test:testContract.runnerScript:scripts/run-aetheria-unity-editmode-tests.ps1" `
--expect-runtime-lifecycle-field "unity-uitoolkit:test:testContract.packageName:org.gamecult.eve.unity-uitoolkit" `
--expect-runtime-lifecycle-field "unity-uitoolkit:test:testContract.testAssembly:GameCult.Eve.UnityUIToolkit.Tests" `
--expect-runtime-lifecycle-field "unity-uitoolkit:test:testContract.testPlatform:EditMode" `
--expect-runtime-lifecycle-field "unity-uitoolkit:test:testContract.managedAssemblyDependencies.0.ownerRepo:CultLib" `
--expect-runtime-lifecycle-field "unity-uitoolkit:test:testContract.managedAssemblyDependencies.0.packageManager:nuget" `
--expect-runtime-lifecycle-field "unity-uitoolkit:test:testContract.managedAssemblyDependencies.1.packageId:GameCult.Mesh" `
--expect-runtime-lifecycle-field "unity-uitoolkit:capture:captureContract.captureKind:unity-editor-or-batchmode-png" `
--expect-runtime-lifecycle-field "unity-uitoolkit:capture:captureContract.artifactKind:png" `
--expect-runtime-lifecycle-field "unity-uitoolkit:capture:captureContract.targetId:unity-uitoolkit" `
@ -192,6 +198,9 @@ node $consumerScript $consumerExport `
--expect-runtime-lifecycle-field "unity-scene:release:releaseContract.requestSchema:gamecult.eve.runtime_release_request.v1" `
--expect-runtime-lifecycle-field "unity-scene:release:releaseContract.requestBuilder:tools/eveunity/eveunity-release-contract.mjs" `
--expect-runtime-lifecycle-field "unity-scene:release:releaseContract.artifactPattern:artifacts/eveunity-scene-release/{version}/org.gamecult.eve.unity-scene-{version}.tgz" `
--expect-runtime-lifecycle-field "unity-scene:release:releaseContract.requiredPackageDependencies.0.packageName:org.gamecult.eve.surface" `
--expect-runtime-lifecycle-field "unity-scene:release:releaseContract.requiredPackageDependencies.0.ownerRepo:Eve" `
--expect-runtime-lifecycle-field "unity-scene:release:releaseContract.requiredPackageDependencies.0.packageManager:upm" `
--expect-runtime-lifecycle-field "unity-scene:test:testContract.runnerKind:unity-scene-provider-shell-smoke" `
--expect-runtime-lifecycle-field "unity-scene:test:testContract.runnerScript:scripts/run-eveunity-scene-provider-shell-smoke.ps1" `
--expect-runtime-lifecycle-field "unity-scene:capture:captureContract.captureKind:unity-scene-frame-png" `

View file

@ -27,8 +27,21 @@ export function buildUnityReleaseRequest({
if (!packageManifest.version || !/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(packageManifest.version)) {
throw new Error(`package version is not a SemVer-compatible release version: ${packageManifest.version || "missing"}`);
}
if (packageManifest.dependencies && !packageManifest.dependencies["org.gamecult.eve.surface"]) {
throw new Error("Unity UI Toolkit package must depend on org.gamecult.eve.surface");
const requiredPackageDependencies = Array.isArray(releaseContract.requiredPackageDependencies)
? releaseContract.requiredPackageDependencies
: [{ packageName: "org.gamecult.eve.surface", version: "0.1.0", packageManager: "upm", ownerRepo: "Eve" }];
const packageDependencies = packageManifest.dependencies || {};
for (const dependency of requiredPackageDependencies) {
if (!dependency?.packageName) {
throw new Error("release contract requiredPackageDependencies entries must name packageName");
}
const actualVersion = packageDependencies[dependency.packageName];
if (!actualVersion) {
throw new Error(`${releaseContract.packageName} must depend on ${dependency.packageName}`);
}
if (dependency.version && actualVersion !== dependency.version) {
throw new Error(`${releaseContract.packageName} dependency ${dependency.packageName} expected ${dependency.version} got ${actualVersion}`);
}
}
const tagName = replaceVersion(releaseContract.tagPattern, packageManifest.version);
@ -54,6 +67,7 @@ export function buildUnityReleaseRequest({
sourceCapabilityManifestPath: capabilityManifestPath,
sourcePackageManifestPath: packageManifestPath,
dependencies: packageManifest.dependencies || {},
requiredPackageDependencies,
};
}

View file

@ -27,6 +27,15 @@ test("builds EveUnity UPM release request from package manifest", () => {
assert.equal(request.artifactKind, "upm-package");
assert.equal(request.artifactPath, "artifacts/eveunity-uitoolkit-release/0.1.0/org.gamecult.eve.unity-uitoolkit-0.1.0.tgz");
assert.equal(request.dependencies["org.gamecult.eve.surface"], "0.1.0");
assert.deepEqual(request.requiredPackageDependencies, [
{
packageName: "org.gamecult.eve.surface",
version: "0.1.0",
packageManager: "upm",
ownerRepo: "Eve",
purpose: "Shared Unity DTOs for gamecult.eve.surface.v1 documents.",
},
]);
});
test("rejects package manifests that do not match the release contract package", () => {
@ -38,6 +47,15 @@ test("rejects package manifests that do not match the release contract package",
);
});
test("rejects package manifests missing required UPM dependencies", () => {
const missingDependencyPackage = { ...packageManifest, dependencies: {} };
assert.throws(
() => buildUnityReleaseRequest({ capabilityManifest, packageManifest: missingDependencyPackage }),
/must depend on org\.gamecult\.eve\.surface/,
);
});
test("builds EveUnity scene UPM release request from package manifest", () => {
const request = buildUnityReleaseRequest({
capabilityManifest: sceneCapabilityManifest,
@ -57,4 +75,5 @@ test("builds EveUnity scene UPM release request from package manifest", () => {
assert.equal(request.artifactKind, "upm-package");
assert.equal(request.artifactPath, "artifacts/eveunity-scene-release/0.1.0/org.gamecult.eve.unity-scene-0.1.0.tgz");
assert.equal(request.dependencies["org.gamecult.eve.surface"], "0.1.0");
assert.equal(request.requiredPackageDependencies[0].ownerRepo, "Eve");
});

View file

@ -1569,7 +1569,16 @@
"requestSchema": "gamecult.eve.runtime_release_request.v1",
"requestBuilder": "tools/eveunity/eveunity-release-contract.mjs",
"artifactPattern": "artifacts/eveunity-uitoolkit-release/{version}/org.gamecult.eve.unity-uitoolkit-{version}.tgz",
"publishProof": "Tagged UPM release is created from the EveUnity repo and references this package root."
"publishProof": "Tagged UPM release is created from the EveUnity repo and references this package root.",
"requiredPackageDependencies": [
{
"packageName": "org.gamecult.eve.surface",
"version": "0.1.0",
"packageManager": "upm",
"ownerRepo": "Eve",
"purpose": "Shared Unity DTOs for gamecult.eve.surface.v1 documents."
}
]
},
"evidencePaths": [
"packages/org.gamecult.eve.unity-uitoolkit/package.json",
@ -1598,7 +1607,30 @@
"testPlatform": "EditMode",
"resultsArtifact": "artifacts/aetheria-unity-editmode/{stamp}/unity-editmode-results.xml",
"logArtifact": "artifacts/aetheria-unity-editmode/{stamp}/unity-editmode.log",
"manifestMutation": "Temporarily adds org.gamecult.eve.unity-uitoolkit to Aetheria Packages/manifest.json testables and restores the manifest after the run."
"manifestMutation": "Temporarily adds org.gamecult.eve.unity-uitoolkit to Aetheria Packages/manifest.json testables and restores the manifest after the run.",
"managedAssemblyDependencies": [
{
"assemblyName": "GameCult.Caching.dll",
"packageId": "GameCult.Caching",
"packageManager": "nuget",
"ownerRepo": "CultLib",
"resolutionMode": "Unity precompiled reference during EveUnity incubation."
},
{
"assemblyName": "GameCult.Mesh.dll",
"packageId": "GameCult.Mesh",
"packageManager": "nuget",
"ownerRepo": "CultLib",
"resolutionMode": "Unity precompiled reference during EveUnity incubation."
},
{
"assemblyName": "MessagePack.Annotations.dll",
"packageId": "MessagePack.Annotations",
"packageManager": "nuget",
"ownerRepo": "CultLib",
"resolutionMode": "Unity precompiled reference during EveUnity incubation."
}
]
},
"evidencePaths": [
"packages/org.gamecult.eve.unity-uitoolkit/Tests/Editor/GameCult.Eve.UnityUIToolkit.Tests.asmdef",

View file

@ -1541,6 +1541,12 @@ function compareTestContract(expected, actual, label) {
if (actual.consumerProject && !existsSync(actual.consumerProject)) {
errors.push(`${label}.consumerProject:${actual.consumerProject}:missing`);
}
errors.push(...compareDependencyRecords(
expected.managedAssemblyDependencies || [],
actual.managedAssemblyDependencies || [],
`${label}.managedAssemblyDependencies`,
["assemblyName", "packageId", "packageManager", "ownerRepo", "resolutionMode"],
));
return errors;
}
@ -1561,6 +1567,30 @@ function compareReleaseContract(expected, actual, label) {
errors.push(`${label}.${key}:${actual[key]}:missing`);
}
}
errors.push(...compareDependencyRecords(
expected.requiredPackageDependencies || [],
actual.requiredPackageDependencies || [],
`${label}.requiredPackageDependencies`,
["packageName", "version", "packageManager", "ownerRepo", "purpose"],
));
return errors;
}
function compareDependencyRecords(expectedRecords, actualRecords, label, keys) {
const errors = [];
for (const expected of expectedRecords) {
const identityKey = expected.packageName ? "packageName" : "assemblyName";
const actual = actualRecords.find(candidate => candidate?.[identityKey] === expected[identityKey]);
if (!actual) {
errors.push(`${label}:${expected[identityKey]}:missing`);
continue;
}
for (const key of keys) {
if ((expected[key] || "") !== (actual[key] || "")) {
errors.push(`${label}:${expected[identityKey]}.${key}:expected ${expected[key] || ""} got ${actual[key] || ""}`);
}
}
}
return errors;
}