Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
139 changes: 119 additions & 20 deletions .github/workflows/pr-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@ jobs:
# the runner pod for 6 hours. The longest panel cell is 2*(1200+10)=40m20s.
# Chair primary/fallback total at most 2*(120+900+10)=34m20s, leaving 15m20s
# for setup, publication, and cleanup. Mint a one-hour AWS session before each model phase.
timeout-minutes: 90
# Batched runs execute at most max_parallel_batches (4) batches at once, so a review of up
# to 8 batches takes at most two waves per phase, each wave its own step and AWS session:
# 2*40m20s panel + 2*34m20s chair = 149m20s, plus 15m image staging, 15m20s setup/publish
# and about 10 minutes of slack so the gate can still publish a diagnostic.
timeout-minutes: 190
concurrency:
group: pr-review-${{ github.event.pull_request.number }}
cancel-in-progress: true
Expand Down Expand Up @@ -293,7 +297,7 @@ jobs:
- name: Build review checklists (L2-L5)
run: |
set -euo pipefail
# Whole accepted diffs only. Input admission below rejects oversize diffs.
# Whole accepted diffs only. Input admission below batches or rejects oversize diffs.
rm -rf /tmp/pr-review/lenses
mkdir -p /tmp/pr-review/lenses
COMMON="Review the code diff for this PR, in this AWS+Kubernetes ops dashboard repo
Expand Down Expand Up @@ -361,7 +365,12 @@ jobs:
env:
HEAD_PNG_CONTEXT: ${{ steps.head_images.outputs.context }}
run: |
python3 scripts/pr-review/input_scope.py /tmp/pr-diff.txt "$HEAD_PNG_CONTEXT" >> "$GITHUB_OUTPUT"
set -euo pipefail
# A diff within one call's limit keeps the single review path. A larger diff is split
# at file boundaries into complete batches, each admitted with the same checks
# (scripts/pr-review/review_batches.py); nothing is truncated or skipped.
python3 scripts/pr-review/review_batches.py admit /tmp/pr-diff.txt "$HEAD_PNG_CONTEXT" /tmp/pr-review > /tmp/pr-review-admit.txt
cat /tmp/pr-review-admit.txt >> "$GITHUB_OUTPUT"

# Git/CLI/prompt preparation needs no AWS session. Issue credentials only now so
# even slow setup cannot consume the panel's one-hour credential lifetime.
Expand All @@ -383,6 +392,7 @@ jobs:
env:
BASE_SHA: ${{ steps.review_context.outputs.base_sha }}
HEAD_PNG_CONTEXT: ${{ steps.head_images.outputs.context }}
WAVES: ${{ steps.input_scope.outputs.waves }}
# Two complete reviews run in parallel with the existing model/budget choices.
PANEL_TIMEOUT: "1200"
# Preserve model timeouts and retries; both reports cover all four checklists.
Expand All @@ -394,17 +404,49 @@ jobs:
git worktree add --detach "$REVIEW_BASE" "$BASE_SHA"
trap 'git -C "$GITHUB_WORKSPACE" worktree remove "$REVIEW_BASE" 2>/dev/null || true' EXIT
cd "$REVIEW_BASE"
bash "$SCRIPT_ROOT/run-panel.sh" /tmp/pr-diff.txt /tmp/pr-review/lenses /tmp/pr-review
echo "panel_responded=$(tr '\n' ' ' < /tmp/pr-review/responded.txt 2>/dev/null)" >> "$GITHUB_ENV"
if [ -f /tmp/pr-review/coverage-severe.flag ]; then
echo "ready=false" >> "$GITHUB_OUTPUT"
else
echo "ready=true" >> "$GITHUB_OUTPUT"
fi
# run-panel.sh once per admitted batch of wave 1, at most max_parallel_batches at a
# time; each batch keeps its own GITHUB_ENV flags (see run-batches.sh).
bash "$SCRIPT_ROOT/run-batches.sh" panel 1 /tmp/pr-review

