Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
43c4002
fix(noema): preserve long-running substantive reviews
seonghobae Aug 31, 2026
8084b2a
test(noema): cover unbounded provider calls
seonghobae Aug 31, 2026
6955bab
docs(adr): prohibit fixed model inference timeouts
seonghobae Aug 31, 2026
e19447f
fix(review): remove fixed orchestration deadlines
seonghobae Aug 31, 2026
1b9ed49
fix(noema): truncate diffs at complete lines
seonghobae Aug 31, 2026
6344fe3
test(review): refresh dispatch blob pin
seonghobae Aug 31, 2026
958e8e5
fix(noema): isolate standalone review concurrency
seonghobae Aug 31, 2026
8b32373
fix(review): keep Noema independent and preserve diff locations
seonghobae Aug 31, 2026
0fb80aa
fix(noema): bind reviews to requested head
seonghobae Aug 31, 2026
c82fe5f
fix(noema): compare expected heads case-insensitively
seonghobae Aug 31, 2026
c724864
test(noema): guard case-insensitive workflow head checks
seonghobae Aug 31, 2026
c4fb9c1
fix(review): fail closed on stalled review evidence
seonghobae Aug 31, 2026
b6c7532
fix(review): remove elapsed-time cutoffs
seonghobae Aug 31, 2026
63aaf4b
fix(review): bound sidecar health probes
seonghobae Aug 31, 2026
55da0a2
fix(review): keep health polling unbounded
seonghobae Sep 1, 2026
4555462
merge(review): keep verdict polling unbounded
seonghobae Sep 1, 2026
3462ccd
test(opencode): accept live head advances safely
seonghobae Sep 1, 2026
8a01a66
Merge remote-tracking branch 'origin/main' into fix/noema-exact-locat…
seonghobae Sep 1, 2026
6ee78b8
fix(review): bind long-running reviews to exact head
seonghobae Sep 1, 2026
739f9c6
fix(autofix): retire superseded head workers
seonghobae Sep 1, 2026
014bf3b
test(review): refresh dispatch workflow pin
seonghobae Sep 1, 2026
c496f86
fix(strix): cancel superseded heads outside scan queue
seonghobae Sep 1, 2026
a23c7cc
fix(noema): preserve active same-head review
seonghobae Sep 1, 2026
2bdb519
fix(autofix): inspect every active worker page
seonghobae Sep 1, 2026
9ee4f1b
test(autofix): cover active worker on later page
seonghobae Sep 1, 2026
c0603e6
test(autofix): isolate active-run inventory boundary
seonghobae Sep 1, 2026
ed33e00
test(strix): align cleanup queue contract
seonghobae Sep 1, 2026
5344daa
Merge remote-tracking branch 'origin/main' into fix/noema-exact-locat…
seonghobae Sep 1, 2026
495373f
fix(autofix): revalidate head before mutation
seonghobae Sep 1, 2026
c86911a
test(autofix): isolate live head validation
seonghobae Sep 1, 2026
fbd3e2b
test(sidecar): enforce unbounded discovery and health waits
seonghobae Sep 1, 2026
bf34e70
Merge remote-tracking branch 'origin/main' into fix/noema-exact-locat…
seonghobae Sep 1, 2026
c8fbd17
Merge remote-tracking branch 'origin/main' into fix/noema-exact-locat…
seonghobae Sep 1, 2026
168a9ae
fix(review): preserve exact-head agent lifecycle
seonghobae Sep 1, 2026
6a27b31
Merge remote-tracking branch 'origin/main' into fix/reconcile-noema-u…
seonghobae Sep 1, 2026
914974c
test(noema): follow exact-head variable rename
seonghobae Sep 1, 2026
f86fd13
test(autofix): isolate active run inventory
seonghobae Sep 1, 2026
900d9f9
fix(review): revalidate live PR before mutations
seonghobae Sep 1, 2026
29be8c9
test(strix): prove live-head cleanup safety
seonghobae Sep 1, 2026
36c6f3a
fix(review): skip redundant scheduler wakes
seonghobae Sep 1, 2026
69d5b42
fix(strix): permit private PR revalidation
seonghobae Sep 1, 2026
8ce0fb4
test(review): avoid Linux fixture SIGPIPE
seonghobae Sep 1, 2026
db1aded
fix(review): preserve fallback review dispatch
seonghobae Sep 1, 2026
5948fa0
Merge remote-tracking branch 'origin/fix/reconcile-noema-unbounded-ex…
seonghobae Sep 1, 2026
0c1e8b1
fix(review): parse paginated review receipts
seonghobae Sep 1, 2026
21864e4
Merge concurrent review receipt fixes
seonghobae Sep 1, 2026
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
62 changes: 34 additions & 28 deletions .github/workflows/noema-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,13 @@ run-name: >-
Required Noema Review ${{ github.event.client_payload.target_repository ||
github.event.pull_request.base.repo.full_name || github.repository }}#${{
github.event.client_payload.pr_number || github.event.pull_request.number ||
github.event.workflow_run.pull_requests[0].number || 'event' }}@${{
'event' }}@${{
github.event.client_payload.pr_head_sha || github.event.pull_request.head.sha ||
github.event.workflow_run.pull_requests[0].head.sha || github.sha }}
github.sha }}

on:
pull_request_target:
types: [opened, synchronize, reopened, ready_for_review, closed]
workflow_run:
workflows: ["Required OpenCode Review", "Strix Security Scan"]
types: [completed]
# Default-branch-only retry entrypoint; no caller-selected workflow ref.
repository_dispatch:
types: [noema-review]
Expand All @@ -22,18 +19,12 @@ concurrency:
noema-review-${{
github.event.pull_request.base.repo.full_name ||
github.event.client_payload.target_repository || github.repository }}-${{
github.event.pull_request.number || github.event.workflow_run.pull_requests[0].number ||
github.event.pull_request.number ||
github.event.client_payload.pr_number ||
github.run_id }}-${{
github.event.client_payload.pr_head_sha || github.event.pull_request.head.sha ||
github.event.workflow_run.pull_requests[0].head.sha || github.sha }}-${{
github.event_name == 'workflow_run' &&
github.event.workflow_run.conclusion == 'cancelled' &&
format('cancelled-{0}', github.run_id) ||
'actionable' }}
# A cancelled upstream review emits a workflow_run event whose Noema job is
# skipped. It must not cancel a live same-head Noema review before skipping.
cancel-in-progress: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion != 'cancelled' }}
github.run_id }}
cancel-in-progress: >-
${{ github.event_name == 'pull_request_target' &&
(github.event.action == 'synchronize' || github.event.action == 'closed') }}

permissions:
contents: read
Expand Down Expand Up @@ -191,10 +182,6 @@ jobs:
runs-on: ubuntu-latest
if: >-
github.event_name == 'repository_dispatch'
|| (
github.event_name == 'workflow_run'
&& github.event.workflow_run.conclusion != 'cancelled'
)
|| (
github.event_name == 'pull_request_target'
&& github.event.action != 'closed'
Expand All @@ -209,8 +196,8 @@ jobs:
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
TARGET_REPOSITORY: ${{ github.event.pull_request.base.repo.full_name || github.event.client_payload.target_repository || github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number || github.event.workflow_run.pull_requests[0].number || github.event.client_payload.pr_number || '' }}
EXPECTED_HEAD: ${{ github.event.client_payload.pr_head_sha || github.event.pull_request.head.sha || github.event.workflow_run.pull_requests[0].head.sha || '' }}
PR_NUMBER: ${{ github.event.pull_request.number || github.event.client_payload.pr_number || '' }}
EXPECTED_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.event.client_payload.pr_head_sha || '' }}
Comment thread
seonghobae marked this conversation as resolved.
steps:
- name: Skip events without pull request context
if: env.PR_NUMBER == ''
Expand Down Expand Up @@ -292,13 +279,13 @@ jobs:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
if [[ ! "$EXPECTED_HEAD" =~ ^[0-9a-f]{40}$ ]]; then
if [[ ! "$EXPECTED_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]]; then
echo "::error::Noema trigger did not provide a canonical lowercase exact head SHA."
exit 1
fi
live_head="$(gh api "repos/${TARGET_REPOSITORY}/pulls/${PR_NUMBER}" --jq '.head.sha')"
if [ "${live_head,,}" != "${EXPECTED_HEAD,,}" ]; then
echo "::error::Noema trigger is stale; expected ${EXPECTED_HEAD}, observed ${live_head}."
if [ "${live_head,,}" != "${EXPECTED_HEAD_SHA,,}" ]; then
echo "::error::Noema trigger is stale; expected ${EXPECTED_HEAD_SHA}, observed ${live_head}."
exit 1
fi

Expand Down Expand Up @@ -332,7 +319,7 @@ jobs:
# current run even when its display_title never rendered a
# matching "@$head" suffix to exclude by.
if ! run_ids="$(jq -r --arg pr "$PR_NUMBER" --argjson current "$CURRENT_RUN_ID" \
--arg target "$TARGET_REPOSITORY" --arg head "$EXPECTED_HEAD" '
--arg target "$TARGET_REPOSITORY" --arg head "$EXPECTED_HEAD_SHA" '
.workflow_runs[]
| select(.id < $current)
| select(.path == ".github/workflows/noema-review.yml")
Expand Down Expand Up @@ -364,7 +351,7 @@ jobs:
sed 's/^/ /' /tmp/noema-supersede-live-head-error >&2 || true
exit 0
fi
if [ "${live_head,,}" != "${EXPECTED_HEAD,,}" ]; then
if [ "${live_head,,}" != "${EXPECTED_HEAD_SHA,,}" ]; then
echo "::notice::Noema cleanup stopped because the PR head advanced."
exit 0
fi
Expand Down Expand Up @@ -495,6 +482,25 @@ jobs:
echo "::add-mask::$app_token"
echo "token=$app_token" >>"$GITHUB_OUTPUT"

- name: Validate current pull request head
if: env.PR_NUMBER != ''
env:
GH_TOKEN: ${{ secrets.NOEMA_REVIEW_TOKEN || steps.noema_github_app_token.outputs.token || steps.noema_oidc_token.outputs.token }}
run: |
set -euo pipefail
if ! [[ "$EXPECTED_HEAD_SHA" =~ ^[0-9a-fA-F]{40}$ ]]; then
echo "::error::Noema expected head must be a full commit SHA."
exit 1
fi
pull_request_json="$(gh api "repos/${TARGET_REPOSITORY}/pulls/${PR_NUMBER}")"
live_state="$(jq -r '.state // empty' <<<"$pull_request_json")"
live_head_sha="$(jq -r '.head.sha // empty' <<<"$pull_request_json")"
if [ "$live_state" != "open" ] || [ "${live_head_sha,,}" != "${EXPECTED_HEAD_SHA,,}" ]; then
printf '::error::Noema review target is closed or stale. expected head=%s; live state=%s head=%s.\n' \
"$EXPECTED_HEAD_SHA" "${live_state:-missing}" "${live_head_sha:-missing}"
exit 1
fi

- name: Resolve Noema target repository visibility
if: env.PR_NUMBER != ''
id: target_visibility
Expand Down Expand Up @@ -575,4 +581,4 @@ jobs:
python3 -m scripts.ci.noema_review_gate \
--repo "$TARGET_REPOSITORY" \
--pr-number "$PR_NUMBER" \
--expected-head "$EXPECTED_HEAD"
--expected-head "$EXPECTED_HEAD_SHA"
38 changes: 2 additions & 36 deletions .github/workflows/opencode-review-dispatch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2312,7 +2312,6 @@ jobs:
# 36-minute publication gate, the 18-minute Noema handoff, and setup/cleanup
# overhead without truncating a late current-head verdict, handoff, merge
# scheduler follow-up, or bounded failure reason.
timeout-minutes: 305
permissions:
actions: write
checks: read
Expand Down Expand Up @@ -3993,7 +3992,6 @@ jobs:
- name: Run OpenCode PR Review model pool
id: opencode_review_model_pool
if: needs.coverage-evidence.result == 'success'
timeout-minutes: 205
continue-on-error: true
env:
SHARE: "false"
Expand All @@ -4004,14 +4002,7 @@ jobs:
# the SAME model 5x let a rate-limited/hung leader consume the whole
# step, so the pool never reached a healthy fallback model.
OPENCODE_MODEL_ATTEMPTS: "1"
# Preserve reviews that legitimately need tens of minutes to inspect a
# large repository. Changed-file count is not a repository-complexity
# proxy. Let Contextual Orchestrator use the existing total review
# budget; the bounded provider-pool watchdog remains the outer guard.
OPENCODE_RUN_TIMEOUT_SECONDS: "11700"
OPENCODE_EXPORT_TIMEOUT_SECONDS: "180"
OPENCODE_TOTAL_RETRY_BUDGET_SECONDS: "11700"
OPENCODE_POOL_STEP_TIMEOUT_SECONDS: "12000"
# A second pass through the same provider catalog repeats the same
# quota/format failures and can occupy the required check for hours.
# Exhaust each distinct candidate once, then publish the bounded
Expand All @@ -4020,23 +4011,10 @@ jobs:
OPENCODE_DYNAMIC_REVIEW_CADENCE: "true"
OPENCODE_SMALL_CHANGE_FILE_THRESHOLD: "3"
OPENCODE_MEDIUM_CHANGE_FILE_THRESHOLD: "20"
OPENCODE_SMALL_CHANGE_RUN_TIMEOUT_SECONDS: "11700"
OPENCODE_SMALL_CHANGE_TOTAL_BUDGET_SECONDS: "11700"
OPENCODE_MEDIUM_CHANGE_RUN_TIMEOUT_SECONDS: "11700"
OPENCODE_MEDIUM_CHANGE_TOTAL_BUDGET_SECONDS: "11700"
OPENCODE_LARGE_CHANGE_RUN_TIMEOUT_SECONDS: "11700"
OPENCODE_LARGE_CHANGE_TOTAL_BUDGET_SECONDS: "11700"
OPENCODE_UNKNOWN_CHANGE_RUN_TIMEOUT_SECONDS: "11700"
OPENCODE_UNKNOWN_CHANGE_TOTAL_BUDGET_SECONDS: "11700"
OPENCODE_DYNAMIC_RUN_TIMEOUT_CAP_SECONDS: "11700"
OPENCODE_DYNAMIC_TOTAL_BUDGET_CAP_SECONDS: "11700"
OPENCODE_DYNAMIC_MAX_CYCLES_CAP: "1"
OPENCODE_FREE_RUN_TIMEOUT_SECONDS: "3600"
OPENCODE_DYNAMIC_MAX_CYCLES: "1"
CENTRAL_REVIEW_PROCESS_FALLBACK_ELIGIBLE: ${{ steps.central_review_process_fallback_scope.outputs.eligible || 'false' }}
CENTRAL_REVIEW_PROCESS_FALLBACK_SCOPE_LABEL: ${{ steps.central_review_process_fallback_scope.outputs.scope_label || 'unsupported' }}
OPENCODE_CENTRAL_REVIEW_PROCESS_FALLBACK_RUN_TIMEOUT_SECONDS: "11700"
OPENCODE_CENTRAL_REVIEW_PROCESS_FALLBACK_TOTAL_BUDGET_SECONDS: "11700"
OPENCODE_CENTRAL_REVIEW_PROCESS_FALLBACK_MAX_CYCLES: "1"
OPENCODE_BACKOFF_INITIAL_SECONDS: "30"
OPENCODE_BACKOFF_MAX_SECONDS: "30"
Expand All @@ -4059,18 +4037,9 @@ jobs:
set -euo pipefail
source "$GITHUB_WORKSPACE/scripts/ci/load_contextual_orchestrator_token.sh"
set +e
timeout --kill-after=30s "${OPENCODE_POOL_STEP_TIMEOUT_SECONDS:-3600}s" \
bash "$GITHUB_WORKSPACE/scripts/ci/run_opencode_review_model_pool.sh"
bash "$GITHUB_WORKSPACE/scripts/ci/run_opencode_review_model_pool.sh"
pool_status=$?
set -e
if [ "$pool_status" -eq 124 ] || [ "$pool_status" -eq 137 ] || [ "$pool_status" -eq 143 ]; then
printf 'OpenCode model pool exceeded the outer %ss step budget; marking the pool exhausted so current-head evidence fallback can publish a bounded reason instead of blocking the org queue.\n' \
"${OPENCODE_POOL_STEP_TIMEOUT_SECONDS:-3600}"
{
printf 'review_model=\n'
printf 'review_status=exhausted\n'
} >>"$GITHUB_OUTPUT"
fi
exit "$pool_status"

- name: Exchange OpenCode app token for review writes
Expand Down Expand Up @@ -4623,7 +4592,6 @@ jobs:
# The approval gate normally waits about six minutes, with bounded
# extensions for image validation or package/GPU builds plus API and
# publication overhead.
timeout-minutes: 36
env:
GH_TOKEN: ${{ steps.opencode_app_token.outputs.token || secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || github.token }}
CHECK_LOOKUP_GH_TOKEN: ${{ github.token }}
Expand Down Expand Up @@ -4678,7 +4646,6 @@ jobs:
# failed-check diagnosis in this publish step is a short best-effort
# augmentation; current-head logs/SARIF remain the authoritative
# reason source when the augmentation is unavailable.
OPENCODE_RUN_TIMEOUT_SECONDS: "120"
OPENCODE_EXPORT_TIMEOUT_SECONDS: "60"
run: |
set -euo pipefail
Expand Down Expand Up @@ -6032,8 +5999,7 @@ jobs:
} >"$prompt_file"

cd "$OPENCODE_REVIEW_WORKDIR"
if ! timeout --kill-after=30s "${OPENCODE_RUN_TIMEOUT_SECONDS:-120}s" \
env -u GH_TOKEN -u GITHUB_TOKEN -u OPENCODE_APP_TOKEN \
if ! env -u GH_TOKEN -u GITHUB_TOKEN -u OPENCODE_APP_TOKEN \
-u ACTIONS_ID_TOKEN_REQUEST_TOKEN -u ACTIONS_ID_TOKEN_REQUEST_URL \
opencode run "$(cat "$prompt_file")" \
--pure \
Expand Down
Loading
Loading