Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .claude/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"permissions": {
"allow": [
"mcp__relaycast__*"
"mcp__relaycast__*",
"mcp__agent-relay__*"
]
}
}
103 changes: 103 additions & 0 deletions .github/workflows/review-swarm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
name: Review swarm

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]

permissions:
contents: read
pull-requests: write

concurrency:
group: review-swarm-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
review:
runs-on: ubuntu-latest
# Ordering invariant: 75-minute job > 65-minute poll > 60-minute swarm.
timeout-minutes: 75
steps:
- name: Check out PR head
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
path: review-target
fetch-depth: 0

- name: Check out immutable gate from main
uses: actions/checkout@v4
with:
ref: main
path: review-gate
sparse-checkout: |
workflows/review-swarm.yaml
.github/workflows/scripts

- name: Validate cloud authentication
env:
RELAY_WORKSPACE_KEY: ${{ secrets.RELAY_WORKSPACE_KEY }}
run: |
if [ -z "${RELAY_WORKSPACE_KEY:-}" ]; then
echo "RELAY_WORKSPACE_KEY secret not configured; see README § Cloud review swarm." >&2
exit 1
fi

- name: Install Agent Relay
run: npm install --global agent-relay

- name: Prepare review input
env:
GH_TOKEN: ${{ github.token }}
run: review-gate/.github/workflows/scripts/swarm-prepare.sh "${{ github.event.pull_request.number }}" review-target review-gate

- name: Launch cloud swarm
id: launch
working-directory: review-target
env:
RELAY_WORKSPACE_KEY: ${{ secrets.RELAY_WORKSPACE_KEY }}
run: |
response=$(agent-relay cloud run \
"$GITHUB_WORKSPACE/review-gate/workflows/review-swarm.yaml" \
--sync-code --json)
run_id=$(jq -r '.run_id // .runId // .id // empty' <<< "$response")
if [ -z "$run_id" ]; then
echo "cloud launch returned no run id: $response" >&2
exit 1
fi
echo "run_id=$run_id" >> "$GITHUB_OUTPUT"

- name: Wait for terminal cloud status
id: wait
env:
RELAY_WORKSPACE_KEY: ${{ secrets.RELAY_WORKSPACE_KEY }}
run: |
# Ordering invariant: 65-minute poll > 60-minute swarm, < 75-minute job.
deadline=$((SECONDS + 3900))
swarm_status=timed_out
while [ "$SECONDS" -lt "$deadline" ]; do
response=$(agent-relay cloud status "${{ steps.launch.outputs.run_id }}" --json 2>/dev/null) || response='{}'
status=$(jq -r '.status // empty' <<< "$response")
case "$status" in
completed|failed|canceled|cancelled|interrupted)
swarm_status=$status
break
;;
esac
sleep 15
done
echo "swarm_status=$swarm_status" >> "$GITHUB_OUTPUT"
exit 0

- name: Sync evidence and update PR comments
if: always() && steps.launch.outputs.run_id != ''
env:
GH_TOKEN: ${{ github.token }}
RELAY_WORKSPACE_KEY: ${{ secrets.RELAY_WORKSPACE_KEY }}
run: review-gate/.github/workflows/scripts/swarm-post.sh "${{ steps.launch.outputs.run_id }}" "${{ github.event.pull_request.number }}" review-target

- name: Enforce successful swarm
if: steps.wait.outputs.swarm_status != 'completed'
run: |
echo "Review swarm ended with status: ${{ steps.wait.outputs.swarm_status }}" >&2
exit 1
59 changes: 59 additions & 0 deletions .github/workflows/scripts/swarm-post.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/usr/bin/env bash
set -euo pipefail

run_id=${1:?usage: swarm-post.sh RUN_ID PR_NUMBER PR_CHECKOUT}
pr_number=${2:?usage: swarm-post.sh RUN_ID PR_NUMBER PR_CHECKOUT}
pr_checkout=${3:?usage: swarm-post.sh RUN_ID PR_NUMBER PR_CHECKOUT}
script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
reviews_dir="$pr_checkout/ops/reviews"
sync_started=$(date +%s)

# shellcheck source=swarm-verdict.sh
. "$script_dir/swarm-verdict.sh"

agent-relay cloud sync "$run_id" --dir "$pr_checkout"

upsert_comment() {
local anchor=$1 body=$2 comment_id
comment_id=$(gh api --paginate \
"repos/${GITHUB_REPOSITORY}/issues/${pr_number}/comments" \
| jq -s -r --arg anchor "$anchor" \
'add | map(select(.body | contains($anchor))) | last | .id // empty')
if [ -n "$comment_id" ]; then
gh api -X PATCH "repos/${GITHUB_REPOSITORY}/issues/comments/${comment_id}" \
-f body="$body" >/dev/null
else
gh api -X POST "repos/${GITHUB_REPOSITORY}/issues/${pr_number}/comments" \
-f body="$body" >/dev/null
fi
}

overall=PASSED
summary=''
for lens in maintainability history structure; do
result=$(swarm_evaluate_lens "$reviews_dir" "$pr_number" "$lens" "$sync_started") || true
IFS=$'\t' read -r state transcript verdict <<< "$result"
[ "$state" = PASSED ] || overall=FAILED
summary="${summary}- ${lens}: ${state}\n"

