Playbook: Executing Infra Task Requests

Audience: p24-infra admin Claude (and human admins) processing incoming infra-task-request issues. For how to submit a request from another repo, see docs/playbooks/cross-project-infra-requests.md.


System architecture

Infra task requests flow through three layers:

  1. GH Actions infra-task-intake.yml — fires on issues event, inserts a row into Supabase dev_r_infra_task_requests with status=queued, adds waiting-infra to the Return-To issue.
  2. n8n workflow infra-task-queue-processor on bms-4 — polls Supabase every 2 minutes, picks up status=queued rows, calls spawn-infra-task-worker.sh via SSH.
  3. claude-runner worker on bms-4 — executes the task, commits changes, opens PRs, posts callback comment on the Return-To issue.

Worker: bms-4 (OVH ns3101999, 54.36.123.110) Spawn script: /opt/p24-infra/scripts/spawn-infra-task-worker.sh <issue_num> Worker logs: /var/log/p24-infra-workers/infra-task-<N>.log Supabase table: dev_r_infra_task_requests in project mwkqmgadqnkkihjdeqsi


Full request lifecycle

TimeEvent
T+0Issue created in radieu/p24-infra with label infra-task-request
T+0infra-task-intake.yml fires, inserts Supabase row status=queued, adds waiting-infra to Return-To issue
T+0 to T+2 minn8n infra-task-queue-processor polls, picks up status=queued row
T+2 minn8n calls spawn-infra-task-worker.sh <issue_num> on bms-4 via SSH; row → status=in_progress
T+2 to T+30 minclaude-runner worker on bms-4 executes, commits, opens PRs
T+doneWorker posts callback comment on Return-To issue, removes waiting-infra, sets p24-infra issue → infra-done, Supabase row → status=done

How to process a received request

When you (the executor worker) receive an infra task request, follow these steps in order.

Step 1 — Parse the issue body

Read the issue and extract the header fields:

Return-To: <repo>#<issue-number>   ← where to post the callback comment
Priority: normal|urgent            ← already handled by dispatcher ordering
E2E/Browser: yes|no               ← affects your timeout and available tools

E2E/Browser handling:

ValueMeaningYour constraints
noCLI/API-only taskStandard 30-min timeout · no display needed
yesNeeds browser or E2E testsUp to 60-min timeout · Playwright/headed Chrome available · needs display/GPU resources
missingTreat as noNote the missing field in your callback comment

Step 2 — Detect task type

Simple task## Task description present, no ## Dependency graph section → execute directly, skip to Step 3.

Orchestrator task## Dependency graph section present → execute waves:

  1. Parse each wave block. Items listed as parallel within a wave run concurrently; waves are sequential.
  2. Execute wave 1 — run all parallel items, wait for all to complete.
  3. If any item in the wave fails: stop, post failure callback (see Step 5), add human-action label. Do not proceed to the next wave.
  4. Proceed to wave 2, repeat until all waves complete.
  5. Post success callback when the last wave is done.

Step 3 — Execute the task

Read the task description carefully. Apply all rules from p24-infra CLAUDE.md.

Key rules:

  • Never display secret values — read from SOPS or .env.bak
  • Every script/action failure → Discord webhook + GH issue in radieu/p24-infra before continuing
  • No direct commits to main — all changes via PR to main from a feature/fix branch
  • SSH commands that modify server files require # PLAYBOOK: infra-task-executor.md annotation

Step 4 — Post callback comment on the Return-To issue

Success:

gh issue comment <N> --repo <repo> --body "$(cat <<'EOF'
## Infra task complete

**Request:** radieu/p24-infra#<issue_number>
**Status:** done

### What was done

- <bullet per action taken>

### Next steps

<what the requesting session should do now, or "none">
EOF
)"

Failure / partial:

gh issue comment <N> --repo <repo> --body "$(cat <<'EOF'
## Infra task failed

**Request:** radieu/p24-infra#<issue_number>
**Status:** failed

### What failed

<description of what went wrong and why>

### What completed (if partial)

- <steps that succeeded before failure, or "none">

### Action required

<what a human needs to do to resolve>
EOF
)"

Step 5 — Close out the request

After posting the callback:

# Remove waiting-infra from the Return-To issue
gh issue edit <N> --repo <repo> --remove-label "waiting-infra"
 
# Mark the p24-infra issue done (success or failure — "done" means processing complete)
gh issue edit <infra_issue_number> --repo radieu/p24-infra \
  --remove-label "wip" --add-label "infra-done"

Monitoring

GH issue labels:

LabelMeaning
infra-task-requestQueued, awaiting pickup
wipWorker spawned and running
human-actionWorker paused — destructive op or ambiguous task; human must unblock
infra-doneComplete, callback posted

Supabase — queue state:

SELECT id, issue_number, status, created_at, updated_at
FROM dev_r_infra_task_requests
ORDER BY created_at DESC
LIMIT 10;

Status values: queuedin_progressdone | failed | blocked_human_action

Worker logs on bms-4:

ssh root@54.36.123.110 "tail -100 /var/log/p24-infra-workers/infra-task-<N>.log"
# List recent worker log files:
ssh root@54.36.123.110 "ls -lt /var/log/p24-infra-workers/infra-task-*.log | head -5"

Escalation

n8n not picking up the task (>10 min after submission)

  1. Check n8n is running and workflow is active:

    • Open https://n8n.bms-4.infra.zintegrowana.online → Workflows → infra-task-queue-processor
    • Confirm status is Active; if inactive, activate it.
  2. Check Supabase row status:

    SELECT status, created_at FROM dev_r_infra_task_requests
    WHERE issue_number = <issue_number>;

    If status=queued and >10 min elapsed, n8n is the bottleneck.

  3. If n8n is down: the hourly triage on bms-4 runs a Phase 2 sweep that picks up stale queued rows as fallback. Wait up to 1 hour or trigger manually.

  4. Manual trigger (emergency):

    ssh root@54.36.123.110 "sudo -u claude-runner /opt/p24-infra/scripts/spawn-infra-task-worker.sh <issue_num>"

Worker spawned but no result after 30 min

  1. Check worker logs:

    ssh root@54.36.123.110 "tail -100 /var/log/p24-infra-workers/infra-task-<N>.log"
  2. If status=in_progress for >2 hours: the hourly triage Phase 2B automatically resets it to queued for retry.

  3. If the p24-infra issue has human-action label: see section below.

  4. If issue has infra-done but no callback comment on Return-To issue: the gh issue comment call failed. Check worker logs for the error. Post a manual comment on the Return-To issue referencing the p24-infra issue number.

human-action label added

The worker detected a potential problem and paused:

  • Destructive keywords (delete, drop, wipe, truncate, reset) in the task description
  • Return-To: none on a task that looks like it should have a callback
  • Ambiguous task description requiring clarification

To unblock:

  1. Read the comment the worker posted — it explains what triggered the gate.
  2. If safe to proceed: add a comment Approved — proceed, remove human-action, re-add infra-task-request to re-queue.
  3. If task needs clarification: contact the requester (via the Return-To issue), then edit the p24-infra issue body, remove human-action, re-add infra-task-request.

  • Requester playbook: docs/playbooks/cross-project-infra-requests.md
  • Hourly triage: docs/playbooks/hourly-triage-outage.md
  • Spawn script on bms-4: /opt/p24-infra/scripts/spawn-infra-task-worker.sh
  • Supabase table: dev_r_infra_task_requests