Fix supervisor monitoring with unique naming tags
ci.yml / Fix supervisor monitoring with unique naming tags (push) Failing after 0s

Implement unique naming tags for all supervisors and workers to enable
proper monitoring and management by the product-builder agent. The previous
generic [CA-AUTO] prefix made it impossible to distinguish between different
supervisor types and count their workers accurately.

Changes:
- Pool supervisors now use specific tags (AUTO-IMP-SUP, AUTO-REV-SUP, etc.)
- Workers use corresponding tags (AUTO-IMP, AUTO-REV, etc.)
- Singleton supervisors use unique tags (AUTO-ARCH, AUTO-EPIC, etc.)
- Product-builder can now count supervisors/workers by tag pattern
- Added metadata mapping for reliable supervisor re-launching
- Updated system-watchdog to recognize new tag patterns

This enables the product-builder to detect zombie supervisors, verify
worker counts, and re-launch failed supervisors reliably.
This commit is contained in:
2026-04-05 23:00:43 +00:00
parent 5fbe4bd533
commit 51cd94dcd5
7 changed files with 239 additions and 55 deletions
+3 -3
View File
@@ -122,8 +122,8 @@ EXISTING_WORKERS = bash("curl -s ${SERVER}/session | python3 -c \"
import sys, json
for s in json.loads(sys.stdin.read()):
title = s.get('title','')
if title.startswith('[CA-AUTO] worker-hunt:'):
module = title.replace('[CA-AUTO] worker-hunt: ','')
if title.startswith('[AUTO-BUG] worker-hunt:'):
module = title.replace('[AUTO-BUG] worker-hunt: ','')
print(module + '=' + s['id'])
\"", timeout=30000)
@@ -161,7 +161,7 @@ LOOP:
for module in batch:
SESSION_ID = bash("curl -s -X POST ${SERVER}/session \
-H 'Content-Type: application/json' \
-d '{\"title\": \"[CA-AUTO] worker-hunt: <module>\"}' \
-d '{\"title\": \"[AUTO-BUG] worker-hunt: <module>\"}' \
| python3 -c \"import sys,json; print(json.loads(sys.stdin.read())['id'])\"",
timeout=30000)
bash("curl -s -X POST ${SERVER}/session/${SESSION_ID}/prompt_async \
@@ -256,7 +256,7 @@ LOOP FOREVER:
# Create session
SESSION_ID = bash("curl -s -X POST ${SERVER}/session \
-H 'Content-Type: application/json' \
-d '{\"title\": \"[CA-AUTO] worker-review: PR-${pr.number}\"}' \
-d '{\"title\": \"[AUTO-REV] worker-review: PR-${pr.number}\"}' \
| python3 -c \"import sys,json; print(json.loads(sys.stdin.read())['id'])\"",
timeout=30000)
+60 -13
View File
@@ -436,11 +436,28 @@ function audit_supervisor_health():
# ── Step 1: Get all supervisor sessions ──────────────────────
sessions = curl -s GET "${SERVER}/session" | parse JSON
statuses = curl -s GET "${SERVER}/session/status" | parse JSON
supervisor_sessions = [s for s in sessions
if s.title.startswith("[CA-AUTO] supervisor:")]
# Map of supervisor tags to identify them
supervisor_tags = [
"AUTO-IMP-SUP", "AUTO-REV-SUP", "AUTO-UAT-SUP", "AUTO-BUG-SUP", "AUTO-INF-SUP",
"AUTO-ARCH", "AUTO-EPIC", "AUTO-HUMAN", "AUTO-EVLV", "AUTO-GUARD",
"AUTO-SPEC", "AUTO-BLOG", "AUTO-DOCS", "AUTO-TIME", "AUTO-OWNR", "AUTO-WDOG"
]
supervisor_sessions = []
for s in sessions:
for tag in supervisor_tags:
if f"[{tag}]" in s.title:
supervisor_sessions.append(s)
break
for session in supervisor_sessions:
name = session.title.replace("[CA-AUTO] supervisor: ", "")
# Extract the display name from the title
import re
match = re.search(r'\[([A-Z-]+)\]\s+(.+)', session.title)
if match:
name = match.group(2) # The part after the tag
else:
name = session.title # Fallback
session_status = statuses.get(session.id)
# Skip sessions that are completed/errored (product-builder handles those)
@@ -549,8 +566,12 @@ function audit_supervisor_health():
"human-liaison", "agent-evolver", "arch-guard", "spec-updater",
"backlog-groomer", "docs-writer", "timeline-updater",
"project-owner", "system-watchdog"]
running_names = [s.title.replace("[CA-AUTO] supervisor: ", "")
for s in supervisor_sessions]
running_names = []
for s in supervisor_sessions:
# Extract display name from new tag format
match = re.search(r'\[([A-Z-]+)\]\s+(.+)', s.title)
if match:
running_names.append(match.group(2))
missing = [n for n in EXPECTED if n not in running_names]
if missing:
findings.append({
@@ -703,9 +724,15 @@ function audit_session_spot_check():
sessions = curl -s GET "${SERVER}/session" | parse JSON
# Find the 3 most recently active supervisor sessions
active_supervisors = [s for s in sessions
if s.title.startswith("[CA-AUTO]")
and statuses.get(s.id) not in ("completed", "error")]
supervisor_prefixes = ["[AUTO-IMP", "[AUTO-REV", "[AUTO-UAT", "[AUTO-BUG", "[AUTO-INF",
"[AUTO-ARCH]", "[AUTO-EPIC]", "[AUTO-HUMAN]", "[AUTO-EVLV]",
"[AUTO-GUARD]", "[AUTO-SPEC]", "[AUTO-BLOG]", "[AUTO-DOCS]",
"[AUTO-TIME]", "[AUTO-OWNR]", "[AUTO-WDOG]"]
active_supervisors = []
for s in sessions:
if any(s.title.startswith(prefix) for prefix in supervisor_prefixes):
if statuses.get(s.id) not in ("completed", "error"):
active_supervisors.append(s)
# Sort by most recent activity (updatedAt or similar)
recent_3 = active_supervisors[:3] # already sorted by update time
@@ -799,11 +826,26 @@ function audit_deep_session_introspection():
session_summaries = {} # name -> { what_doing, health, issues }
sessions = curl -s GET "${SERVER}/session" | parse JSON
supervisor_sessions = [s for s in sessions
if s.title.startswith("[CA-AUTO] supervisor:")]
# Find supervisor sessions by their unique tags
supervisor_tags = [
"AUTO-IMP-SUP", "AUTO-REV-SUP", "AUTO-UAT-SUP", "AUTO-BUG-SUP", "AUTO-INF-SUP",
"AUTO-ARCH", "AUTO-EPIC", "AUTO-HUMAN", "AUTO-EVLV", "AUTO-GUARD",
"AUTO-SPEC", "AUTO-BLOG", "AUTO-DOCS", "AUTO-TIME", "AUTO-OWNR", "AUTO-WDOG"
]
supervisor_sessions = []
for s in sessions:
for tag in supervisor_tags:
if f"[{tag}]" in s.title:
supervisor_sessions.append(s)
break
for session in supervisor_sessions:
name = session.title.replace("[CA-AUTO] supervisor: ", "")
# Extract display name from the title
match = re.search(r'\[([A-Z-]+)\]\s+(.+)', session.title)
if match:
name = match.group(2)
else:
name = session.title
# ── Read last 10 messages ────────────────────────────────
messages = curl -s GET "${SERVER}/session/${session.id}/message?limit=10"
@@ -994,7 +1036,12 @@ function audit_deep_session_introspection():
issue_modifications = {} # issue_number -> [session_names]
for session in supervisor_sessions:
name = session.title.replace("[CA-AUTO] supervisor: ", "")
# Extract display name from the title
match = re.search(r'\[([A-Z-]+)\]\s+(.+)', session.title)
if match:
name = match.group(2)
else:
name = session.title
messages = curl -s GET "${SERVER}/session/${session.id}/message?limit=5"
| parse JSON
@@ -1209,7 +1256,7 @@ function dispatch_one_off(agent_name, finding):
# Create a session and dispatch via prompt_async
SESSION_ID = curl -s -X POST "${SERVER}/session" \
-H "Content-Type: application/json" \
-d '{"title": "[CA-AUTO] one-off: <agent_name> — <finding.type>"}'
-d '{"title": "[AUTO-ONEOFF] <agent_name> — <finding.type>"}'
curl -s -X POST "${SERVER}/session/${SESSION_ID}/prompt_async" \
-H "Content-Type: application/json" \
+3 -3
View File
@@ -163,8 +163,8 @@ EXISTING_WORKERS = bash("curl -s ${SERVER}/session | python3 -c \"
import sys, json
for s in json.loads(sys.stdin.read()):
title = s.get('title','')
if title.startswith('[CA-AUTO] worker-testinfra:'):
area = title.replace('[CA-AUTO] worker-testinfra: ','')
if title.startswith('[AUTO-INF] worker-testinfra:'):
area = title.replace('[AUTO-INF] worker-testinfra: ','')
print(area + '=' + s['id'])
\"", timeout=30000)
@@ -195,7 +195,7 @@ LOOP:
for area in batch:
SESSION_ID = bash("curl -s -X POST ${SERVER}/session \
-H 'Content-Type: application/json' \
-d '{\"title\": \"[CA-AUTO] worker-testinfra: <area>\"}' \
-d '{\"title\": \"[AUTO-INF] worker-testinfra: <area>\"}' \
| python3 -c \"import sys,json; print(json.loads(sys.stdin.read())['id'])\"",
timeout=30000)
bash("curl -s -X POST ${SERVER}/session/${SESSION_ID}/prompt_async \
+3 -3
View File
@@ -125,8 +125,8 @@ EXISTING_WORKERS = bash("curl -s ${SERVER}/session | python3 -c \"
import sys, json
for s in json.loads(sys.stdin.read()):
title = s.get('title','')
if title.startswith('[CA-AUTO] worker-uat:'):
area = title.replace('[CA-AUTO] worker-uat: ','')
if title.startswith('[AUTO-UAT] worker-uat:'):
area = title.replace('[AUTO-UAT] worker-uat: ','')
print(area + '=' + s['id'])
\"", timeout=30000)
@@ -162,7 +162,7 @@ LOOP:
for area in batch:
SESSION_ID = bash("curl -s -X POST ${SERVER}/session \
-H 'Content-Type: application/json' \
-d '{\"title\": \"[CA-AUTO] worker-uat: <area>\"}' \
-d '{\"title\": \"[AUTO-UAT] worker-uat: <area>\"}' \
| python3 -c \"import sys,json; print(json.loads(sys.stdin.read())['id'])\"",
timeout=30000)
bash("curl -s -X POST ${SERVER}/session/${SESSION_ID}/prompt_async \
+8 -8
View File
@@ -479,10 +479,10 @@ def adopt_existing_workers():
continue
# Adopt issue implementation workers
if title.startswith('[CA-AUTO] worker-issue-impl: issue-'):
if title.startswith('[AUTO-IMP] worker-issue-impl: issue-'):
try:
# Extract issue number: "[CA-AUTO] worker-issue-impl: issue-123"
issue_num_str = title.replace('[CA-AUTO] worker-issue-impl: issue-', '').strip()
# Extract issue number: "[AUTO-IMP] worker-issue-impl: issue-123"
issue_num_str = title.replace('[AUTO-IMP] worker-issue-impl: issue-', '').strip()
issue_number = int(issue_num_str)
active_issue_workers[issue_number] = session_id
adopted_issue_workers += 1
@@ -491,10 +491,10 @@ def adopt_existing_workers():
print(f"[WARNING] Could not parse issue number from title: {title}")
# Adopt PR fix workers
elif title.startswith('[CA-AUTO] worker-pr-fix: PR-'):
elif title.startswith('[AUTO-IMP] worker-pr-fix: PR-'):
try:
# Extract PR number: "[CA-AUTO] worker-pr-fix: PR-456"
pr_num_str = title.replace('[CA-AUTO] worker-pr-fix: PR-', '').strip()
# Extract PR number: "[AUTO-IMP] worker-pr-fix: PR-456"
pr_num_str = title.replace('[AUTO-IMP] worker-pr-fix: PR-', '').strip()
pr_number = int(pr_num_str)
# We need to reconstruct the PR worker info - get PR data from Forgejo
@@ -645,7 +645,7 @@ Your task: Fix this PR based on work_type:
CRITICAL: You own this PR until it is merged. Monitor and handle all feedback.
Do not exit until the PR is merged or blocked by human feedback (needs feedback label)."""
title = f"[CA-AUTO] worker-pr-fix: PR-{pr.number}"
title = f"[AUTO-IMP] worker-pr-fix: PR-{pr.number}"
work_id = f"PR-{pr.number}"
else: # issue-impl mode
@@ -672,7 +672,7 @@ Your task: Implement this issue fully, create PR, and shepherd it through review
CRITICAL: You own this issue from implementation through PR merge.
Do not exit until the PR is merged. Monitor and handle all review feedback."""
title = f"[CA-AUTO] worker-issue-impl: issue-{issue['number']}"
title = f"[AUTO-IMP] worker-issue-impl: issue-{issue['number']}"
work_id = f"issue-{issue['number']}"
def verify_worker_started(session_id, retries=3):
+161 -24
View File
@@ -517,13 +517,35 @@ ALL_SESSIONS = bash("curl -s ${SERVER}/session", timeout=30000)
# Step 2: Find existing supervisor sessions
EXISTING = bash("echo '${ALL_SESSIONS}' | python3 -c \"
import sys, json
import re
sessions = json.loads(sys.stdin.read())
# Map tags to display names
tag_map = {
'AUTO-IMP-SUP': 'implementor-pool',
'AUTO-REV-SUP': 'reviewer-pool',
'AUTO-UAT-SUP': 'tester-pool',
'AUTO-BUG-SUP': 'hunter-pool',
'AUTO-INF-SUP': 'test-infra-pool',
'AUTO-ARCH': 'architect',
'AUTO-EPIC': 'epic-planner',
'AUTO-HUMAN': 'human-liaison',
'AUTO-EVLV': 'agent-evolver',
'AUTO-GUARD': 'arch-guard',
'AUTO-SPEC': 'spec-updater',
'AUTO-BLOG': 'backlog-groomer',
'AUTO-DOCS': 'docs-writer',
'AUTO-TIME': 'timeline-updater',
'AUTO-OWNR': 'project-owner',
'AUTO-WDOG': 'system-watchdog'
}
for s in sessions:
title = s.get('title', '')
if title.startswith('[CA-AUTO] supervisor:'):
# Extract the display name from title
name = title.replace('[CA-AUTO] supervisor: ', '')
print(name + '=' + s['id'])
# Check if title matches any supervisor tag pattern
match = re.match(r'\\[([A-Z-]+)\\]', title)
if match and match.group(1) in tag_map:
tag = match.group(1)
display_name = tag_map[tag]
print(display_name + '=' + s['id'])
\"", timeout=30000)
# Step 3: Check status of each existing session
@@ -586,7 +608,7 @@ Pre-flight: Launching 16 supervisors via prompt_async:
# ── Helper function: launch one supervisor ───────────────────────
# For EACH supervisor, SKIP if already running (adopted in Phase C.0).
function launch_supervisor(agent_name, display_name, prompt_text):
function launch_supervisor(agent_name, display_name, tag, prompt_text):
# Check if this supervisor was adopted from a previous run
if display_name in existing_supervisors:
# Already running — record its session ID and skip launch
@@ -596,7 +618,7 @@ function launch_supervisor(agent_name, display_name, prompt_text):
# Step 1: Create a session
SESSION_ID=$(curl -s -X POST "${SERVER}/session" \
-H "Content-Type: application/json" \
-d "{\"title\": \"[CA-AUTO] supervisor: ${display_name}\"}" \
-d "{\"title\": \"[${tag}] ${display_name}\"}" \
| python3 -c "import sys,json; print(json.loads(sys.stdin.read())['id'])")
# Step 2: Fire-and-forget launch via prompt_async
@@ -618,7 +640,7 @@ rm -f /tmp/ca-supervisor-sessions.env
# Launch each with its specific prompt containing all needed parameters:
# (Forgejo PAT, git identity, repo info, N, etc.)
launch_supervisor("issue-implementor", "implementor-pool",
launch_supervisor("issue-implementor", "implementor-pool", "AUTO-IMP-SUP",
"You are the implementation pool supervisor.
SESSION STATE ISSUE: #{SESSION_STATE_ISSUE_NUMBER}
Repo: <owner>/<repo>. Forgejo PAT: <PAT>.
@@ -628,7 +650,7 @@ launch_supervisor("issue-implementor", "implementor-pool",
When creating tracking issues, ALWAYS include these labels:
Type/Automation, State/In Progress, Priority/Medium")
launch_supervisor("ca-continuous-pr-reviewer", "reviewer-pool",
launch_supervisor("ca-continuous-pr-reviewer", "reviewer-pool", "AUTO-REV-SUP",
"You are the PR review pool supervisor.
SESSION STATE ISSUE: #{SESSION_STATE_ISSUE_NUMBER}
Repo: <owner>/<repo>. Instance ID: reviewer-pool-1.
@@ -637,7 +659,7 @@ launch_supervisor("ca-continuous-pr-reviewer", "reviewer-pool",
When creating tracking issues, ALWAYS include these labels:
Type/Automation, State/In Progress, Priority/Medium")
launch_supervisor("ca-uat-tester", "tester-pool",
launch_supervisor("ca-uat-tester", "tester-pool", "AUTO-UAT-SUP",
"You are the UAT testing pool supervisor.
SESSION STATE ISSUE: #{SESSION_STATE_ISSUE_NUMBER}
Repo: <owner>/<repo>. Instance ID: uat-pool-1.
@@ -646,7 +668,7 @@ launch_supervisor("ca-uat-tester", "tester-pool",
When creating tracking issues, ALWAYS include these labels:
Type/Automation, State/In Progress, Priority/Medium")
launch_supervisor("ca-bug-hunter", "hunter-pool",
launch_supervisor("ca-bug-hunter", "hunter-pool", "AUTO-BUG-SUP",
"You are the bug hunting pool supervisor.
SESSION STATE ISSUE: #{SESSION_STATE_ISSUE_NUMBER}
Repo: <owner>/<repo>. Instance ID: hunter-pool-1.
@@ -655,7 +677,7 @@ launch_supervisor("ca-bug-hunter", "hunter-pool",
When creating tracking issues, ALWAYS include these labels:
Type/Automation, State/In Progress, Priority/Medium")
launch_supervisor("ca-test-infra-improver", "test-infra-pool",
launch_supervisor("ca-test-infra-improver", "test-infra-pool", "AUTO-INF-SUP",
"You are the test infrastructure improvement pool supervisor.
SESSION STATE ISSUE: #{SESSION_STATE_ISSUE_NUMBER}
Repo: <owner>/<repo>. Instance ID: test-infra-pool-1.
@@ -664,7 +686,7 @@ launch_supervisor("ca-test-infra-improver", "test-infra-pool",
When creating tracking issues, ALWAYS include these labels:
Type/Automation, State/In Progress, Priority/Medium")
launch_supervisor("ca-architect", "architect",
launch_supervisor("ca-architect", "architect", "AUTO-ARCH",
"You are the continuous architecture designer.
SESSION STATE ISSUE: #{SESSION_STATE_ISSUE_NUMBER}
Repo: <owner>/<repo>. Instance ID: architect-1.
@@ -673,7 +695,7 @@ launch_supervisor("ca-architect", "architect",
When creating tracking issues, ALWAYS include these labels:
Type/Automation, State/In Progress, Priority/Medium")
launch_supervisor("ca-epic-planner", "epic-planner",
launch_supervisor("ca-epic-planner", "epic-planner", "AUTO-EPIC",
"You are the continuous epic planner.
SESSION STATE ISSUE: #{SESSION_STATE_ISSUE_NUMBER}
Repo: <owner>/<repo>. Instance ID: epic-planner-1.
@@ -681,7 +703,7 @@ launch_supervisor("ca-epic-planner", "epic-planner",
When creating tracking issues, ALWAYS include these labels:
Type/Automation, State/In Progress, Priority/Medium")
launch_supervisor("ca-human-liaison", "human-liaison",
launch_supervisor("ca-human-liaison", "human-liaison", "AUTO-HUMAN",
"You are the human liaison.
SESSION STATE ISSUE: #{SESSION_STATE_ISSUE_NUMBER}
Repo: <owner>/<repo>. Instance ID: human-liaison-1.
@@ -689,7 +711,7 @@ launch_supervisor("ca-human-liaison", "human-liaison",
When creating tracking issues, ALWAYS include these labels:
Type/Automation, State/In Progress, Priority/Medium")
launch_supervisor("ca-agent-evolver", "agent-evolver",
launch_supervisor("ca-agent-evolver", "agent-evolver", "AUTO-EVLV",
"You are the agent evolver.
SESSION STATE ISSUE: #{SESSION_STATE_ISSUE_NUMBER}
Repo: <owner>/<repo>. Instance ID: agent-evolver-1.
@@ -697,7 +719,7 @@ launch_supervisor("ca-agent-evolver", "agent-evolver",
When creating tracking issues, ALWAYS include these labels:
Type/Automation, State/In Progress, Priority/Medium")
launch_supervisor("ca-architecture-guard", "arch-guard",
launch_supervisor("ca-architecture-guard", "arch-guard", "AUTO-GUARD",
"You are the architecture guard.
SESSION STATE ISSUE: #{SESSION_STATE_ISSUE_NUMBER}
Repo: <owner>/<repo>. Forgejo PAT: <PAT>.
@@ -705,7 +727,7 @@ launch_supervisor("ca-architecture-guard", "arch-guard",
When creating tracking issues, ALWAYS include these labels:
Type/Automation, State/In Progress, Priority/Medium")
launch_supervisor("ca-spec-updater", "spec-updater",
launch_supervisor("ca-spec-updater", "spec-updater", "AUTO-SPEC",
"You are the spec updater.
SESSION STATE ISSUE: #{SESSION_STATE_ISSUE_NUMBER}
Repo: <owner>/<repo>. Forgejo PAT: <PAT>.
@@ -713,7 +735,7 @@ launch_supervisor("ca-spec-updater", "spec-updater",
When creating tracking issues, ALWAYS include these labels:
Type/Automation, State/In Progress, Priority/Medium")
launch_supervisor("ca-backlog-groomer", "backlog-groomer",
launch_supervisor("ca-backlog-groomer", "backlog-groomer", "AUTO-BLOG",
"You are the backlog groomer.
SESSION STATE ISSUE: #{SESSION_STATE_ISSUE_NUMBER}
Repo: <owner>/<repo>. Instance ID: groomer-1.
@@ -721,7 +743,7 @@ launch_supervisor("ca-backlog-groomer", "backlog-groomer",
When creating tracking issues, ALWAYS include these labels:
Type/Automation, State/In Progress, Priority/Medium")
launch_supervisor("ca-docs-writer", "docs-writer",
launch_supervisor("ca-docs-writer", "docs-writer", "AUTO-DOCS",
"You are the documentation writer.
SESSION STATE ISSUE: #{SESSION_STATE_ISSUE_NUMBER}
Repo: <owner>/<repo>. Forgejo PAT: <PAT>.
@@ -729,7 +751,7 @@ launch_supervisor("ca-docs-writer", "docs-writer",
When creating tracking issues, ALWAYS include these labels:
Type/Automation, State/In Progress, Priority/Medium")
launch_supervisor("ca-timeline-updater", "timeline-updater",
launch_supervisor("ca-timeline-updater", "timeline-updater", "AUTO-TIME",
"You are the timeline updater.
SESSION STATE ISSUE: #{SESSION_STATE_ISSUE_NUMBER}
Repo: <owner>/<repo>. Forgejo PAT: <PAT>.
@@ -737,7 +759,7 @@ launch_supervisor("ca-timeline-updater", "timeline-updater",
When creating tracking issues, ALWAYS include these labels:
Type/Automation, State/In Progress, Priority/Medium")
launch_supervisor("ca-project-owner", "project-owner",
launch_supervisor("ca-project-owner", "project-owner", "AUTO-OWNR",
"You are the project owner and triager.
SESSION STATE ISSUE: #{SESSION_STATE_ISSUE_NUMBER}
Repo: <owner>/<repo>. Instance ID: project-owner-1.
@@ -745,7 +767,7 @@ launch_supervisor("ca-project-owner", "project-owner",
When creating tracking issues, ALWAYS include these labels:
Type/Automation, State/In Progress, Priority/Medium")
launch_supervisor("ca-system-watchdog", "system-watchdog",
launch_supervisor("ca-system-watchdog", "system-watchdog", "AUTO-WDOG",
"You are the system watchdog.
SESSION STATE ISSUE: #{SESSION_STATE_ISSUE_NUMBER}
Repo: <owner>/<repo>. Instance ID: watchdog-1.
@@ -810,6 +832,91 @@ invoke ca-session-persister with:
supervisors_relaunched = 0
heartbeat_count = 0
# ── Supervisor metadata mapping for re-launching ─────────────────
# Maps display_name -> {agent_name, tag, prompt_template}
SUPERVISOR_METADATA = {
"implementor-pool": {
"agent": "issue-implementor",
"tag": "AUTO-IMP-SUP",
"prompt": "You are the implementation pool supervisor..."
},
"reviewer-pool": {
"agent": "ca-continuous-pr-reviewer",
"tag": "AUTO-REV-SUP",
"prompt": "You are the PR review pool supervisor..."
},
"tester-pool": {
"agent": "ca-uat-tester",
"tag": "AUTO-UAT-SUP",
"prompt": "You are the UAT testing pool supervisor..."
},
"hunter-pool": {
"agent": "ca-bug-hunter",
"tag": "AUTO-BUG-SUP",
"prompt": "You are the bug hunting pool supervisor..."
},
"test-infra-pool": {
"agent": "ca-test-infra-improver",
"tag": "AUTO-INF-SUP",
"prompt": "You are the test infrastructure improvement pool supervisor..."
},
"architect": {
"agent": "ca-architect",
"tag": "AUTO-ARCH",
"prompt": "You are the continuous architecture designer..."
},
"epic-planner": {
"agent": "ca-epic-planner",
"tag": "AUTO-EPIC",
"prompt": "You are the continuous epic planner..."
},
"human-liaison": {
"agent": "ca-human-liaison",
"tag": "AUTO-HUMAN",
"prompt": "You are the human liaison..."
},
"agent-evolver": {
"agent": "ca-agent-evolver",
"tag": "AUTO-EVLV",
"prompt": "You are the agent evolver..."
},
"arch-guard": {
"agent": "ca-architecture-guard",
"tag": "AUTO-GUARD",
"prompt": "You are the architecture guard..."
},
"spec-updater": {
"agent": "ca-spec-updater",
"tag": "AUTO-SPEC",
"prompt": "You are the spec updater..."
},
"backlog-groomer": {
"agent": "ca-backlog-groomer",
"tag": "AUTO-BLOG",
"prompt": "You are the backlog groomer..."
},
"docs-writer": {
"agent": "ca-docs-writer",
"tag": "AUTO-DOCS",
"prompt": "You are the documentation writer..."
},
"timeline-updater": {
"agent": "ca-timeline-updater",
"tag": "AUTO-TIME",
"prompt": "You are the timeline updater..."
},
"project-owner": {
"agent": "ca-project-owner",
"tag": "AUTO-OWNR",
"prompt": "You are the project owner and triager..."
},
"system-watchdog": {
"agent": "ca-system-watchdog",
"tag": "AUTO-WDOG",
"prompt": "You are the system watchdog..."
}
}
MONITORING LOOP (runs until product is verified complete):
# ── Sleep 60 seconds ─────────────────────────────────────────
@@ -823,6 +930,33 @@ MONITORING LOOP (runs until product is verified complete):
# ── Check session status for all supervisors ─────────────────
# Use Bash tool to curl the session status endpoint:
STATUS = bash("curl -s ${SERVER}/session/status")
# ── Count supervisors and workers by tag ─────────────────────
# Get all sessions and count by tag pattern
ALL_SESSIONS = bash("curl -s ${SERVER}/session")
# Count pool supervisors (should be exactly 1 each)
IMP_SUP_COUNT = bash("echo '${ALL_SESSIONS}' | grep -c '\\[AUTO-IMP-SUP\\]' || echo 0")
REV_SUP_COUNT = bash("echo '${ALL_SESSIONS}' | grep -c '\\[AUTO-REV-SUP\\]' || echo 0")
UAT_SUP_COUNT = bash("echo '${ALL_SESSIONS}' | grep -c '\\[AUTO-UAT-SUP\\]' || echo 0")
BUG_SUP_COUNT = bash("echo '${ALL_SESSIONS}' | grep -c '\\[AUTO-BUG-SUP\\]' || echo 0")
INF_SUP_COUNT = bash("echo '${ALL_SESSIONS}' | grep -c '\\[AUTO-INF-SUP\\]' || echo 0")
# Count workers by type
IMP_WORK_COUNT = bash("echo '${ALL_SESSIONS}' | grep -c '\\[AUTO-IMP\\]' || echo 0")
REV_WORK_COUNT = bash("echo '${ALL_SESSIONS}' | grep -c '\\[AUTO-REV\\]' || echo 0")
UAT_WORK_COUNT = bash("echo '${ALL_SESSIONS}' | grep -c '\\[AUTO-UAT\\]' || echo 0")
BUG_WORK_COUNT = bash("echo '${ALL_SESSIONS}' | grep -c '\\[AUTO-BUG\\]' || echo 0")
INF_WORK_COUNT = bash("echo '${ALL_SESSIONS}' | grep -c '\\[AUTO-INF\\]' || echo 0")
# Count singleton supervisors
SINGLETON_COUNTS = bash("echo '${ALL_SESSIONS}' | grep -E '\\[AUTO-(ARCH|EPIC|HUMAN|EVLV|GUARD|SPEC|BLOG|DOCS|TIME|OWNR|WDOG)\\]' | wc -l || echo 0")
# Log counts every 10 heartbeats
if heartbeat_count % 10 == 0:
echo "Supervisor counts: IMP=${IMP_SUP_COUNT}, REV=${REV_SUP_COUNT}, UAT=${UAT_SUP_COUNT}, BUG=${BUG_SUP_COUNT}, INF=${INF_SUP_COUNT}"
echo "Worker counts: IMP=${IMP_WORK_COUNT}, REV=${REV_WORK_COUNT}, UAT=${UAT_WORK_COUNT}, BUG=${BUG_WORK_COUNT}, INF=${INF_WORK_COUNT}"
echo "Singleton supervisors: ${SINGLETON_COUNTS}/11"
# Parse status to find sessions that are no longer active
for each supervisor in /tmp/ca-supervisor-sessions.env:
@@ -831,8 +965,10 @@ MONITORING LOOP (runs until product is verified complete):
if session is completed or errored or not found:
# ── IMMEDIATELY re-launch this supervisor ────────────
# Get metadata for this supervisor
metadata = SUPERVISOR_METADATA[display_name]
# Create new session + prompt_async (same as Phase C.2)
launch_supervisor(agent_name, display_name, prompt_text)
launch_supervisor(metadata["agent"], display_name, metadata["tag"], metadata["prompt"])
supervisors_relaunched += 1
# Update the tracking file with the new session ID
@@ -863,7 +999,8 @@ MONITORING LOOP (runs until product is verified complete):
"Supervisor: Product Builder | Agent: product-builder"
)
# Re-launch the zombie supervisor
launch_supervisor(agent_name, display_name, prompt_text)
metadata = SUPERVISOR_METADATA[display_name]
launch_supervisor(metadata["agent"], display_name, metadata["tag"], metadata["prompt"])
supervisors_relaunched += 1
# ── Check system watchdog alerts (every 3 heartbeats) ────────