Make your orc at the door, and change your mind at the barber's
Last week the orc you built finally turned up in the level. This week there is a way to build one.
In plain words
Last week the orc you built finally turned up in the level. This week there is a way to build one. Start Level 1 on a fresh save and the game stops and asks: pick a skin, a hat, a nose, feet. Before, the editor existed but nothing in the game ever opened it, so a new player got the grey placeholder ball and no way out of it. And because first choices are rarely final, rolling into a barber's chair reopens the same editor on the orc you already have, and the change lands on the ball in front of you straight away. The robot playtesters skip the whole thing — a modal that waits for a human would stall them until the heat death of the soak.
Under the hood
Two features and a housekeeping pass on checks that were not checking.
- Creation at the door (
9069fd7, #27). Shaped likestory_beats.gd: an autoload watchingcurrent_scene, keyed by level id, so no level scene is edited. That is not tidiness —level1.tscn's root isGameRoot, a C++ GDExtension type that cannot instantiate in a headless sandbox, so a scene-embedded node would have been untestable outside a full host build. It opens only on a creation level and only when the profile has no character; it seeds each slot from that slot's fallback, the one thing guaranteed ungated, so a brand-new profile can wear every slot; it passesUnlocks.gate_for(save)so earned parts stay earned. Cancel writes nothing —character_storeroutes a missing character back to creation rather than papering over it with a silent default. Two bugs the new tests caught while being written:const EditorScriptshadows a native Godot class and silently took the whole autoload down, and_close()calledget_tree()on a detached node, which logs an error before returning null. - The barber's chair (
0193b8f, #43). Both entry points instance the same editor throughCharacterCreation, so the tutorial chair and the shop cannot drift apart. Every judgement — playtest safety, refusing to stack a second editor, loading the existing character, saving over the right id — lives inreopen_for_edit(scene), which returns whether it opened so a caller can tell "opened" from "declined" without reaching into private state.scripts/barber_chair.gdis a deliberately logic-freeArea3D: it referencesPlayerBall, which comes from the C++ extension, so nothing in it can run headlessly. A real bug fixed in passing:_on_doneminted a new character id every time, so each visit would have written another.borcand orphaned the last one — invisible except as a growinguser://characters/. Suites now stand at 328 checks / 63 tests, all eight green. - The suites that gated nothing (
8a300d3, #101). CI rantests/character_formatand nothing else ran a suite at all, so 239 checks across five suites existed and stopped no regression from reaching main green. The case that prompted it: #17's guard against giving a multi-material component a colour region — which would flatten eyes to one colour, worse than the bug it fixes and invisible in a diff — lives intests/component_db, merged and never once run by CI. Suites are now discovered, not listed, each in its own engine invocation so one aborting cannot take the rest with it, and an absentproject/tests/dies rather than matching no glob and passing silently. - A correction to last week's last paragraph. We reported 117 of 120
screenshot anchors pixel-identical and blamed the three stragglers on the
lean smoothing still settling when the shot fires. The real cause is one
line (
2c0585c, #99 + #100):run_one(launcher, "camera", [], ...)passed the camera probe no engine flags at all. It is the only non-headless instance in the swarm, so it alone missed what--headlessimplies —--audio-driver Dummy, which is why eight headless bots log zero engine errors and the windowed probe logs one in a container with no sound device, and--fixed-fps, without which the probe runs in real time and the ball is somewhere slightly different when each shot fires. Spawn is the only anchor that frames the character; the rest are level geometry, which is why 117 were already stable. Not yet verified that the errors vanish — that needs a soak. Two consecutive runs on an unchanged tree should reportchanged: 0. - CI stopped building the same game for every typo (
de6c18e,bcfa93f). Measured 2026-07-26: four consecutive commits touched onlydocs/cowork-handoff.mdand each triggered four platform builds plus the soak — roughly 48 minutes of aconcurrent = 1runner per markdown edit, and 99% of all measured job time went there.rules:changesnow gates build, package and playtest. In the same breath the soak went automatic on main instead ofwhen: manual: the appearance forwarder went a week unexercised because nobody pressed the button, and when it finally ran all nine runs passed — so the gate bought nothing and hid the one check that could have said so. The follow-up commit is the joke writing itself:tools/playtest/**was missing from the path list, so a change to the soak runner would not have triggered the soak. The soak's own source, unsoaked. - Four yellow runs nobody read (
793d493).dependency-freshnesshad failed 4 of 4 runs in the last 20 pipelines. Not stale dependencies — a comparison that can never be equal:godot-cppis pinned to10.0-master-20260629because the<cstdint>fix is master-only, while every upstream release tag looks likegodot-4.5-stable. The fix is to consult whatversions.lockalready declares one line below (GODOT_CPP_GIT_TAG="", "no tag exists for this pin"), so comparison resumes on its own the day someone re-pins. A second defect surfaced while testing it, same theme as everything above:(could not query)never setbehind, so a total network failure printed "All queryable dependencies are current" and exited 0 — six failed queries reported as a clean bill of health. - Noted, not fixed (
8e68197). A review of the appearance and unlock path, checked against the running registry rather than by reading, found that an outfit of entirely legal parts — bubbling skin, wide eyes, fangs, wick hat, tail-flame, snout, boots — yields zero colour rows, and the colour section silently disappears. The #27 seed yields two, so first-run is fine; this bites players who customise into multi-material parts. It is the visible cost of #17's correct conservatism, and the real fix is per-meshcolour_regionmetadata out of Blender.