feat(launch): persist PHASES_SPEC to .phases-spec (status/watchdog/reboot agree)

Mirror the .loop-backend pattern: env wins, else the persisted file, else
the default build sequence. Without this, a custom single-phase run was
invisible to bare 'launch.py status' and would NOT survive a reboot (the
service has no PHASES_SPEC env). Now the current phase set is durable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
autonomic-bot
2026-06-02 00:17:34 +00:00
parent d349656c3b
commit 2b617ba19f

View File

@ -47,6 +47,7 @@ LOG_DIR = os.environ.get("LOG_DIR", "/srv/cc-ci/.cc-ci-logs")
# This ensures the watchdog (which runs in its own tmux session without the caller's env)
# uses the same backend/model when it restarts a dead session.
_BACKEND_FILE = os.path.join(LOG_DIR, ".loop-backend")
_PHASES_FILE = os.path.join(LOG_DIR, ".phases-spec")
_MODEL_FILE = os.path.join(LOG_DIR, ".loop-model")
def _read_file_default(path, default):
@ -88,7 +89,7 @@ ORCH_WAKE_PROMPT = os.environ.get("ORCH_WAKE_PROMPT", f"{PLAN_DIR}/ai-progress
STALL_IDLE = int(os.environ.get("STALL_IDLE", 300))
STALL_GRACE = int(os.environ.get("STALL_GRACE", 180))
PHASES_SPEC = os.environ.get("PHASES_SPEC", ";".join([
_DEFAULT_PHASES_SPEC = ";".join([
"1c|plan-phase1c-full-reproducibility.md|STATUS-1c.md",
"1b|plan-phase1b-review-lint.md|STATUS-1b.md",
"1d|plan-phase1d-generic-test-suite.md|STATUS-1d.md",
@ -100,7 +101,10 @@ PHASES_SPEC = os.environ.get("PHASES_SPEC", ";".join([
"3|plan-phase3-results-ux.md|STATUS-3.md",
"4|plan-phase4-final-review-polish-cleanup.md|STATUS-4.md",
"5|plan-phase5-verify-upgrade-flow.md|STATUS-5.md",
]))
])
# Env wins; else a persisted file written by `start` (so status/watchdog/reboot all agree on the
# current phase set); else the default build sequence above.
PHASES_SPEC = os.environ.get("PHASES_SPEC") or _read_file_default(_PHASES_FILE, _DEFAULT_PHASES_SPEC)
PHASES = [p.split("|") for p in PHASES_SPEC.split(";")]
PHASE_IDX_FILE = os.environ.get("PHASE_IDX_FILE", f"{LOG_DIR}/.phase-idx")
@ -677,7 +681,9 @@ def main():
# Persist backend/model so the watchdog uses them when restarting dead sessions.
Path(_BACKEND_FILE).write_text(BACKEND)
Path(_MODEL_FILE).write_text(LOOP_MODEL)
Path(_PHASES_FILE).write_text(PHASES_SPEC)
log(f"backend={BACKEND} model={LOOP_MODEL or '<default>'} (persisted to {_BACKEND_FILE})")
log(f"phases='{all_ids()}' (persisted to {_PHASES_FILE})")
start_loops()
start_watchdog()
log(f"started at phase {phase_id(cur_idx())}.")