# Batches beyond max_parallel_batches form a second wave with its own one-hour session
# (the review role's maximum), so no wave outlives its credentials.
- name: Renew AWS credentials before the second panel wave
id: panel_credentials_2
if: steps.input_scope.outputs.ready == 'true' && steps.input_scope.outputs.waves == '2' && steps.panel_review.outcome == 'success'
uses: aws-actions/configure-aws-credentials@v4
with:
mask-aws-account-id: true
role-to-assume: ${{ secrets.AWS_CI_REVIEW_ROLE_ARN }}
aws-region: us-east-1
role-duration-seconds: 3600
unset-current-credentials: true
use-existing-credentials: false

- name: Run panel (two comprehensive reviewers) โ€” second batch wave
id: panel_review_2
if: steps.input_scope.outputs.ready == 'true' && steps.input_scope.outputs.waves == '2' && steps.panel_review.outcome == 'success'
env:
BASE_SHA: ${{ steps.review_context.outputs.base_sha }}
HEAD_PNG_CONTEXT: ${{ steps.head_images.outputs.context }}
WAVES: ${{ steps.input_scope.outputs.waves }}
# Two complete reviews run in parallel with the existing model/budget choices.
PANEL_TIMEOUT: "1200"
# Preserve model timeouts and retries; both reports cover all four checklists.
CLAUDE_PANEL_TIMEOUT: "1200"
run: |
set -euo pipefail
SCRIPT_ROOT="$GITHUB_WORKSPACE/scripts/pr-review"
REVIEW_BASE=$(mktemp -d "$RUNNER_TEMP/pr-review-base.XXXXXX")
git worktree add --detach "$REVIEW_BASE" "$BASE_SHA"
trap 'git -C "$GITHUB_WORKSPACE" worktree remove "$REVIEW_BASE" 2>/dev/null || true' EXIT
cd "$REVIEW_BASE"
# run-panel.sh once per admitted batch of wave 2, at most max_parallel_batches at a
# time; each batch keeps its own GITHUB_ENV flags (see run-batches.sh).
bash "$SCRIPT_ROOT/run-batches.sh" panel 2 /tmp/pr-review

- name: Renew AWS credentials before chair synthesis
id: chair_credentials
if: steps.input_scope.outputs.ready == 'true' && steps.panel_review.outputs.ready == 'true'
if: steps.input_scope.outputs.ready == 'true' && (steps.input_scope.outputs.waves == '2' && steps.panel_review_2.outputs.ready || steps.panel_review.outputs.ready) == 'true'
uses: aws-actions/configure-aws-credentials@v4
with:
mask-aws-account-id: true
Expand All @@ -416,21 +458,55 @@ jobs:

- name: Synthesize panel reviews (Claude chair)
id: chair_review
if: steps.input_scope.outputs.ready == 'true' && steps.panel_review.outputs.ready == 'true'
if: steps.input_scope.outputs.ready == 'true' && (steps.input_scope.outputs.waves == '2' && steps.panel_review_2.outputs.ready || steps.panel_review.outputs.ready) == 'true'
env:
PR_NUMBER: ${{ steps.review_context.outputs.number }}
PR_TITLE: ${{ fromJSON(steps.review_context.outputs.title_json) }}
BASE_SHA: ${{ steps.review_context.outputs.base_sha }}
HEAD_PNG_CONTEXT: ${{ steps.head_images.outputs.context }}
WAVES: ${{ steps.input_scope.outputs.waves }}
run: |
set -euo pipefail
SCRIPT_ROOT="$GITHUB_WORKSPACE/scripts/pr-review"
REVIEW_BASE=$(mktemp -d "$RUNNER_TEMP/pr-review-chair-base.XXXXXX")
git worktree add --detach "$REVIEW_BASE" "$BASE_SHA"
trap 'git -C "$GITHUB_WORKSPACE" worktree remove "$REVIEW_BASE" 2>/dev/null || true' EXIT
cd "$REVIEW_BASE"
bash "$SCRIPT_ROOT/synthesize.sh" /tmp/pr-diff.txt /tmp/pr-review \
"$PR_NUMBER" "$PR_TITLE" /tmp/review.md
# synthesize.sh once per batch of wave 1; after the last wave the combined review
# (written to /tmp/review.md) passes only if every batch passes.
REVIEW_OUT=/tmp/review.md bash "$SCRIPT_ROOT/run-batches.sh" chair 1 /tmp/pr-review