if [ -n "${transcript:-}" ] && [ -f "$transcript" ]; then
content=$(<"$transcript")
else
content="No fresh transcript was produced for this run (${state})."
fi
upsert_comment "<!-- swarm-lens: ${lens} -->" \
"<!-- swarm-lens: ${lens} -->
### Review swarm: ${lens}

${content}"
done

upsert_comment '<!-- swarm-marker -->' \
"<!-- swarm-marker -->
### Review swarm: ${overall}

Cloud run: \`${run_id}\`

$(printf '%b' "$summary")"

printf 'swarm verdict: %s\n' "$overall"
24 changes: 24 additions & 0 deletions .github/workflows/scripts/swarm-prepare.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -euo pipefail

pr_number=${1:?usage: swarm-prepare.sh PR_NUMBER PR_CHECKOUT GATE_CHECKOUT}
pr_checkout=${2:?usage: swarm-prepare.sh PR_NUMBER PR_CHECKOUT GATE_CHECKOUT}
gate_checkout=${3:?usage: swarm-prepare.sh PR_NUMBER PR_CHECKOUT GATE_CHECKOUT}
target_dir="$pr_checkout/.review-target"

case $pr_number in
''|*[!0-9]*) echo "invalid PR number: $pr_number" >&2; exit 2 ;;
esac

mkdir -p "$target_dir"
printf '%s\n' "$pr_number" > "$target_dir/pr-number"
gh pr diff "$pr_number" --repo "$GITHUB_REPOSITORY" > "$target_dir/pr.diff"
gh pr view "$pr_number" --repo "$GITHUB_REPOSITORY" \
--json headRefName,headRefOid,title,url > "$target_dir/pr.json"

# The uploaded helper is copied from main's checkout. The reviewed head cannot
# alter the verdict code used by the cloud aggregate.
cp "$gate_checkout/.github/workflows/scripts/swarm-verdict.sh" \
"$target_dir/swarm-verdict.sh"
git -C "$pr_checkout" add -f .review-target/pr-number .review-target/pr.diff \
.review-target/pr.json .review-target/swarm-verdict.sh
55 changes: 55 additions & 0 deletions .github/workflows/scripts/swarm-verdict.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/usr/bin/env bash

# Shared by the cloud aggregate and the GitHub-side publisher. Callers choose
# whether to supply a lower mtime bound for newly-synced transcript evidence.

swarm_find_transcript() {
local reviews_dir=$1 pr_number=$2 lens=$3

find "$reviews_dir" -maxdepth 1 -type f \
-name "????????-????-pr${pr_number}-${lens}.md" -print 2>/dev/null \
| LC_ALL=C sort \
| tail -n 1
}

swarm_last_verdict() {
local transcript=$1 last_line

last_line=$(awk 'NF { line=$0 } END { print line }' "$transcript")
if [[ $last_line =~ (^|[[:space:]])(REVIEW_PASSED|REVIEW_FAILED)([[:space:]]|$) ]]; then
printf '%s\n' "${BASH_REMATCH[2]}"
else
printf '%s\n' "REVIEW_UNCLEAR"
fi
}

swarm_evaluate_lens() {
local reviews_dir=$1 pr_number=$2 lens=$3 minimum_mtime=${4:-}
local transcript verdict mtime

transcript=$(swarm_find_transcript "$reviews_dir" "$pr_number" "$lens")
if [ -z "$transcript" ]; then
printf 'MISSING\t\tREVIEW_MISSING\n'
return 1
fi

if [ -n "$minimum_mtime" ]; then
mtime=$(stat -c %Y "$transcript")
if [ "$mtime" -lt "$minimum_mtime" ]; then
printf 'STALE\t%s\tREVIEW_STALE\n' "$transcript"
return 1
fi
fi

verdict=$(swarm_last_verdict "$transcript")
if [ "$verdict" = REVIEW_PASSED ]; then
printf 'PASSED\t%s\t%s\n' "$transcript" "$verdict"
return 0
fi
if [ "$verdict" = REVIEW_FAILED ]; then
printf 'FAILED\t%s\t%s\n' "$transcript" "$verdict"
else
printf 'UNCLEAR\t%s\t%s\n' "$transcript" "$verdict"
fi
return 1
}
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ dist/
.env
.agentworkforce/
.cargo-home/
.review-target

# Toolchains materialize inside the workspace in a cloud sandbox and must never
# be committed or delivered. Run f18ec684's patch carried .rustup-home/ files;
# ops/deliver-run.sh scrubs them too, but ignoring them is the durable fix.
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,11 @@ Nine gates, in `docs/RFC-0001` §3. Gate 1 first: a relayflow can run — the he
ladder survives `kill -9` at every boundary.

Private while we build. YC 2026-09-15 runs on this base.

## Cloud review swarm

The `Review swarm` GitHub Actions workflow requires a repository Actions secret
named `RELAY_WORKSPACE_KEY`. Obtain the real key with
`agent-relay workspace key --reveal-secrets`, then add it under **Settings →
Secrets and variables → Actions**. The masked output from `agent-relay workspace
key` without `--reveal-secrets` is not usable authentication material.
Loading
Loading