Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/perf/shipping-fidelity-il2cpp-low-profile.v1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"schemaVersion": 1,
"profileId": "shipping-fidelity-il2cpp-low-player-v1",
"configuration": {
"buildTarget": "StandaloneWindows64",
"scriptingBackend": "IL2CPP",
"apiCompatibilityLevel": "NET_Standard_2_0",
"codeOptimization": "Release",
"il2cppCompilerConfiguration": "Release",
"il2cppCodeGeneration": "OptimizeSpeed",
"managedStrippingLevel": "Low",
"incrementalGc": true,
"stripEngineCode": true
},
"buildOptions": {
"developmentBuild": false,
"allowDebugging": false,
"deepProfiling": false,
"enableAssertions": false,
"includeTestAssemblies": false,
"autoRunPlayer": false,
"connectToHost": false,
"connectWithProfiler": false,
"cleanBuildCache": true,
"detailedBuildReport": true
},
"runtime": {
"debugBuild": false
}
}
30 changes: 30 additions & 0 deletions .github/perf/shipping-fidelity-il2cpp-medium-profile.v1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"schemaVersion": 1,
"profileId": "shipping-fidelity-il2cpp-medium-player-v1",
"configuration": {
"buildTarget": "StandaloneWindows64",
"scriptingBackend": "IL2CPP",
"apiCompatibilityLevel": "NET_Standard_2_0",
"codeOptimization": "Release",
"il2cppCompilerConfiguration": "Release",
"il2cppCodeGeneration": "OptimizeSpeed",
"managedStrippingLevel": "Medium",
"incrementalGc": true,
"stripEngineCode": true
},
"buildOptions": {
"developmentBuild": false,
"allowDebugging": false,
"deepProfiling": false,
"enableAssertions": false,
"includeTestAssemblies": false,
"autoRunPlayer": false,
"connectToHost": false,
"connectWithProfiler": false,
"cleanBuildCache": true,
"detailedBuildReport": true
},
"runtime": {
"debugBuild": false
}
}
30 changes: 30 additions & 0 deletions .github/perf/shipping-fidelity-il2cpp-minimal-profile.v1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"schemaVersion": 1,
"profileId": "shipping-fidelity-il2cpp-minimal-player-v1",
"configuration": {
"buildTarget": "StandaloneWindows64",
"scriptingBackend": "IL2CPP",
"apiCompatibilityLevel": "NET_Standard_2_0",
"codeOptimization": "Release",
"il2cppCompilerConfiguration": "Release",
"il2cppCodeGeneration": "OptimizeSpeed",
"managedStrippingLevel": "Minimal",
"incrementalGc": true,
"stripEngineCode": true
},
"buildOptions": {
"developmentBuild": false,
"allowDebugging": false,
"deepProfiling": false,
"enableAssertions": false,
"includeTestAssemblies": false,
"autoRunPlayer": false,
"connectToHost": false,
"connectWithProfiler": false,
"cleanBuildCache": true,
"detailedBuildReport": true
},
"runtime": {
"debugBuild": false
}
}
46 changes: 27 additions & 19 deletions .github/workflows/unity-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -469,11 +469,11 @@ jobs:
-ReleaseCodeOptimization `
-ReleasePlayerBuild

# Run the shipping-fidelity slice on the oldest and newest supported
# editors. Keep it last because it builds a second IL2CPP player, and the
# central cleanup action below returns the final activation before the
# editor-scoped organization lock is released.
- name: Run stripped shipping-fidelity player
# Run all shipping-fidelity stripping levels on the oldest and newest
# supported editors. Keep the group last because each cell builds another
# IL2CPP player, and the central cleanup action below returns the final
# activation before the editor-scoped organization lock is released.
- name: Run stripped shipping-fidelity players
id: run_shipping
if: >-
${{
Expand All @@ -490,22 +490,30 @@ jobs:
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
UNITY_ACCELERATOR_ENDPOINT: ${{ secrets.UNITY_ACCELERATOR_ENDPOINT }}
run: |
$projectPath = Join-Path $env:RUNNER_WORKSPACE 'dxm-u\t\${{ matrix.unity-version }}-shipping'
$cachePath = Join-Path $env:RUNNER_WORKSPACE 'dxm-c\${{ matrix.unity-version }}'
./scripts/unity/run-ci-tests.ps1 `
-UnityVersion '${{ matrix.unity-version }}' `
-UnityInstallRoot (Join-Path $env:RUNNER_TOOL_CACHE 'u6-v3') `
-TestMode shipping `
-AssemblyNames '' `
-ArtifactsPath '.artifacts/unity/${{ matrix.unity-version }}-shipping' `
-ProjectPath $projectPath `
-CachePath $cachePath `
-CanonicalProfilePath '.github/perf/shipping-fidelity-il2cpp-profile.v1.json' `
-LicenseReturnOwner Central `
-ReleaseCodeOptimization `
-ReleasePlayerBuild
$shippingProfiles = @(
@{ Level = 'minimal'; Path = '.github/perf/shipping-fidelity-il2cpp-minimal-profile.v1.json' },
@{ Level = 'low'; Path = '.github/perf/shipping-fidelity-il2cpp-low-profile.v1.json' },
@{ Level = 'medium'; Path = '.github/perf/shipping-fidelity-il2cpp-medium-profile.v1.json' },
@{ Level = 'high'; Path = '.github/perf/shipping-fidelity-il2cpp-profile.v1.json' }
)
foreach ($shippingProfile in $shippingProfiles) {
$projectPath = Join-Path $env:RUNNER_WORKSPACE "dxm-u\t\${{ matrix.unity-version }}-shipping-$($shippingProfile.Level)"
./scripts/unity/run-ci-tests.ps1 `
-UnityVersion '${{ matrix.unity-version }}' `
-UnityInstallRoot (Join-Path $env:RUNNER_TOOL_CACHE 'u6-v3') `
-TestMode shipping `
-AssemblyNames '' `
-ArtifactsPath ".artifacts/unity/${{ matrix.unity-version }}-shipping/$($shippingProfile.Level)" `
-ProjectPath $projectPath `
-CachePath $cachePath `
-CanonicalProfilePath $shippingProfile.Path `
-LicenseReturnOwner Central `
-ReleaseCodeOptimization `
-ReleasePlayerBuild
}
Comment thread
cursor[bot] marked this conversation as resolved.
Outdated
Comment thread
cursor[bot] marked this conversation as resolved.
Outdated

# A mode failure is tolerated until the test modes and shipping slice have
# A mode failure is tolerated until the test modes and shipping group have
# had a chance to run. Preserve diagnostics and result verification, then fail
# the editor-scoped job from one summary gate before central cleanup.
- name: Dump EditMode log tail on failure or cancellation
Expand Down
15 changes: 9 additions & 6 deletions .llm/skills/il2cpp-build-configuration/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,11 @@ fidelity leg additionally takes `-TestMode shipping` and the shipping profile.
is mandatory for test players. Default stripping deletes the benchmark
assemblies and the `[Preserve]` standalone test-run callback, and the player
then runs nothing.
- `.github/perf/shipping-fidelity-il2cpp-profile.v1.json` pins High stripping
and `includeTestAssemblies=false` for the separate shipping consumer. That
player builds through `BuildPipeline` and must not use Unity Test Framework.
- The four shipping-fidelity profiles under `.github/perf/` pin Minimal, Low,
Medium, and High stripping with `includeTestAssemblies=false`. The existing
`shipping-fidelity-il2cpp-profile.v1.json` is the High profile. Each separate
shipping consumer builds through `BuildPipeline` and must not use Unity Test
Framework.
- Pin `Il2CppCodeGeneration.OptimizeSpeed`, incremental GC, and engine-code
stripping from the canonical profile. Do not rely on an ephemeral project's
defaults.
Expand All @@ -93,9 +95,10 @@ fidelity leg additionally takes `-TestMode shipping` and the shipping profile.
- Never publish a Debug number. `perf-numbers.yml` publishes only the Standalone
IL2CPP Release leg; manually dispatched `unity-benchmarks.yml` supplies
per-version editor coverage and allocation evidence.
- The Unity Tests workflow runs the shipping-fidelity player on the oldest and
newest supported editors. Its positive and missing-root runs use the same
binary and publish correctness evidence only, never throughput rows.
- The Unity Tests workflow builds every shipping-fidelity stripping level on
the oldest and newest supported editors. Each level's positive and
missing-root runs use the same binary and publish correctness evidence only,
never throughput rows.

### Backend split

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,20 +95,23 @@ execute and write results. The runner's `StandaloneScriptingBackend` parameter
defaults to `IL2CPP` and accepts `Mono2x`, so the same script can build either
backend; the published leg pins IL2CPP.

The separate shipping-fidelity player uses High managed stripping and excludes
test assemblies. It builds through `BuildPipeline.BuildPlayer` instead of Unity
Test Framework, then runs positive generated-root coverage and an expected
missing-root control from the same binary.
The separate shipping-fidelity cells use Minimal, Low, Medium, and High managed
stripping and exclude test assemblies. Each cell builds through
`BuildPipeline.BuildPlayer` instead of Unity Test Framework, then runs positive
generated-root coverage and an expected missing-root control from the same
binary.

## Canonical profile

`.github/perf/canonical-il2cpp-profile.v1.json` is the reviewed source of truth
for the published standalone IL2CPP leg.
`.github/perf/shipping-fidelity-il2cpp-profile.v1.json` is the reviewed source
of truth for the stripped correctness player. Each workflow passes its selected
file through `-CanonicalProfilePath`. The runner copies the exact bytes under
the source filename and writes a SHA-256 file to the run artifacts, then embeds
the profile ID and hash in generated editor and player code.
The four shipping-fidelity profiles under `.github/perf/` are the reviewed
sources of truth for the stripped correctness players. The existing
`.github/perf/shipping-fidelity-il2cpp-profile.v1.json` remains the High profile.
Each workflow passes its selected file through `-CanonicalProfilePath`. The
runner copies the exact bytes under the source filename and writes a SHA-256
file to the run artifacts, then embeds the profile ID and hash in generated
editor and player code.

The profile also pins `Il2CppCodeGeneration.OptimizeSpeed`, incremental GC,
engine-code stripping, and the final `BuildOptions` flags. Keep these values in
Expand Down Expand Up @@ -158,8 +161,9 @@ manually dispatched `unity-benchmarks.yml` runs the EditMode and PlayMode
benchmark tests across Unity versions with `-ReleaseCodeOptimization` for
coverage only.

The Unity Tests workflow runs the shipping-fidelity profile on the oldest and
newest supported editors. Its evidence is correctness-only and never enters the
The Unity Tests workflow runs all four shipping-fidelity profiles on the oldest
and newest supported editors. Each profile uses an isolated project and
artifact directory. Its evidence is correctness-only and never enters the
published benchmark baseline.

## Common Pitfalls
Expand Down
8 changes: 4 additions & 4 deletions .llm/skills/unity-editor-ci/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ The active Unity workflows run `scripts/unity/run-ci-tests.ps1` directly on self
Windows runners. `unity-tests.yml` is a four-version matrix. Each editor-scoped
job runs `editmode`, `playmode`, and `standalone` as separate invocations under
one lock and cleanup window. The oldest and current endpoint jobs also run the
stripped shipping-fidelity player. Both player modes build `StandaloneWindows64`
IL2CPP players from runner-local projects under
Minimal, Low, Medium, and High shipping-fidelity cells. All player modes build
`StandaloneWindows64` IL2CPP players from runner-local projects under
`$RUNNER_WORKSPACE/dxm-u/t/<version>-<mode>/`.

## When to use
Expand Down Expand Up @@ -54,7 +54,7 @@ IL2CPP players from runner-local projects under
- Timeout invariant: every step before and including the cleanup gate has an explicit positive
timeout. Editor validation is capped at `10`, and the acquire step cap (`305`) exceeds its
internal wait (`300`). Grouped correctness invocations use `90`/`90`/`150` caps, and the
endpoint-only shipping invocation uses `150`. Cleanup uses `5`/`2`/`5`/`2` for
endpoint-only shipping group uses `150`. Cleanup uses `5`/`2`/`5`/`2` for
return/classify/release/gate. `unity-tests.yml` uses a `1050`-minute job cap. Other licensed
jobs retain their `900`-minute cap. Each cap must retain at least 60 minutes beyond the sum
of its enforced step caps.
Expand All @@ -77,7 +77,7 @@ IL2CPP players from runner-local projects under

- CI must pass `-CiManagedOnly -RequireHealthyExisting` plus `-ProvisioningProfile`
explicitly. The grouped correctness job validates `StandaloneWindowsIl2Cpp` once because
that superset serves all test modes and the endpoint-only shipping invocation. Other jobs use
that superset serves all test modes and the endpoint-only shipping cells. Other jobs use
`EditorOnly` for editmode, playmode, benchmarks, and release checks, or
`StandaloneWindowsIl2Cpp` for standalone (verifies `windows-il2cpp`); `Android` and `Full`
remain manual-maintenance profiles.
Expand Down
13 changes: 7 additions & 6 deletions .llm/skills/unity-editor-ci/references/unity-ci-matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@

Four jobs each run three independent test modes. `editmode`/`playmode` run in-editor
on Mono; `standalone` builds and runs a `StandaloneWindows64` IL2CPP test player.
The oldest and current endpoint jobs also build and run the stripped
`StandaloneWindows64` IL2CPP shipping-fidelity player. Each invocation keeps its
own result verification, artifact, timeout, and runner-local project. The direct runner
The oldest and current endpoint jobs also build and run Minimal, Low, Medium,
and High `StandaloneWindows64` IL2CPP shipping-fidelity players. Each level
keeps its own result evidence and runner-local project inside the grouped
shipping step and artifact. The direct runner
generates a package host project under
`$RUNNER_WORKSPACE/dxm-u/t/<version>-<mode>/`, imports the repo package with a
`file:` dependency, and configures IL2CPP before either player build. Test hosts
Expand Down Expand Up @@ -70,13 +71,13 @@ With both controls, a run consumes at most one seat while another repository can
job timeout-minutes >= sum(all capped steps through cleanup gate) + 60
```

Editor validation is capped at 10 minutes. The acquire input `timeout-minutes: "300"` is the internal lock-poll budget. Its enclosing step has `timeout-minutes: 305`, so the action can finish and report a timeout before GitHub terminates the step. Grouped correctness test modes use 90/90/150-minute caps, and the endpoint-only shipping invocation uses 150 minutes. Return/classify/release/gate use 5/2/5/2 minutes. `unity-tests.yml` uses `timeout-minutes: 1050`; other licensed jobs retain `timeout-minutes: 900`. `scripts/validate-unity-pr-policy.py` sums every enforced step cap through the cleanup gate and requires at least 60 minutes of remaining job time.
Editor validation is capped at 10 minutes. The acquire input `timeout-minutes: "300"` is the internal lock-poll budget. Its enclosing step has `timeout-minutes: 305`, so the action can finish and report a timeout before GitHub terminates the step. Grouped correctness test modes use 90/90/150-minute caps, and the endpoint-only shipping group uses 150 minutes. Return/classify/release/gate use 5/2/5/2 minutes. `unity-tests.yml` uses `timeout-minutes: 1050`; other licensed jobs retain `timeout-minutes: 900`. `scripts/validate-unity-pr-policy.py` sums every enforced step cap through the cleanup gate and requires at least 60 minutes of remaining job time.

The step-level caps protect the in-use seat from a hung editor or ancillary action. They must remain strictly below the job timeout so the step fails first and the cleanup chain still runs. This matters because `stuck-job-watchdog.yml` ignores any `in_progress` job; without step caps, a wedged action can squat the seat until the whole job is cancelled.

Runner administrators manually install every exact editor and required module under `RUNNER_TOOL_CACHE/u6-v3`. Workflows validate that root with `-CiManagedOnly -RequireHealthyExisting` before acquiring the organization lock; they never install or repair editors. Release the lock only after the always-run return and cleanup-classification steps.

**Operator note (standalone IL2CPP):** the grouped correctness jobs require the Windows IL2CPP Unity module and the host build toolchain needed by Unity for Windows players. They validate the `StandaloneWindowsIl2Cpp` profile once before the lock, then reuse that editor for all test modes and the endpoint-only shipping invocation. Other workflows still select `EditorOnly` or `StandaloneWindowsIl2Cpp` according to their one mode. See [unity-editor-cli-bootstrap](./unity-editor-cli-bootstrap.md) for manual maintenance details.
**Operator note (standalone IL2CPP):** the grouped correctness jobs require the Windows IL2CPP Unity module and the host build toolchain needed by Unity for Windows players. They validate the `StandaloneWindowsIl2Cpp` profile once before the lock, then reuse that editor for all test modes and the endpoint-only shipping cells. Other workflows still select `EditorOnly` or `StandaloneWindowsIl2Cpp` according to their one mode. See [unity-editor-cli-bootstrap](./unity-editor-cli-bootstrap.md) for manual maintenance details.

`unity-benchmarks.yml` (active; manual-only, NEVER on PRs):

Expand All @@ -89,7 +90,7 @@ The active `unity-benchmarks.yml` explicitly omits `pull_request` and `push` per

## compute-unity-assemblies is-empty Gate

Every workflow that consumes `./.github/actions/compute-unity-assemblies` gives each Unity test invocation a stable compute id. Grouped correctness uses `compute`, `compute_playmode`, and `compute_standalone`; each test run receives only its matching assembly output through an environment variable. Test work skips when its selection is empty. The endpoint-only shipping invocation is not test-assembly-discovery gated. Lock acquisition remains unconditional because the static matrix is structurally non-empty and the organization analyzer must prove each acquisition. When asmdef discovery resolves no owned assemblies, verification treats the empty selection as an intentional skip while the terminal return/classify/release/gate chain still proves cleanup.
Every workflow that consumes `./.github/actions/compute-unity-assemblies` gives each Unity test invocation a stable compute id. Grouped correctness uses `compute`, `compute_playmode`, and `compute_standalone`; each test run receives only its matching assembly output through an environment variable. Test work skips when its selection is empty. The endpoint-only shipping group is not test-assembly-discovery gated. Lock acquisition remains unconditional because the static matrix is structurally non-empty and the organization analyzer must prove each acquisition. When asmdef discovery resolves no owned assemblies, verification treats the empty selection as an intentional skip while the terminal return/classify/release/gate chain still proves cleanup.

The `Verify tests actually ran` step keeps a cancellation-safe gate and must also require `steps.compute.outcome == 'success'` plus either `steps.compute.outputs.is-empty == 'true'` or a non-skipped Unity run step (never an is-empty gate alone). It receives `expected-empty: ${{ steps.compute.outputs.is-empty }}`, so an intentional skip reads as success rather than a "tests did not run" failure, while checkout/cache/setup/editor-validation/lock failures that prevent Unity from launching are not obscured by a generic missing-results annotation. The skip path does not fire for the current asmdef set; it is the robustness path for a target whose assemblies are all filtered out, such as a runtime-only standalone run when every DxMessaging test asmdef is editor-only.

Expand Down
Loading
Loading