Twinned from https://github.com/cfsh/ninefold/issues/1144 by tools/beads/import_github.py's reconcile pass.
Godot's C# script→class resolution can't instantiate a scene-attached script whose filename has more than one dot before .cs. That's exactly the shape STYLE_GUIDE.md §1.2 mandates for every Godot-runtime test: *.GodotTest.cs, paired with a sibling *_test.tscn that attaches it via script = ExtResource(...).
Confirmed live on the sandbox box (nf-dev-sg), Godot /opt/godot/Godot_v4.7.1-stable_mono_linux.x86_64, against the pre-existing games/tonapse/ControllerNav.GodotTest.cs + controller_nav_test.tscn (nothing in this repro touches either file):
``` $ "$GODOT_CONSOLE" --headless res://games/tonapse/controller_nav_test.tscn ... ERROR: Cannot instantiate C# script because the associated class could not be found. Script: 'res://games/tonapse/ControllerNav.GodotTest.cs'. Make sure the script exists and contains a class definition with a name that matches the filename of the script exactly (it's case-sensitive). at: can_instantiate (modules/mono/csharp_script.cpp:2358) ```
The process never quits after this — the node's script fails to instantiate, _Ready() never runs, and there's nothing left to call GetTree().Quit(), so it hangs forever. run_godot_tests.sh has presumably been silently broken (hangs, never PASS/FAIL) since whichever change last touched this path.
Ruled out before filing:
dotnet build Ninefold.sln — same error..godot/mono/temp/{bin,obj} entirely and rebuilt through Godot's own --build-solutions orchestration (not just dotnet build) — same error, on a genuinely fresh Ninefold.dll.strings -e l on the fresh DLL shows both ControllerNavTest and ScriptPathAttribute present in the assembly — the type compiles in fine, it's the runtime path→type resolution that fails.games/explore/explore_orbit.tscn → ExploreOrbit.cs, class ExploreOrbit) instantiates without error in the same environment — isolating the failure to the dotted-filename case specifically, not headless mode or this box in general.[GlobalClass] on the test class does not route around it (tried directly).```bash "$GODOT_CONSOLE" --headless res://games/tonapse/controller_nav_test.tscn # hangs; ^C after the ERROR line above appears ```
PR #1143 works around this for one new test by giving the scene a thin, normally-named shim script (e.g. PlanetOrbitGoldenRunner.cs, filename == class name) that the .tscn actually attaches, which just calls into the real .GodotTest.cs logic as a plain static method — sidestepping Godot's script-instantiation path entirely for the dotted file. See that PR's PlanetOrbitGolden.GodotTest.cs header comment for the full reasoning.
That shim is a one-off workaround, not a fix for the convention itself. Real options, roughly in order of how much churn they cost:
.GodotTest.cs gets a same-directory, normally-named runner .cs that owns the actual script = ExtResource(...) attachment. Cheapest, but it's a workaround baked into the convention rather than a fix, and needs a STYLE_GUIDE.md update documenting the required extra file._GodotTest.cs or GodotTest_Foo.cs) to something Godot's naive fallback can actually match against a legal C# identifier, if such a shape exists. Needs checking what Godot's can_instantiate fallback is actually parsing (this issue didn't get that far).Whoever picks this up should re-verify against whatever Godot version is current at the time — this was confirmed against 4.7.1.stable.mono specifically, and re-confirm run_godot_tests.sh actually reaches PASS afterward (it's not wired into presubmit.py/merge_pr.py, so nothing else will catch a regression here).
None.
No comments.