From 2b617ba19f3da0af6da0b23c7c824195362427e2 Mon Sep 17 00:00:00 2001 From: autonomic-bot Date: Tue, 2 Jun 2026 00:17:34 +0000 Subject: [PATCH] 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 --- cc-ci-plan/launch.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cc-ci-plan/launch.py b/cc-ci-plan/launch.py index 7070abb..91a07ae 100644 --- a/cc-ci-plan/launch.py +++ b/cc-ci-plan/launch.py @@ -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 ''} (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())}.")