HDR alpha remap — implementation plan
HDR Alpha Remap Implementation Plan
Section titled “HDR Alpha Remap Implementation Plan”For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Stop the HDR canvas’s linear-light alpha blending from lifting faint translucent layers ~10-20x (the “washed out” HDR look) by remapping alpha a -> a^γ on the HDR canvas only.
Architecture: A new per-profile static ALPHA_GAMMA (SDR 1.0 = identity, HDR 2.2) is pushed as the global shader uniform hdr_alpha_gamma by the existing ShaderGlobals.push, which already follows the same decision as the root use_hdr_2d hold. A shared include hdr_alpha.gdshaderinc applies it as the last write of COLOR.a. fx/additive_mat.tres (~50 users) becomes a saved ShaderMaterial carrying the include; the shaders behind the measured worst layers get it directly. No runtime material swapping.
Tech Stack: Godot 4.7 typed GDScript, canvas_item shaders, GUT, Node node --test (console tools).
Spec: docs/superpowers/specs/2026-10-10-hdr-alpha-remap-design.md
Global Constraints
Section titled “Global Constraints”- Work in worktree
.claude/worktrees/hdr-colour-space, branchhdr-colour-space. Implementer subagents get their OWN worktree off this branch’s tip, never the main checkout. - SDR look must be byte-identical:
ColorProfileSdr.ALPHA_GAMMA = 1.0,pow(a, 1.0) == a. ColorProfileHdr.ALPHA_GAMMAseed2.2. Registry rangemin 1.0, max 3.0on both profiles.- Global name
hdr_alpha_gamma, typefloat, declared in[shader_globals]of BOTHproject.godotandplatform/tvos/project.godotat1.0,;comments only (a#line swallows the next key). - Saved materials only: never
ShaderMaterial.new()/CanvasItemMaterial.new()at runtime in shipped dirs (godot#124088;tests/test_baked_shader_materials.gd). - Out of scope: default-material
draw_*/ StyleBoxFlat (HUD bars), HeroLights, GPUParticles process materials,arena_galaxy.gdshader(writes alpha 1.0, remap is a no-op). - Gate:
scripts/gate.sh(orscripts/check-test-count.sh; never pull a whole GUT run into context). After merges addingclass_names rungodot --headless --path . --importfirst, thengit checkout -- project.godot audio/bus_layout.tres(keep YOUR intendedproject.godotedits: re-apply or commit them before the checkout). - The headless gate never compiles shaders: every shader edit gets a windowed compile check under
--rendering-method mobileAND--rendering-method gl_compatibility. - Commit with
git commit --file=<msgfile>, message ending with the session attribution lines.
Task 1: ALPHA_GAMMA profile value, hdr_alpha_gamma global, shared include
Section titled “Task 1: ALPHA_GAMMA profile value, hdr_alpha_gamma global, shared include”Files:
- Modify:
render/color_profile_sdr.gd(next toBORDER_HALO, line ~48) - Modify:
render/color_profile_hdr.gd(next toBORDER_HALO, line ~35) - Modify:
render/shader_globals.gd:18-19(GLOBALS) - Modify:
project.godotandplatform/tvos/project.godot([shader_globals], aftercs_linearize) - Modify:
net/tunables_registry.gd(after each profile’sBORDER_HALOrow, lines ~1023 and ~1070) - Modify:
tools/tunable_docs/docs.d/color_profiles.json(after eachBORDER_HALOentry), then regeneratecontrol/src/tunable_docs.jswith the repo’s generator (find it:git grep -l "docs.d" -- tools scripts; a hand edit of the generated file fails the gate) - Create:
render/shaders/hdr_alpha.gdshaderinc - Test:
tests/test_color_profiles.gd
Interfaces:
-
Produces:
ColorProfileSdr.ALPHA_GAMMA: float = 1.0,ColorProfileHdr.ALPHA_GAMMA: float = 2.2, global uniformhdr_alpha_gamma, includeres://render/shaders/hdr_alpha.gdshaderincexposingfloat hdr_alpha(float a). -
Step 1: Write the failing tests (edit
tests/test_color_profiles.gd)
Add "ALPHA_GAMMA": 1.0, to SDR_BUNDLED (after "BORDER_HALO": 2.2,) and "ALPHA_GAMMA": 2.2, to HDR_SEEDS. In test_push_sends_the_profiles_values, extend the SDR expected list to:
assert_eq(_pushed, [[&"border_halo", 2.2], [&"wfx_hot", 1.0], [&"wfx_accent", 1.0], [&"boss_hot", 1.0], [&"dissolve_edge", 1.0], [&"glass_cap", 10000.0], [&"hdr_alpha_gamma", 1.0]], "SDR: today's look, byte for byte")and after the HDR push assertions add assert_has(_pushed, [&"hdr_alpha_gamma", 2.2], "HDR: the alpha remap"). Append:
# HDR alpha remap (spec 2026-10-10): the HDR canvas blends alpha in linear light, so hdr_alpha()# raises alpha to hdr_alpha_gamma there; SDR pushes 1.0 (identity).func test_hdr_alpha_include_reads_the_global() -> void: var src := FileAccess.get_file_as_string("res://render/shaders/hdr_alpha.gdshaderinc") assert_true(src.contains("global uniform float hdr_alpha_gamma;")) assert_true(src.contains("float hdr_alpha(float a)")) assert_true(src.contains("pow(a, hdr_alpha_gamma)"))- Step 2: Run, verify FAIL
Run: GUT_LOG=$TMPDIR/bh-alpha-t1.log scripts/check-test-count.sh (or the single script via the GUT -gselect=test_color_profiles.gd invocation in docs/reference/running-and-testing.md).
Expected: FAIL in test_sdr_bundled_values_are_todays_look (count), test_hdr_seeds, test_push_sends_the_profiles_values, test_hdr_alpha_include_reads_the_global.
- Step 3: Implement
render/color_profile_sdr.gd, after BORDER_HALO:
# HDR alpha remap (spec 2026-10-10; shader global hdr_alpha_gamma): alpha exponent applied by# hdr_alpha() on the HDR canvas. 1.0 here = identity, the 8-bit canvas already blends in gamma space.static var ALPHA_GAMMA: float = 1.0render/color_profile_hdr.gd, after BORDER_HALO:
# The HDR canvas blends alpha in LINEAR light, so a faint fill authored for SDR is ~10x brighter.# a^γ matches SDR over black (γ ≈ the sRGB curve). 1.0 = no remap (the live A/B "off").static var ALPHA_GAMMA: float = 2.2render/shader_globals.gd:
const GLOBALS := {&"border_halo": "BORDER_HALO", &"wfx_hot": "WFX_HOT", &"wfx_accent": "WFX_ACCENT", &"boss_hot": "BOSS_HOT", &"dissolve_edge": "DISSOLVE_EDGE", &"glass_cap": "GLASS_BACKDROP_CAP", &"hdr_alpha_gamma": "ALPHA_GAMMA"}Both project files, after the cs_linearize={...} block:
; HDR alpha remap (render/shaders/hdr_alpha.gdshaderinc): SDR value 1.0 = identity.hdr_alpha_gamma={"type": "float","value": 1.0}net/tunables_registry.gd:
{"key": "ColorProfileSdr.ALPHA_GAMMA", "script": COLOR_SDR, "name": "ALPHA_GAMMA", "min": 1.0, "max": 3.0}, {"key": "ColorProfileHdr.ALPHA_GAMMA", "script": COLOR_HDR, "name": "ALPHA_GAMMA", "min": 1.0, "max": 3.0},docs.d/color_profiles.json:
"ColorProfileSdr.ALPHA_GAMMA": { "label": "SDR alpha remap exponent", "desc": "SDR look (no HDR output): Exponent applied to translucent alpha (shader global hdr_alpha_gamma). 1 = no remap, the right value on the gamma-space SDR canvas.", "src": "code", "group": "Glow & colour grade" }, "ColorProfileHdr.ALPHA_GAMMA": { "label": "HDR alpha remap exponent", "desc": "HDR look (HDR output on): The HDR canvas blends in linear light, so faint fills look about 10x brighter than on SDR. Alpha is raised to this power to match. 2.2 = matches SDR over black, 1 = off (the washed-out look).", "src": "code", "group": "Glow & colour grade" },render/shaders/hdr_alpha.gdshaderinc:
// HDR alpha remap (spec docs/superpowers/specs/2026-10-10-hdr-alpha-remap-design.md). The 8-bit SDR// canvas blends alpha on sRGB-encoded values; the HDR (use_hdr_2d) canvas blends in linear light, so a// faint fill is ~10x brighter there. hdr_alpha_gamma is the active colour profile's ALPHA_GAMMA// (ShaderGlobals.push): 1.0 on SDR (identity), ~2.2 on HDR. DECLARED in [shader_globals] of both project// files (the export baker fails on runtime-only globals). Call it as the LAST write of COLOR.a in fragment().#ifndef HDR_ALPHA_INC#define HDR_ALPHA_INCglobal uniform float hdr_alpha_gamma;
float hdr_alpha(float a) { return a <= 0.0 ? 0.0 : pow(a, hdr_alpha_gamma);}#endif- Step 4: Run, verify PASS; also run
node --testintools/tunable_docsif it has tests, and the docs.d gate test (it runs inscripts/gate.sh). - Step 5: Commit —
feat(hdr): ALPHA_GAMMA profile value + hdr_alpha_gamma global + hdr_alpha include
Task 2: fx/additive_mat.tres becomes a saved ShaderMaterial with the remap; CS_ADD / CS_MIX get it
Section titled “Task 2: fx/additive_mat.tres becomes a saved ShaderMaterial with the remap; CS_ADD / CS_MIX get it”Files:
- Create:
render/shaders/additive.gdshader - Modify:
fx/additive_mat.tres(same path, new type) - Modify:
render/shaders/cs_add.gdshader,render/shaders/cs_mix.gdshader(the shaders behindcs_add_mat.tres/cs_mix_mat.tres; confirm names withgrep shader render/shaders/cs_*_mat.tres) - Modify: the 50 typed preload sites (recipe below)
- Modify:
tests/test_fx_manager.gd:334-339 - Create:
tests/test_hdr_alpha.gd
Interfaces:
-
Consumes:
res://render/shaders/hdr_alpha.gdshaderinc,hdr_alpha(float)(Task 1). -
Produces:
preload("res://fx/additive_mat.tres")is aShaderMaterial; typed holders areMaterial.ColorSpace.ADDITIVE,FxManager.ADDITIVE_MAT,PrewarmPass.ADDITIVE_MATare typedMaterial. -
Step 1: Write the failing test
tests/test_hdr_alpha.gd
extends GutTest
# HDR alpha remap (spec docs/superpowers/specs/2026-10-10-hdr-alpha-remap-design.md): every material# behind the measured worst HDR-lift layers applies hdr_alpha() as the last write of COLOR.a.
const INCLUDE := "#include \"res://render/shaders/hdr_alpha.gdshaderinc\""const SHADERS := [ "res://render/shaders/additive.gdshader", "res://render/shaders/cs_add.gdshader", "res://render/shaders/cs_mix.gdshader",]
func _fragment_body(src: String) -> String: var i := src.find("void fragment()") return src.substr(i) if i >= 0 else ""
func test_targets_include_and_apply_the_remap_last() -> void: for p: String in SHADERS: var src := FileAccess.get_file_as_string(p) assert_true(src.contains(INCLUDE), "%s includes hdr_alpha" % p) var frag := _fragment_body(src) assert_ne(frag, "", "%s has a fragment()" % p) var at := frag.rfind("COLOR.a = hdr_alpha(COLOR.a);") assert_gt(at, -1, "%s remaps alpha" % p) var tail := frag.substr(at + 1) assert_false(tail.contains("COLOR.a") or tail.contains("COLOR ="), "%s: nothing writes alpha after the remap" % p)
func test_additive_mat_is_a_saved_additive_shader_material() -> void: var m: Material = preload("res://fx/additive_mat.tres") assert_true(m is ShaderMaterial, "additive_mat carries the remap shader") var sh := (m as ShaderMaterial).shader assert_eq(sh.resource_path, "res://render/shaders/additive.gdshader") assert_true(sh.code.contains("blend_add"), "still additive") assert_ne(m.resource_path, "", "saved, so the export baker compiles it")
func test_no_canvas_item_typed_additive_holders_left() -> void: for dir: String in ["res://fx", "res://render", "res://ui", "res://tools"]: _scan(dir) var main_src := FileAccess.get_file_as_string("res://main.gd") assert_false(main_src.contains("CanvasItemMaterial = preload(\"res://fx/additive_mat.tres\")"), "main.gd")
func _scan(dir: String) -> void: for f in DirAccess.get_files_at(dir): if f.ends_with(".gd"): var p := dir.path_join(f) assert_false(FileAccess.get_file_as_string(p).contains("CanvasItemMaterial = preload(\"res://fx/additive_mat.tres\")"), p) for d in DirAccess.get_directories_at(dir): _scan(dir.path_join(d))-
Step 2: Run, verify FAIL (additive.gdshader missing, additive_mat still CanvasItemMaterial, 50 typed sites).
-
Step 3: Implement
render/shaders/additive.gdshader:
shader_type canvas_item;render_mode blend_add;// The shared additive material (fx/additive_mat.tres, ~50 users). Was a CanvasItemMaterial// (blend_mode ADD); a saved ShaderMaterial now so it can carry the HDR alpha remap// (render/shaders/hdr_alpha.gdshaderinc). Identical on SDR (hdr_alpha_gamma 1.0).#include "res://render/shaders/hdr_alpha.gdshaderinc"
void fragment() { COLOR.a = hdr_alpha(COLOR.a);}fx/additive_mat.tres (write via the Godot editor/headless save or by hand; keep uid lines if the old file had one; it does not):
[gd_resource type="ShaderMaterial" load_steps=2 format=3]
[ext_resource type="Shader" path="res://render/shaders/additive.gdshader" id="1"]
[resource]shader = ExtResource("1")Then run godot --headless --path . --import so additive.gdshader.uid is generated; commit the .uid.
CS_ADD / CS_MIX shaders: add the include under the existing color_space include and a fragment:
#include "res://render/shaders/hdr_alpha.gdshaderinc"...void fragment() { COLOR.a = hdr_alpha(COLOR.a);}Retype recipe (deterministic; 50 sites verified by git grep -c):
git grep -l 'CanvasItemMaterial = preload("res://fx/additive_mat.tres")' -- '*.gd' \ | xargs sed -i '' 's/: CanvasItemMaterial = preload("res:\/\/fx\/additive_mat.tres")/: Material = preload("res:\/\/fx\/additive_mat.tres")/'git grep -n 'CanvasItemMaterial = preload("res://fx/additive_mat.tres")' -- '*.gd' # expect no outputThen fix any remaining use that needs the narrower type: git grep -n -E 'ADDITIVE(_MAT)?\)?\.(blend_mode|light_mode|particles)' (verified none in fx/render/ui/main.gd on 2026-10-10). Comments that say “CanvasItemMaterial” about the shared material (render/color_space.gd:92, fx/fx_manager.gd:11) get updated to “the shared additive material”.
tests/test_fx_manager.gd test_pooled_fx_share_one_additive_material, replace the two type asserts with:
assert_true(shared is ShaderMaterial, "the shared additive material (carries the HDR alpha remap)") assert_true((shared as ShaderMaterial).shader.code.contains("blend_add"), "same additive look")- Step 4: Run
godot --headless --path . --import,git checkout -- audio/bus_layout.tres(andproject.godotonly if the import changed anything beyond Task 1’s committed block:git diff project.godot), then the gate. Expected: PASS, test count +3. - Step 5: Windowed shader compile check under both renderers (boot the game ~10 s into a run; any shader error prints
SHADER ERROR):
for r in mobile gl_compatibility; do perl -e 'alarm 40; exec @ARGV' godot --path . --rendering-method $r 2>&1 | grep -i -E 'shader error|error:' | head; donegit checkout -- project.godot audio/bus_layout.tres platform/tvos/project.godotExpected: no shader errors.
- Step 6: Commit —
feat(hdr): shared additive material carries the HDR alpha remap
Task 3: Remap in the shaders behind the measured layers
Section titled “Task 3: Remap in the shaders behind the measured layers”Files (verified 2026-10-10: each has one fragment(); last alpha write shown):
| Shader | Last alpha write today |
|---|---|
render/shaders/arena_grid_breathe.gdshader |
COLOR.a *= (1.0 - breathe_depth) + ... (l.11) |
render/shaders/arena_aurora.gdshader |
COLOR.a *= v_alpha; (l.25) |
render/star_field.gdshader |
COLOR.a *= v_alpha; (l.21) |
render/web_field.gdshader |
COLOR = vec4(web_col, ...); (l.45) |
render/web_field_lite.gdshader |
read it: the final COLOR write |
render/web_look_a.gdshader, web_look_b.gdshader, web_look_c.gdshader |
read each: the final COLOR write |
render/shaders/enemy_smear.gdshader |
COLOR.a *= tail; (l.17) |
- Modify:
tests/test_hdr_alpha.gd(SHADERS)
Recipe per shader: add #include "res://render/shaders/hdr_alpha.gdshaderinc" after render_mode (or after shader_type when there is none), and append COLOR.a = hdr_alpha(COLOR.a); as the LAST statement of fragment(), after every existing COLOR/COLOR.a write and outside any early return/discard branch that would skip it (if a fragment returns early, restructure so the remap runs on every path that writes a visible alpha).
- Step 1: Failing test — append the nine paths above to
SHADERSintests/test_hdr_alpha.gd. Run: FAIL (nine “includes hdr_alpha”). - Step 2: Implement the recipe in all nine.
- Step 3: Gate PASS, then the windowed compile check from Task 2 Step 5 under both renderers (web looks: switch through them with the existing web-look console command or
tests/test_web_look_switch.gd’s mechanism, so a/b/c compile too). - Step 4: Commit —
feat(hdr): alpha remap in the arena, web, star and smear shaders
Task 4: Measure, A/B tool preset, docs
Section titled “Task 4: Measure, A/B tool preset, docs”Files:
- Modify:
tools/console_mcp/lib/hdr_ab.mjs,tools/console_mcp/hdr_ab.mjs,tools/console_mcp/test/hdr_ab.test.mjs - Modify:
docs/architecture/rendering-and-performance.md(§ “The HDR canvas blends alpha in LINEAR light”)
Interfaces:
-
Produces:
phaseCommand(toggle, on, { gamma })inlib/hdr_ab.mjsreturning the console command for one phase. -
Step 1: Failing node test in
test/hdr_ab.test.mjs:
import { phaseCommand } from '../lib/hdr_ab.mjs';test('alpha toggle sets the HDR alpha exponent instead of a graphics effect', () => { assert.deepEqual(phaseCommand('alpha', true, { gamma: 2.4 }), { kind: 'set_tunables', tunables: { 'ColorProfileHdr.ALPHA_GAMMA': 2.4 } }); assert.deepEqual(phaseCommand('alpha', false, { gamma: 2.4 }), { kind: 'set_tunables', tunables: { 'ColorProfileHdr.ALPHA_GAMMA': 1.0 } }); assert.deepEqual(phaseCommand('hdr_output', true), { kind: 'graphics', effect: 'hdr_output', on: true });});(match the file’s existing import test from 'node:test' / assert style). Run cd tools/console_mcp && npm test: FAIL.
- Step 2: Implement in
lib/hdr_ab.mjs:
// One phase's console command. 'alpha' A/Bs the HDR alpha remap (ColorProfileHdr.ALPHA_GAMMA:// 1.0 = off, the washed-out look) through set_tunables; everything else is a graphics effect.export function phaseCommand(toggle, on, { gamma = 2.2 } = {}) { if (toggle === 'alpha') return { kind: 'set_tunables', tunables: { 'ColorProfileHdr.ALPHA_GAMMA': on ? gamma : 1.0 } }; return { kind: 'graphics', effect: toggle, on };}In hdr_ab.mjs: const gamma = Number(opt('gamma', 2.2));; the phase loop and restore() send phaseCommand(toggle, ph.on, { gamma }) / phaseCommand(toggle, true, { gamma }) (alpha restore = the remap ON at gamma; it is live-only, a relaunch resets to the code seed); for toggle === 'alpha' skip the flagOf status confirmation and print (alpha: trust the on-device "Console: ..." note); preflight skips the gfx: flag check for alpha but keeps the run/pause checks and adds if (toggle === 'alpha' && !status.hdr?.enabled) p.push('HDR output is not engaged: the alpha remap only acts on the HDR canvas'). Default grade for alpha = 'seed' (no grade change). Update the usage comment. Run npm test: PASS.
- Step 3: Measure (controller may run this; Mac windowed):
O=<scratch>/ablate-after; mkdir -p $OCS_OUT=$O CS_PROFILE=ablate perl -e 'alarm 600; exec @ARGV' godot --path . --rendering-method mobile res://tools/cs_capture/cs_capture.tscn > $O/log.txt 2>&1git checkout -- project.godot audio/bus_layout.tres platform/tvos/project.godotgrep -E 'BASE|arena_background|zone_renderer|archetype_renderer|enemy_aura_look|hud.gd' $O/log.txtBaseline (before, 2026-10-10): HDR BASE p75 0.01984 vs SDR 0.00091; p75 HDR/SDR arena_background 0.01810/0.00091, zone_renderer 0.01572/0.00091, archetype_renderer 0.00347/0.00025, enemy_aura_look 0.00056/0.00014, hud 0.00340/0.00025. Acceptance: each of the four targeted layers’ HDR p75 ≤ 1.5x its SDR p75. If one misses, ablate within it (which child/shader still lifts) and report before adding scope; do NOT tune γ above 3.0 to force it.
- Step 4: Docs — replace the last sentence of the rendering doc § (“the fix direction is … (plan pending)”) with the shipped mechanism:
ALPHA_GAMMAper profile →hdr_alpha_gamma→hdr_alpha.gdshaderincas the lastCOLOR.awrite;additive_mat.tresis a ShaderMaterial; the covered shader list; the before/after ablate numbers; out-of-scope paths (HUD StyleBoxes, plaindraw_*on the default material, HeroLights) and the rule: a new translucent shader on the canvas includeshdr_alphaand applies it last (pinned bytests/test_hdr_alpha.gd’s list). - Step 5: Gate PASS; commit —
feat(hdr): alpha A/B preset in hdr_ab, ablate after-numbers, rendering doc
Task 5 (controller + Chris, not a subagent): device verification
Section titled “Task 5 (controller + Chris, not a subagent): device verification”- Review:
bh-revieweron the branch diff vs the pre-plan tip50c0b4c3(MERGE / DO NOT MERGE). - Bump + Dev install on the ATV from the worktree (
bh-worktree-device-install);ListAgentsfirst (the ATV is shared). - A/B with Chris in a real run:
node tools/console_mcp/hdr_ab.mjs atv --toggle alpha --gamma 2.2 --hold 20(OFF = 1.0 vs ON = 2.2). If Chris wants it stronger or softer, repeat with--gamma 1.8/2.4. Record his verdict and γ. - Perf ABBA on the ATV with the remap ON vs OFF (skill
bh-console-live-ab): flag > 0.5 ms render or ≥ 2 fps. - Fresh-install stall check (
bh-fresh-install-stall-check): a shared material changed type. - Persist the chosen γ as the
ColorProfileHdr.ALPHA_GAMMAseed (updateHDR_SEEDSintests/test_color_profiles.gdand the docs.d desc in the same commit); remote-config patch only with Chris’s OK. - Re-measure the HUD: if it is still the top lift, propose the follow-up (StyleBox/draw path) to Chris; do not build it in this plan.
Execution handoff
Section titled “Execution handoff”- Decisions (Chris, 2026-10-10): coverage = “Measured worst first” (not everything, not shaders-only); approach A (global + shared include, additive_mat becomes a ShaderMaterial, no runtime swaps) — rejected B (runtime material swap: 53-user registry, the swap pattern caused two step-2 bugs) and post-blend correction (impossible). After presenting the spec, Chris said “Go ahead” (= approved spec + plan writing). The A/B is the
ColorProfileHdr.ALPHA_GAMMAtunable 1.0↔2.2 via console, NOT a new Debug Settings row (stated to Chris; he did not object). - Accepted edge: the console
color_profile hdrdev command can force the HDR profile on an SDR canvas; γ 2.2 then darkens faint layers there. Dev-only path, accepted; do not special-case it. - Authorized: code on
hdr-colour-space, pushes of that branch. Needs Chris’s same-day OK: device installs/bumps (checkListAgentsfirst; ATV shared), any remote-config patch, merge to main. - Done outside the plan: spec committed 50c0b4c3. Baseline ablate numbers are in Task 4 Step 3 (Mac, 2026-10-10, headroom 4.93).
- Gotchas hit while planning:
cs_capturerewritesproject.godot,audio/bus_layout.tres,platform/tvos/project.godot;git checkout --them after every run (but keep Task 1’s intended[shader_globals]edits — commit them first). In a zsh one-liner,cdinto the worktree can reset back to the main checkout; use absolute paths. - Open for Chris after Task 5: γ verdict; whether the HUD (StyleBox, 14x) gets a follow-up; then the queued P3 wide-gamut work, the fresh-install stall check and the merge of hdr-colour-space (memory
bullet-heaven-hdr-output). - Next action: execute Task 1 subagent-driven (bh-implementer, model opus, own worktree off
hdr-colour-spacetip), perbh-sdd-concurrent+sdd-worktree-leak-guard.