From 51cd94dcd50856c1fe996ef11bcb5f1e790e520e Mon Sep 17 00:00:00 2001 From: Jeffrey Phillips Freeman Date: Sun, 5 Apr 2026 23:00:43 +0000 Subject: [PATCH] Fix supervisor monitoring with unique naming tags 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. --- .opencode/agents/ca-bug-hunter.md | 6 +- .opencode/agents/ca-continuous-pr-reviewer.md | 2 +- .opencode/agents/ca-system-watchdog.md | 73 +++++-- .opencode/agents/ca-test-infra-improver.md | 6 +- .opencode/agents/ca-uat-tester.md | 6 +- .opencode/agents/issue-implementor.md | 16 +- .opencode/agents/product-builder.md | 185 +++++++++++++++--- 7 files changed, 239 insertions(+), 55 deletions(-) diff --git a/.opencode/agents/ca-bug-hunter.md b/.opencode/agents/ca-bug-hunter.md index 3b38d15a6..cb26dbbe9 100644 --- a/.opencode/agents/ca-bug-hunter.md +++ b/.opencode/agents/ca-bug-hunter.md @@ -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: \"}' \ + -d '{\"title\": \"[AUTO-BUG] worker-hunt: \"}' \ | 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 \ diff --git a/.opencode/agents/ca-continuous-pr-reviewer.md b/.opencode/agents/ca-continuous-pr-reviewer.md index e196fe3eb..1a7beb746 100644 --- a/.opencode/agents/ca-continuous-pr-reviewer.md +++ b/.opencode/agents/ca-continuous-pr-reviewer.md @@ -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) diff --git a/.opencode/agents/ca-system-watchdog.md b/.opencode/agents/ca-system-watchdog.md index 97568354e..f4f5340da 100644 --- a/.opencode/agents/ca-system-watchdog.md +++ b/.opencode/agents/ca-system-watchdog.md @@ -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: "}' + -d '{"title": "[AUTO-ONEOFF] "}' curl -s -X POST "${SERVER}/session/${SESSION_ID}/prompt_async" \ -H "Content-Type: application/json" \ diff --git a/.opencode/agents/ca-test-infra-improver.md b/.opencode/agents/ca-test-infra-improver.md index b35634dfb..a73855cd5 100644 --- a/.opencode/agents/ca-test-infra-improver.md +++ b/.opencode/agents/ca-test-infra-improver.md @@ -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: \"}' \ + -d '{\"title\": \"[AUTO-INF] worker-testinfra: \"}' \ | 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 \ diff --git a/.opencode/agents/ca-uat-tester.md b/.opencode/agents/ca-uat-tester.md index 90f1ea73b..16b4359bd 100644 --- a/.opencode/agents/ca-uat-tester.md +++ b/.opencode/agents/ca-uat-tester.md @@ -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: \"}' \ + -d '{\"title\": \"[AUTO-UAT] worker-uat: \"}' \ | 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 \ diff --git a/.opencode/agents/issue-implementor.md b/.opencode/agents/issue-implementor.md index 4ac645bf3..784ed7a6b 100644 --- a/.opencode/agents/issue-implementor.md +++ b/.opencode/agents/issue-implementor.md @@ -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): diff --git a/.opencode/agents/product-builder.md b/.opencode/agents/product-builder.md index 40057c59a..51e8eee63 100644 --- a/.opencode/agents/product-builder.md +++ b/.opencode/agents/product-builder.md @@ -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: /. Forgejo 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: /. 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: /. 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: /. 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: /. 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: /. 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: /. 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: /. 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: /. 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: /. Forgejo 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: /. Forgejo 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: /. 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: /. Forgejo 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: /. Forgejo 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: /. 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: /. 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) ────────