Runtime console, first recorded boot
- Date: 2026-08-22
- Branch / commit:
purrnet-implementation@3b8cf3cb - Editor: Unity 6000.5.5f1 (
ProjectSettings/ProjectVersion.txt) - PurrNet:
dev.purrnet.purrnet1.19.1, vendored atAssets/PurrNet/ - Ticket: RIOT-83
How this was captured, and what that limits
Section titled “How this was captured, and what that limits”Not a GUI editor session. A throwaway [UnityTest] harness loaded build scene 0, subscribed to
Application.logMessageReceived at Info level, idled 30 seconds, and wrote every unique message
to a file. It ran batchmode, -nographics, against a disposable APFS clone of the project — never
the working copy.
Two reasons for that, both deliberate:
- Booting the working copy in a GUI editor risks re-serialising assets. That is not paranoia: the
Kaph SDF font atlas was found destroyed by exactly that mechanism earlier the same day
(RIOT-219), and
NewApartment.unityholds 45 components whose authored values only survive because nothing has re-saved the scene (RIOT-97, RIOT-45). - A headless run is reproducible and can be re-run by anyone, which a description of what someone saw on screen is not.
What this cost, stated plainly: the run never hosts. Nothing clicks “Host”, so no player spawns, no session starts, and the map is never loaded. Predictions 1, 2, 4 and 5 are therefore not-observed rather than confirmed or refuted. This is a partial discharge of RIOT-83, not a complete one. The remaining half needs a driven session — see What is still owed.
The harness is not committed. It leaked a DontDestroyOnLoad NetworkManager into the existing
PlayMode tests, which is a real constraint on whoever writes the permanent version: any boot test
must tear the manager down, or it poisons every test that runs after it. The CodegenCanaryTests
SetUp guard caught this immediately and named the cause, which is the guard working exactly as
designed.
The headline
Section titled “The headline”The game boots, and boots clean. Zero exceptions, zero errors. InitializeScene loads and
auto-advances to MainMenu at t+3s with no input. It then sits there, stable, for the remaining
27 seconds.
That is worth stating flatly because the audit’s 148 static findings invite the opposite assumption. The boot path is not the problem. Whatever is broken is downstream of pressing a button.
The six predictions
Section titled “The six predictions”| # | Prediction | Verdict |
|---|---|---|
| 1 | One NullReferenceException per player spawn from PlayerRoll |
not-observed — no player spawns without hosting |
| 2 | 45 missing-script errors loading NewApartment |
not-observed — map never loaded |
| 3 | Animator missing-behaviour warning | not-observed at runtime, but statically confirmed |
| 4 | PurrNetTest / HealthTest / StatusEffectTest surviving scene loads |
not-observed |
| 5 | PurrNet permission errors once a second peer joins | not testable here — single peer |
| 6 | Total silence | confirmed — not one audio message in 30 seconds |
Prediction 3 is confirmed by file inspection rather than console: RaccoonAnimator.controller:2165
holds m_Script: {fileID: 11500000, guid: 04d42aafecceaac4f97adcdeccc3328a, type: 3}, and that GUID
resolves to no .cs.meta anywhere under Assets or Packages. The warning did not appear because
the controller is never instantiated on this path.
Prediction 5’s premise is stale and the ticket should not be trusted on it. RIOT-83 states the
settings file sets guardFailureAction: ReturnDefault, and cites Assets/PurrNet/PurrNetSettings.asset.
That path does not exist. The live file is ProjectSettings/PurrNetSettings.asset and it reads
guardFailureAction: 3 (LogError) — changed in RIOT-121. So the ticket’s warning that “if the
console is quiet here, that is not good news” no longer applies: rejected guards now log errors
and a quiet console would be genuine.
Unpredicted findings
Section titled “Unpredicted findings”1. Ten missing-script warnings fire during boot, on objects that are in neither menu scene
Section titled “1. Ten missing-script warnings fire during boot, on objects that are in neither menu scene”Warning The referenced script (Unknown) on this Behaviour is missing!Warning The referenced script on this Behaviour (Game Object 'slippers (1)') is missing!Warning The referenced script on this Behaviour (Game Object 'radio') is missing!Warning The referenced script on this Behaviour (Game Object 'cake_birthday') is missing!Warning The referenced script on this Behaviour (Game Object 'food_ingredient_cheese') is missing!Warning The referenced script on this Behaviour (Game Object 'pillow_B (2)') is missing!Warning The referenced script on this Behaviour (Game Object 'pillow_B (1)') is missing!Warning The referenced script on this Behaviour (Game Object 'pillow_B') is missing!Warning The referenced script on this Behaviour (Game Object 'Payload') is missing!Warning The referenced script on this Behaviour (Game Object 'SimultaneousTransmitter') is missing!None of these object names appears in InitializeScene.unity or MainMenu.unity — verified by
direct grep, count 0 in both. They match the broken first-party prefab set from RIOT-25:
cake_birthday is a live prefab at Assets/RacoonRiot/Prefabs/Objects/Light/Attackable/.
So something instantiates or loads broken item prefabs during boot, before any gameplay scene.
The leading hypothesis is the network prefab registry — RIOT-183 records that prefabId is a
positional index over an auto-scan of the Assets root, which would mean the manager touches every
registered prefab at startup. That is a hypothesis, not a confirmed mechanism; it has not been traced
to a call site and should not be written up as fact until it has.
This matters beyond tidiness: if the registry really does load every scanned prefab, then RIOT-25’s
30 broken prefabs are a boot-time cost in every build, and RIOT-190 (DebugGun registered as
spawnable everywhere) is a symptom of the same design rather than an isolated slip.
2. An OpenFracture warning fires at boot
Section titled “2. An OpenFracture warning fires at boot”Warning Parent transform of fractured object must be uniformly scaled in all axes or fragments will not render correctly.Notable because RIOT-38 records that no first-party code calls OpenFracture. Something is nonetheless configured well enough to reach OpenFracture’s validation path at boot, and is misconfigured when it gets there.
3. Scene index 4 in the build list is a test-runner artifact, not a finding
Section titled “3. Scene index 4 in the build list is a test-runner artifact, not a finding”The harness reported a fifth build scene, Assets/InitTestScene<guid>.unity. EditorBuildSettings.asset
in the repository contains four scenes and no such entry; the Unity Test Framework injects it for
the duration of a PlayMode run. Recorded here only so the next reader does not re-investigate it.
What is still owed on RIOT-83
Section titled “What is still owed on RIOT-83”The half that needs a driven session, in one sitting:
- Click through Host → Lobby →
NewApartment, then idle 60s. This is what settles predictions 1, 2 and 4. - Prediction 5 needs a second peer.
LocalTransport.cs:17hardcasts a singleConnection, so an in-process session cannot produce one. The same-machine fallback is a standalone player against an editor host on loopback; a genuine two-machine test is blocked on RIOT-42 / RIOT-48 / RIOT-55. - Whether the raccoon spawns at all, and where players physically land given
NewApartmenthas zeroSpawnPointcomponents. - Whether
MainMenu’s unbounded connection wait ever completes.
The permanent version of this harness belongs to RIOT-165, and must dispose the NetworkManager in
teardown for the reason above.