- name: Renew AWS credentials before the second chair wave
id: chair_credentials_2
if: steps.input_scope.outputs.ready == 'true' && (steps.input_scope.outputs.waves == '2' && steps.panel_review_2.outputs.ready || steps.panel_review.outputs.ready) == 'true' && steps.input_scope.outputs.waves == '2' && steps.chair_review.outcome == 'success'
uses: aws-actions/configure-aws-credentials@v4
with:
mask-aws-account-id: true
role-to-assume: ${{ secrets.AWS_CI_REVIEW_ROLE_ARN }}
aws-region: us-east-1
role-duration-seconds: 3600
unset-current-credentials: true
use-existing-credentials: false

- name: Synthesize panel reviews (Claude chair) โ€” second batch wave
id: chair_review_2
if: steps.input_scope.outputs.ready == 'true' && (steps.input_scope.outputs.waves == '2' && steps.panel_review_2.outputs.ready || steps.panel_review.outputs.ready) == 'true' && steps.input_scope.outputs.waves == '2' && steps.chair_review.outcome == 'success'
env:
PR_NUMBER: ${{ steps.review_context.outputs.number }}
PR_TITLE: ${{ fromJSON(steps.review_context.outputs.title_json) }}
BASE_SHA: ${{ steps.review_context.outputs.base_sha }}
HEAD_PNG_CONTEXT: ${{ steps.head_images.outputs.context }}
WAVES: ${{ steps.input_scope.outputs.waves }}
run: |
set -euo pipefail
SCRIPT_ROOT="$GITHUB_WORKSPACE/scripts/pr-review"
REVIEW_BASE=$(mktemp -d "$RUNNER_TEMP/pr-review-chair-base.XXXXXX")
git worktree add --detach "$REVIEW_BASE" "$BASE_SHA"
trap 'git -C "$GITHUB_WORKSPACE" worktree remove "$REVIEW_BASE" 2>/dev/null || true' EXIT
cd "$REVIEW_BASE"
# synthesize.sh once per batch of wave 2; after the last wave the combined review
# (written to /tmp/review.md) passes only if every batch passes.
REVIEW_OUT=/tmp/review.md bash "$SCRIPT_ROOT/run-batches.sh" chair 2 /tmp/pr-review

- name: Check for blocking issues
id: gate
Expand All @@ -440,9 +516,11 @@ jobs:
REVIEW_INPUT_READY: ${{ steps.input_scope.outputs.ready }}
REVIEW_INPUT_REASON: ${{ steps.input_scope.outputs.reason }}
IMAGE_STAGE_OUTCOME: ${{ steps.head_images.outcome }}
PANEL_READY: ${{ steps.panel_review.outputs.ready }}
PANEL_OUTCOME: ${{ steps.panel_review.outcome }}
CHAIR_OUTCOME: ${{ steps.chair_review.outcome }}
# With two batch waves the second step carries the phase result (it runs only after the
# first wave succeeded, so its outcome is skipped/failure whenever either wave failed).
PANEL_READY: ${{ steps.input_scope.outputs.waves == '2' && steps.panel_review_2.outputs.ready || steps.panel_review.outputs.ready }}
PANEL_OUTCOME: ${{ steps.input_scope.outputs.waves == '2' && steps.panel_review_2.outcome || steps.panel_review.outcome }}
CHAIR_OUTCOME: ${{ steps.input_scope.outputs.waves == '2' && steps.chair_review_2.outcome || steps.chair_review.outcome }}
run: |
# Fail-closed first: if an oversized line was dropped from a real source/IaC file (not a
# known generated/export type), no lens saw that content โ€” force BLOCKED regardless of the
Expand All @@ -459,9 +537,18 @@ jobs:
elif [ "$PANEL_OUTCOME" = "success" ] && [ "${PANEL_READY:-false}" != "true" ]; then
echo "result=fail" >> "$GITHUB_OUTPUT"
echo "reason=Panel coverage incomplete" >> "$GITHUB_OUTPUT"
if ! bash "${GITHUB_WORKSPACE:-$PWD}/scripts/pr-review/report-panel-failure.sh" /tmp/pr-review /tmp/review.md; then
printf '%s\n' "Panel failure diagnostics unavailable. Review remains incomplete." "VERDICT: FAIL" > /tmp/review.md
fi
WORKS=/tmp/pr-review
[ ! -s /tmp/pr-review/batch-works.tsv ] || WORKS=$(cut -f1 /tmp/pr-review/batch-works.tsv)
: > /tmp/review.md
for work in $WORKS; do
[ "$work" = /tmp/pr-review ] || [ -f "$work/coverage-severe.flag" ] || continue
[ "$work" = /tmp/pr-review ] || echo "## Batch ${work##*/batch-}" >> /tmp/review.md
if ! bash "${GITHUB_WORKSPACE:-$PWD}/scripts/pr-review/report-panel-failure.sh" "$work" /tmp/review-part.md; then
printf '%s\n' "Panel failure diagnostics unavailable. Review remains incomplete." > /tmp/review-part.md
fi
sed '/^VERDICT:/d' /tmp/review-part.md >> /tmp/review.md
done
echo "VERDICT: FAIL" >> /tmp/review.md
elif [ "$PANEL_OUTCOME" != "success" ] || [ "$CHAIR_OUTCOME" != "success" ]; then
echo "result=fail" >> "$GITHUB_OUTPUT"
if [ "${image_coverage_failed:-0}" = "1" ]; then
Expand Down Expand Up @@ -532,12 +619,18 @@ jobs:
# the code has a CRITICAL/MAJOR, so the message says so distinctly
# (synthesize.sh's chair-failed.flag -> chair_failed).
STATUS_BADGE="**Status: BLOCKED** โ€” review generation failed (model timeout/error) โ€” not a code problem, re-run the workflow"
elif [ "$GATE_RESULT" = "fail" ] && [ "${chair_failed_any:-0}" = "1" ]; then
# Batched review: at least one batch's chair failed (model timeout/error) while others
# produced verdicts. Not a code finding for the failed batches; re-run the workflow.
STATUS_BADGE="**Status: BLOCKED** โ€” review generation failed for one or more batches (model timeout/error, not a code finding for those batches) โ€” re-run the workflow; findings from other batches, if any, are below"
elif [ "$GATE_RESULT" = "fail" ]; then
STATUS_BADGE="**Status: BLOCKED** โ€” CRITICAL/MAJOR issues must be resolved before merge"
else
STATUS_BADGE="**Status: PASSED** โ€” No blocking issues found"
fi
sed '$ { /^VERDICT:/d }' /tmp/review.md > /tmp/review-clean.md
# GitHub rejects comments over 65,536 characters; batched reviews can exceed it.
python3 -I scripts/pr-review/review_batches.py fit /tmp/review-clean.md
{
echo "$MARKER"
echo "## ๐Ÿค– AI Code Review (two independent reviewers)"
Expand Down Expand Up @@ -602,3 +695,9 @@ jobs:
*) echo "::error::Unexpected HEAD PNG cleanup path"; exit 1 ;;
esac
fi

- name: Remove batched-review work directories
if: always()
run: |
# Raw batch diffs and panel slots must not persist on the self-hosted runner.
rm -rf /tmp/pr-review/batch-[0-9]* /tmp/pr-review/batch-works.tsv /tmp/review-part.md
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed

- Bedrock models: chat, AI Diagnosis, routing, synthesis and the background workers move to Claude Sonnet 5.5, Opus 5.5 (AI Diagnosis Deep tier option) and Haiku 5.5. These models reject `temperature`, so requests no longer send it. Haiku calls and Sonnet calls with fixed output caps run without extended thinking so existing budgets still fit (the chat agent keeps adaptive thinking, as on Sonnet 5); Opus 5.5, which always thinks, gets extra output headroom for Deep report sections and invariant proposals. The web task's classifier and synthesis IAM grants must allow the 5.5 models before this release rolls out.
- PR review batching: a filtered diff larger than one review call's 6,000-line/128 KiB limit is reviewed in up to 8 complete batches split at file boundaries instead of being rejected outright. Workflow, review-script, Terraform/IAM, agent, AgentCore, secret-rotation, EKS, incident, API-route and AWS-client files, plus any path segment naming auth, secret, credential, assume-role, mutation or allowlist surfaces, are reviewed together in the first batch, and each batch receives the paths changed in the other batches as data, so a dependency no listed path provides stays blocking. Each batch passes the same input admission, gets both independent reviewers and its own chair in parallel, and the PR passes only if every batch passes; a later batch cannot clear an earlier batch's coverage or report failure. A single file over the per-batch budget, or a diff needing more than 8 batches, is still rejected before any model call, and diffs within the limit keep the single-review path.

### Fixed

Expand Down Expand Up @@ -701,6 +702,7 @@ First release of the **v2 line** (versioned independently from the v1 1.x line,
### Changed

- Bedrock ๋ชจ๋ธ: ์ฑ„ํŒ…, AI ์ง„๋‹จ, ๋ผ์šฐํŒ…, ํ•ฉ์„ฑ, ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์›Œ์ปค๊ฐ€ Claude Sonnet 5.5, Opus 5.5(AI ์ง„๋‹จ Deep ๋‹จ๊ณ„ ์„ ํƒ), Haiku 5.5๋กœ ๋ฐ”๋€๋‹ˆ๋‹ค. ์ด ๋ชจ๋ธ๋“ค์€ `temperature`๋ฅผ ๊ฑฐ๋ถ€ํ•˜๋ฏ€๋กœ ์š”์ฒญ์—์„œ ๋” ์ด์ƒ ๋ณด๋‚ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Haiku ํ˜ธ์ถœ๊ณผ ์ถœ๋ ฅ ์ƒํ•œ์ด ๊ณ ์ •๋œ Sonnet ํ˜ธ์ถœ์€ ๊ธฐ์กด ์ƒํ•œ์ด ์œ ์ง€๋˜๋„๋ก ํ™•์žฅ ์‚ฌ๊ณ  ์—†์ด ์‹คํ–‰ํ•˜๊ณ (์ฑ„ํŒ… ์—์ด์ „ํŠธ๋Š” Sonnet 5 ๋•Œ์ฒ˜๋Ÿผ adaptive ์‚ฌ๊ณ  ์œ ์ง€), ํ•ญ์ƒ ์‚ฌ๊ณ ํ•˜๋Š” Opus 5.5๋Š” Deep ๋ฆฌํฌํŠธ ์„น์…˜๊ณผ ๋ถˆ๋ณ€์‹ ์ œ์•ˆ์— ์ถœ๋ ฅ ์—ฌ์œ ๋ถ„์„ ๋” ๋ฐ›์Šต๋‹ˆ๋‹ค. ์›น ํƒœ์Šคํฌ์˜ ๋ถ„๋ฅ˜๊ธฐยทํ•ฉ์„ฑ IAM ๊ถŒํ•œ์ด ์ด ๋ฆด๋ฆฌ์Šค ๋ฐฐํฌ ์ „์— 5.5 ๋ชจ๋ธ์„ ํ—ˆ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
- PR ๋ฆฌ๋ทฐ ๋ถ„ํ•  ๊ฒ€ํ† : ํ•„ํ„ฐ๋ง๋œ diff๊ฐ€ ๋ฆฌ๋ทฐ 1ํšŒ ํ•œ๋„(6,000์ค„/128 KiB)๋ฅผ ๋„˜์œผ๋ฉด ๋ฐ”๋กœ ๊ฑฐ๋ถ€ํ•˜์ง€ ์•Š๊ณ , ํŒŒ์ผ ๊ฒฝ๊ณ„๋กœ ๋‚˜๋ˆˆ ์ตœ๋Œ€ 8๊ฐœ์˜ ์™„์ „ํ•œ ๋ฐฐ์น˜๋กœ ๊ฒ€ํ† ํ•ฉ๋‹ˆ๋‹ค. ์›Œํฌํ”Œ๋กœยท๋ฆฌ๋ทฐ ์Šคํฌ๋ฆฝํŠธยทTerraform/IAMยทagentยทAgentCoreยท์‹œํฌ๋ฆฟ ๊ต์ฒดยทEKSยท์ธ์‹œ๋˜ํŠธยทAPI ๋ผ์šฐํŠธยทAWS ํด๋ผ์ด์–ธํŠธ ํŒŒ์ผ๊ณผ, ๊ฒฝ๋กœ ๊ตฌ๊ฐ„ ์ด๋ฆ„์ด ์ธ์ฆยท์‹œํฌ๋ฆฟยท์ž๊ฒฉ ์ฆ๋ช…ยท์—ญํ•  ์ „ํ™˜ยท๋ณ€๊ฒฝยทํ—ˆ์šฉ ๋ชฉ๋ก์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ํŒŒ์ผ์€ ์ฒซ ๋ฐฐ์น˜์—์„œ ํ•จ๊ป˜ ๊ฒ€ํ† ํ•˜๊ณ , ๊ฐ ๋ฐฐ์น˜๋Š” ๋‹ค๋ฅธ ๋ฐฐ์น˜์—์„œ ๋ฐ”๋€ ๊ฒฝ๋กœ ๋ชฉ๋ก์„ ๋ฐ์ดํ„ฐ๋กœ ๋ฐ›์•„ ์–ด๋А ๊ฒฝ๋กœ๋„ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š” ์˜์กด์„ฑ์€ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ๋ฐฐ์น˜๋Š” ๊ฐ™์€ ์ž…๋ ฅ ๊ฒ€์‚ฌ๋ฅผ ๊ฑฐ์ณ ๋‘ ๋…๋ฆฝ ๋ฆฌ๋ทฐ์–ด์™€ ์ž์ฒด chair๊ฐ€ ๋ณ‘๋ ฌ๋กœ ๊ฒ€ํ† ํ•˜๋ฉฐ, ๋ชจ๋“  ๋ฐฐ์น˜๊ฐ€ ํ†ต๊ณผํ•ด์•ผ PR์ด ํ†ต๊ณผํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„ ๋ฐฐ์น˜๊ฐ€ ์•ž์„  ๋ฐฐ์น˜์˜ ๊ฒ€ํ†  ๋ฒ”์œ„ยท๋ณด๊ณ ์„œ ์‹คํŒจ๋ฅผ ์ง€์šฐ์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ํŒŒ์ผ ํ•˜๋‚˜๊ฐ€ ๋ฐฐ์น˜ ํ•œ๋„๋ฅผ ๋„˜๊ฑฐ๋‚˜ 8๊ฐœ๋ฅผ ๋„˜๋Š” ๋ฐฐ์น˜๊ฐ€ ํ•„์š”ํ•˜๋ฉด ๋ชจ๋ธ ํ˜ธ์ถœ ์ „์— ๊ฑฐ๋ถ€ํ•˜๊ณ , ํ•œ๋„ ์•ˆ์˜ diff๋Š” ๊ธฐ์กด ๋‹จ์ผ ๊ฒ€ํ†  ๊ฒฝ๋กœ๋ฅผ ๊ทธ๋Œ€๋กœ ์”๋‹ˆ๋‹ค.

### ์ˆ˜์ •

Expand Down
5 changes: 3 additions & 2 deletions docs/runbooks/AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- generated-by: co-agent ยท source: CLAUDE.md ยท claude-md-sha: 09cdc810253a ยท generated-at: 2026-11-05 ยท DO NOT EDIT โ€” edit CLAUDE.md then run /co-agent sync-context -->
<!-- generated-by: co-agent ยท source: CLAUDE.md ยท claude-md-sha: dc59dfd5a344 ยท generated-at: 2026-11-05 ยท DO NOT EDIT โ€” edit CLAUDE.md then run /co-agent sync-context -->

> You are an external reviewer for this repo โ€” project context below, distilled from CLAUDE.md. This file is shared verbatim by the external review panel (not a per-AI copy).

Expand All @@ -24,7 +24,8 @@ removed; flag any change that reintroduces a v1 procedure.
`connector-target-sync.md` covers chat connector target registration (`connector_target_sync_enabled`), the ADR-005 owner-override exception: scope, one-stack-per-account caveat, enable/verify, reason codes and that disabling leaves already-written targets.

`pr-review-head-images.md` defines two comprehensive reviewer reports, complete diff
admission (6,000 lines/128 KiB), bounded chair input and distinct incomplete-review
admission (6,000 lines/128 KiB per call; larger diffs in at most 8 complete batches that must
all pass), bounded chair input and distinct incomplete-review
diagnostics, alongside staged HEAD image evidence and historical BASE context.

## Deployment review checks
Expand Down
Loading
Loading