v0.5.24
Fixed
-
_default.defaultswas a fallback, not a floor — so configuring a project silently disarmed its zombie hang-guard.resolve_project_defaultsdidprojects.get(name) or projects.get("_default"), an either/or: a project with an entry never saw_default.defaultsat all. That block is the fleet hang-guard —idle_timeout_sandmax_wall_s, the reaper written after a silent job held a desktop GPU for six days — andconfig/projects.yamldescribed it as "the FLEET-WIDE hang-guard: any unlisted project inherits them". It reached exactly the projects nobody had configured, and fell off the moment anyone gave a project a priority:job projects set NAME 70writes a bare{priority: 70}, and that alone was enough.On 2026-07-14, registering 32 real projects to set their priorities disarmed the hang-guard on all 32 — including
orchid-sdxl, the project whose 170-hour zombie created the guard. Nothing failed and no test went red; the guard was simply gone from everything that mattered, while the config file went on claiming it was fleet-wide._default.defaultsis now a floor: merged under every project, overridden one key at a time (settingidle_timeout_sno longer dropsmax_wall_s). The merge is derived fromdataclasses.fields, so a field added later is inherited without anyone remembering to add it.ProjectDefaults.escalate_to_arcchanges frombool = Falsetobool | None = None: every field now usesNoneas its unset sentinel, because a merge cannot otherwise tell "the project said nothing" from "the project said false" — and a project must be able to opt out of a floor. Guarded bytests/test_project_defaults_floor.py, mutation-verified against the old either/or. -
test_uv_lock_in_sync_with_pyprojectcould only ever pass in CI, and the committed lock was stale through seven releases.uv runsyncs before it runs: handed a staleuv.lockit rewrites the file, then starts pytest. So the guard shelled out touv lock --checkagainst a lockfile its own runner had just repaired.uv.locksat atjobd 0.5.16whilepyproject.tomlsaid0.5.23, with CI green the whole way; the staleness only surfaced running pytest directly. Fixed by settingUV_NO_SYNC: "1"once at the workflow level inci.yml— not on individualuv runlines, because the nextuv runsomeone adds would not have it — and re-locking. Verified both directions on a pristine checkout: with the rewrite a stale lock passes, withUV_NO_SYNCit fails as it always should have.