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
96 changes: 96 additions & 0 deletions .github/workflows/review-swarm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
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:
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
# Ordering invariant: job 75m > poll 3900s (65m) > swarm 3600000ms (60m).
timeout-minutes: 75
steps:
- name: Check out immutable gate from main
uses: actions/checkout@v4
with:
ref: main
path: gate

- name: Check out PR head
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
path: target

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

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

- name: Fetch PR evidence on runner
env:
GH_TOKEN: ${{ github.token }}
working-directory: target
run: ../gate/.github/workflows/scripts/swarm-prepare.sh '${{ github.event.pull_request.number }}' ../gate

- name: Launch cloud swarm
id: launch
env:
RELAY_API_KEY: ${{ secrets.RELAY_WORKSPACE_KEY }}
working-directory: target
run: |
result=$(agent-relay cloud run --json ../gate/workflows/review-swarm.yaml)
run_id=$(printf '%s' "$result" | jq -er '.runId // .id')
echo "run_id=$run_id" >> "$GITHUB_OUTPUT"

- name: Wait for cloud swarm
id: wait
if: steps.launch.outputs.run_id != ''
env:
RELAY_API_KEY: ${{ secrets.RELAY_WORKSPACE_KEY }}
run: |
deadline=$((SECONDS + 3900))
swarm_status=timed_out
while [ "$SECONDS" -lt "$deadline" ]; do
status_json=$(agent-relay cloud status --json '${{ steps.launch.outputs.run_id }}') || {
swarm_status=status_error
break
}
swarm_status=$(printf '%s' "$status_json" | jq -r '.status // "unknown"')
case "$swarm_status" in
completed|failed|cancelled) break ;;
esac
sleep 15
done
echo "swarm_status=$swarm_status" >> "$GITHUB_OUTPUT"
# Deliberately exit zero: post must publish evidence for rejected runs.
exit 0

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

- name: Enforce terminal success
if: steps.wait.outputs.swarm_status != 'completed'
run: |
echo "Review swarm did not complete: ${{ steps.wait.outputs.swarm_status }}" >&2
exit 1
51 changes: 51 additions & 0 deletions .github/workflows/scripts/swarm-post.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/bin/sh
set -eu

run_id=$1
pr=$2
repo=$3
worktree=$4
sync_started=$(date +%s)

agent-relay cloud sync "$run_id" --dir "$worktree"
cd "$worktree"
. .review-target/swarm-verdict.sh

post_sticky() {
anchor=$1
body_file=$2
comment_id=$(gh api --paginate "repos/$repo/issues/$pr/comments" \
--jq ".[] | select(.body | contains(\"$anchor\")) | .id" | head -n 1)
if [ -n "$comment_id" ]; then
gh api --method PATCH "repos/$repo/issues/comments/$comment_id" \
--raw-field "body=$(cat "$body_file")" >/dev/null
else
gh pr comment "$pr" --repo "$repo" --body-file "$body_file" >/dev/null
fi
}

failed=0
for lens in $SWARM_LENSES; do
transcript=$(swarm_latest_transcript "$pr" "$lens" ops/reviews)
if [ -z "$transcript" ] || [ "$(stat -c %Y "$transcript")" -lt "$sync_started" ]; then
echo "POST_FAILED: $lens transcript is missing or stale" >&2
failed=1
continue
fi
body=$(mktemp)
printf '<!-- swarm-lens: %s -->\n' "$lens" > "$body"
cat "$transcript" >> "$body"
post_sticky "<!-- swarm-lens: $lens -->" "$body"
rm -f "$body"
done

marker=$(mktemp)
if [ "$failed" -eq 0 ] && swarm_evaluate "$pr" ops/reviews; then
printf '%s\n%s\n' '<!-- review-swarm -->' '🎯 review-swarm: PASSED' > "$marker"
else
failed=1
printf '%s\n%s\n' '<!-- review-swarm -->' '🛑 review-swarm: FAILED' > "$marker"
fi
post_sticky '<!-- review-swarm -->' "$marker"
rm -f "$marker"
[ "$failed" -eq 0 ]
25 changes: 25 additions & 0 deletions .github/workflows/scripts/swarm-prepare.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/bin/sh
set -eu

pr=$1
gate_root=$2
target_dir=.review-target

case "$pr" in *[!0-9]*|'') echo "PREPARE_FAILED: invalid PR number" >&2; exit 64;; esac
[ -f "$gate_root/.github/workflows/scripts/swarm-verdict.sh" ] || {
echo "PREPARE_FAILED: trusted verdict helper missing" >&2; exit 66;
}

mkdir -p "$target_dir"
printf '%s\n' "$pr" > "$target_dir/pr-number"
gh pr diff "$pr" > "$target_dir/pr.diff"
gh pr view "$pr" --json headRefName,headRefOid,title,url > "$target_dir/pr.json"
cp "$gate_root/.github/workflows/scripts/swarm-verdict.sh" \
"$target_dir/swarm-verdict.sh"

for file in pr-number pr.diff pr.json swarm-verdict.sh; do
[ -s "$target_dir/$file" ] || {
echo "PREPARE_FAILED: $target_dir/$file is empty" >&2; exit 65;
}
done
git add -f "$target_dir"
47 changes: 47 additions & 0 deletions .github/workflows/scripts/swarm-verdict.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/bin/sh

SWARM_LENSES="maintainability history structure"

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

swarm_transcript_verdict() {
awk 'NF { line=$0 } END {
count=split(line, words, /[[:space:]]+/)
print count ? words[count] : ""
}' "$1"
}

swarm_evaluate() {
pr=$1
reviews_dir=$2
failed=0

for lens in $SWARM_LENSES; do
transcript=$(swarm_latest_transcript "$pr" "$lens" "$reviews_dir")
if [ -z "$transcript" ]; then
echo "SWARM_FAILED: $lens transcript MISSING"
failed=1
continue
fi

verdict=$(swarm_transcript_verdict "$transcript")
if [ "$verdict" = REVIEW_PASSED ]; then
echo "SWARM_LENS: $lens PASSED $transcript"
elif [ "$verdict" = REVIEW_FAILED ]; then
echo "SWARM_FAILED: $lens FAILED $transcript"
failed=1
else
echo "SWARM_FAILED: $lens UNCLEAR $transcript"
failed=1
fi
done

[ "$failed" -eq 0 ] && { echo SWARM_PASSED; return 0; }
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
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,17 @@ 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.

## Review-swarm secret

The `Review swarm` GitHub Actions workflow requires a repository Actions secret
named `RELAY_WORKSPACE_KEY`. Obtain the unmasked key for the canonical workspace
with:

```bash
agent-relay workspace key --reveal-secrets
```

Add that value under **Settings → Secrets and variables → Actions → New
repository secret**. The workflow fails during preflight when the secret is
missing; it never falls back to interactive login.
Loading
Loading