tao-shen Claude Opus 4.6 commited on
Commit
8cab3f9
Β·
1 Parent(s): a5f444a

fix: allow write_file during APP_STARTING so agents can fix stuck startups

Browse files

APP_STARTING was incorrectly grouped with BUILDING/RESTARTING in
write-blocking guards. During BUILDING, writes reset the build. But
during APP_STARTING, writes trigger a NEW build β€” which is exactly
what agents need to fix a stuck startup (e.g. wrong entrypoint,
blocking restore script, missing deps).

This caused agents to diagnose the problem correctly but be unable
to apply fixes, wasting entire grace periods on read-only diagnostics.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Files changed (1) hide show
  1. scripts/conversation-loop.py +10 -8
scripts/conversation-loop.py CHANGED
@@ -544,8 +544,9 @@ def parse_and_execute_actions(raw_text, depth=0):
544
  "Writing the same file twice wastes a rebuild cycle.")
545
  results.append({"action": key, "result": result})
546
  print(f"[BLOCKED] {key} β€” duplicate write this cycle")
547
- # Guard: block write_file during BUILDING/APP_STARTING/RESTARTING
548
- elif target == "space" and child_state["stage"] in ("BUILDING", "RESTARTING", "APP_STARTING"):
 
549
  result = (f"β›” BLOCKED: Cain is currently {child_state['stage']}. "
550
  "Writing to Space during build RESETS the entire build from scratch. "
551
  "Wait for it to finish, then try again.")
@@ -598,10 +599,11 @@ def parse_and_execute_actions(raw_text, depth=0):
598
  if len(results) >= MAX_ACTIONS_PER_TURN:
599
  break
600
 
601
- # Block restart/write when Cain is building/starting β€” just wait
602
- if child_state["stage"] in ("BUILDING", "RESTARTING", "APP_STARTING") and name in ("restart", "write_file", "set_env", "set_secret"):
 
603
  result = (f"β›” BLOCKED: Cain is currently {child_state['stage']}. "
604
- "Do NOT restart or make changes β€” wait for it to finish starting. "
605
  "Every write_file during build RESETS the entire build from scratch. "
606
  "Use [ACTION: check_health] to monitor progress.")
607
  results.append({"action": action_str, "result": result})
@@ -692,10 +694,10 @@ def parse_and_execute_actions(raw_text, depth=0):
692
  break
693
 
694
  # Apply same blocking rules
695
- if child_state["stage"] in ("BUILDING", "RESTARTING", "APP_STARTING") and name in ("restart", "write_file", "set_env", "set_secret"):
696
- result = (f"β›” BLOCKED: Cain is currently {child_state['stage']}. Wait for it to finish starting. Writing during build RESETS it.")
697
  results.append({"action": action_str, "result": result})
698
- print(f"[BLOCKED-emoji] {name} β€” Cain is {child_state['stage']}")
699
  break
700
 
701
  # Rebuild cooldown (emoji parser)
 
544
  "Writing the same file twice wastes a rebuild cycle.")
545
  results.append({"action": key, "result": result})
546
  print(f"[BLOCKED] {key} β€” duplicate write this cycle")
547
+ # Guard: block write_file during BUILDING/RESTARTING (would reset build)
548
+ # APP_STARTING is allowed β€” writing triggers a new build which may fix the stuck state
549
+ elif target == "space" and child_state["stage"] in ("BUILDING", "RESTARTING"):
550
  result = (f"β›” BLOCKED: Cain is currently {child_state['stage']}. "
551
  "Writing to Space during build RESETS the entire build from scratch. "
552
  "Wait for it to finish, then try again.")
 
599
  if len(results) >= MAX_ACTIONS_PER_TURN:
600
  break
601
 
602
+ # Block restart/write when Cain is building/restarting β€” would reset build
603
+ # APP_STARTING is allowed so agents can fix stuck startups
604
+ if child_state["stage"] in ("BUILDING", "RESTARTING") and name in ("restart", "write_file", "set_env", "set_secret"):
605
  result = (f"β›” BLOCKED: Cain is currently {child_state['stage']}. "
606
+ "Do NOT restart or make changes β€” wait for it to finish. "
607
  "Every write_file during build RESETS the entire build from scratch. "
608
  "Use [ACTION: check_health] to monitor progress.")
609
  results.append({"action": action_str, "result": result})
 
694
  break
695
 
696
  # Apply same blocking rules
697
+ if child_state["stage"] in ("BUILDING", "RESTARTING") and name in ("restart", "write_file", "set_env", "set_secret"):
698
+ result = (f"β›” BLOCKED: Cain is currently {child_state['stage']}. Wait for it to finish. Writing during build RESETS it.")
699
  results.append({"action": action_str, "result": result})
700
+ print(f"[BLOCKED] sub-agent {name} β€” Cain is {child_state['stage']}")
701
  break
702
 
703
  # Rebuild cooldown (emoji parser)