township: loading a template persists, not just applies

Loading applied the template to the live session but never wrote the active config file,
which made "switch live" only half true:

- the launcher starts the tool with --config <out_dir>/township_config.json, so the
  template silently reverted on the next restart;
- _ref_gen_res_steps deliberately RE-READS that file from disk for keyframe_size and
  keyframe_steps (so Run-page edits apply without a restart), which meant those two
  options came from the stale file even in the same session — the loaded template
  disagreeing with itself.

The load now writes the active config too, reports the path back as `persisted`, and says
so in the log if the write fails rather than leaving a switch that looks applied and
reverts later.

Verified live: save a template with keyframe_size 1024x576, load it, and the active
config file on disk carries it.
Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
parent c1a65e1d
......@@ -192,6 +192,23 @@ def test_the_web_routes_exist(route):
assert route in SRC
def test_loading_persists_to_the_active_config():
"""Live is not enough. The launcher starts the tool with
--config <out_dir>/township_config.json, so a load that only changed the session
would silently revert on the next restart — and _ref_gen_res_steps RE-READS that
file for keyframe_size/keyframe_steps, so a stale file makes those two options
disagree with the rest of the loaded template in the same session."""
seg = SRC[SRC.index('if path in ("/templates/load"'):SRC.index('if path == "/process":')]
assert "township_config.json" in seg
assert 'open(_ap, "w"' in seg
assert '"persisted"' in seg
def test_a_failed_persist_is_reported_not_swallowed():
seg = SRC[SRC.index('if path in ("/templates/load"'):SRC.index('if path == "/process":')]
assert "could not write" in seg
def test_loading_applies_to_the_live_session():
"""The Run page renders from default_args, so a load that only wrote a file would
appear to do nothing until restart."""
......
......@@ -11042,9 +11042,34 @@ async function resetPrompts(ev){
# reload and every subsequent job uses it.
for _k, _val in tcfg.items():
setattr(default_args, _k, _val)
_web_log(f" ⚙ Loaded template '{nm}' ({len(tcfg)} options)")
# …and make it STICK, by writing the active config file too. Two reasons
# this is not optional:
# 1. the launcher starts the tool with --config <out_dir>/
# township_config.json, so without this the template silently
# reverts on the next restart;
# 2. _ref_gen_res_steps deliberately RE-READS that file from disk for
# keyframe_size/keyframe_steps, so leaving it stale would have those
# two options disagree with the rest of the loaded template in the
# very same session.
_active = (getattr(default_args, "config", None)
or str(Path(default_args.out_dir) / "township_config.json"))
_persisted = None
try:
_ap = Path(_active)
_ap.parent.mkdir(parents=True, exist_ok=True)
with open(_ap, "w", encoding="utf-8") as f:
_j.dump(tcfg, f, indent=2, sort_keys=True)
f.write("\n")
_persisted = str(_ap)
except Exception as e:
# The switch is already live; failing to persist is worth saying
# out loud rather than silently reverting on the next restart.
_web_log(f" ⚠ Loaded '{nm}' live, but could not write {_active}: {e}")
_web_log(f" ⚙ Loaded template '{nm}' ({len(tcfg)} options)"
+ (f" → {_persisted}" if _persisted else ""))
self._send(200, "application/json",
_j.dumps({"ok": True, "name": nm, "options": len(tcfg)}))
_j.dumps({"ok": True, "name": nm, "options": len(tcfg),
"persisted": _persisted}))
return
if path == "/process":
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment