*.GodotTest.cs scenes fail to instantiate under godot --headless (confirmed on ControllerNav.GodotTest.cs) nf-q6v ← Beads

closed priority 2 task godot-dotted-cs activesession:godot-dotted-cs

Twinned from https://github.com/cfsh/ninefold/issues/1144 by tools/beads/import_github.py's reconcile pass.

What's broken

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.

Why this isn't a stale-build artifact

Ruled out before filing:

Repro

```bash "$GODOT_CONSOLE" --headless res://games/tonapse/controller_nav_test.tscn # hangs; ^C after the ERROR line above appears ```

Suggested fix shape

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:

  1. Apply the same shim pattern everywhere — every .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.
  2. Drop the second dot — rename the marker (e.g. _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).
  3. File upstream / pin a Godot version where this works, if it turns out to be a regression in 4.7.1 specifically rather than how Godot 4's C# script binding has always worked.

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).

Dependencies

None.

Comments

No comments.

Add a comment