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
6 changes: 2 additions & 4 deletions .github/workflows/agent-mention-router.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ jobs:

- name: Route trusted local agent mention
run: >-
python3 -u scripts/ci/agent_mention_router.py
python3 scripts/ci/agent_mention_router.py
--event-path "${RUNNER_TEMP}/agent-mention-event.json"

sweep-organization-agent-mentions:
Expand All @@ -83,7 +83,6 @@ jobs:
OPENCODE_REPOSITORY_DISPATCH_TARGETS: ${{ vars.OPENCODE_REPOSITORY_DISPATCH_TARGETS }}
LOOKBACK_HOURS: ${{ vars.AGENT_MENTION_LOOKBACK_HOURS || '168' }}
MAX_DISPATCHES: ${{ vars.AGENT_MENTION_MAX_DISPATCHES || '20' }}
TIME_BUDGET_SECONDS: ${{ vars.AGENT_MENTION_TIME_BUDGET_SECONDS || '480' }}
DRY_RUN: "false"
steps:
- name: Exchange OpenCode app token for sibling-repository comments
Expand Down Expand Up @@ -181,9 +180,8 @@ jobs:
--repository-source "$TARGET_REPOSITORY_SOURCE"
--lookback-hours "$LOOKBACK_HOURS"
--max-dispatches "$MAX_DISPATCHES"
--time-budget-seconds "$TIME_BUDGET_SECONDS"
)
if [ "$DRY_RUN" = "true" ]; then
args+=(--dry-run)
fi
python3 -u scripts/ci/agent_mention_sweep.py "${args[@]}"
python3 scripts/ci/agent_mention_sweep.py "${args[@]}"
51 changes: 22 additions & 29 deletions .github/workflows/opencode-review-dispatch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,6 @@ jobs:
&& rm -rf /var/lib/apt/lists/*
ENV LLVM_COV=/usr/bin/llvm-cov-19
ENV LLVM_PROFDATA=/usr/bin/llvm-profdata-19
ENV COREPACK_HOME=/opt/corepack
RUN test -x "$LLVM_COV"
RUN test -x "$LLVM_PROFDATA"
RUN curl --proto '=https' --tlsv1.2 -fsSLo /tmp/node-linux-x64.tar.xz \
Expand All @@ -669,17 +668,25 @@ jobs:
&& tar --no-same-owner -xJf /tmp/node-linux-x64.tar.xz -C /usr/local --strip-components=1 \
&& test "$(/usr/local/bin/node --version)" = "v24.18.0" \
&& /usr/local/bin/npm --version >/dev/null \
&& corepack --version >/dev/null \
&& rm -f /tmp/node-linux-x64.tar.xz
RUN curl --proto '=https' --tlsv1.2 -fsSLo /tmp/cargo-llvm-cov.tar.gz \
https://github.com/taiki-e/cargo-llvm-cov/releases/download/v0.8.7/cargo-llvm-cov-x86_64-unknown-linux-musl.tar.gz \
&& echo '967b5cc996c29d8baa52bbb4595ef1f53af35255af8e2036ddbc6468d7b523c7 /tmp/cargo-llvm-cov.tar.gz' | sha256sum -c - \
&& tar -xzf /tmp/cargo-llvm-cov.tar.gz -C /usr/local/bin cargo-llvm-cov \
&& chmod 0755 /usr/local/bin/cargo-llvm-cov \
&& rm -f /tmp/cargo-llvm-cov.tar.gz
RUN curl --proto '=https' --tlsv1.2 -fsSLo /tmp/pnpm.tgz \
https://registry.npmjs.org/pnpm/-/pnpm-11.5.3.tgz \
&& echo '7ac1c919341c213a34dc0d02afb7143c5c26ac26ee8c4782deea821b8ac64d2134a081fd8941dae6e29bbb48f58dfc2b7fbceeccc07cb2f09d219d342a4969ed /tmp/pnpm.tgz' | sha512sum -c - \
&& mkdir -p /opt/pnpm \
&& tar --no-same-owner -xzf /tmp/pnpm.tgz -C /opt/pnpm --strip-components=1 \
&& chmod 0755 /opt/pnpm/bin/pnpm.cjs \
&& ln -s /opt/pnpm/bin/pnpm.cjs /usr/local/bin/pnpm \
&& test "$(/usr/local/bin/pnpm --version)" = "11.5.3" \
&& rm -f /tmp/pnpm.tgz
COPY base-javascript-packages /tmp/base-javascript-packages
RUN set -eu; \
mkdir -p /opt/corepack /opt/javascript-package-locks /opt/npm-cache /opt/pnpm-store; \
mkdir -p /opt/javascript-package-locks /opt/npm-cache /opt/pnpm-store; \
install -m 0444 /tmp/base-javascript-packages/manifest.json \
/opt/javascript-package-locks/manifest.json; \
jq -r '.[] | [.directory, .package_manager] | @tsv' \
Expand All @@ -696,8 +703,8 @@ jobs:
--no-fund; \
rm -rf node_modules; \
;; \
pnpm@*) \
corepack pnpm fetch \
pnpm@11.5.3) \
pnpm fetch \
--frozen-lockfile \
--ignore-scripts \
--store-dir /opt/pnpm-store; \
Expand All @@ -709,7 +716,7 @@ jobs:
esac; \
done; \
npm cache verify --cache /opt/npm-cache; \
chmod -R a+rX /opt/corepack /opt/npm-cache /opt/pnpm-store; \
chmod -R a+rX /opt/npm-cache /opt/pnpm-store; \
rm -rf /tmp/base-javascript-packages
COPY requirements-opencode-review-ci-hashes.txt /tmp/requirements-opencode-review-ci-hashes.txt
RUN python3 -m pip install \
Expand Down Expand Up @@ -1256,9 +1263,6 @@ jobs:
printf 'Coverage package runner %s requires an exact packageManager version (for example %s@1.2.3); mutable or missing specifications are refused.\n' "$runner" "$runner" >&2
return 1
fi
if [ "$runner" = "pnpm" ] && command -v corepack >/dev/null 2>&1; then
return 0
fi
if command -v "$runner" >/dev/null 2>&1; then
return 0
fi
Expand Down Expand Up @@ -1299,17 +1303,6 @@ jobs:
fi
}

run_package_script_and_capture() {
local label="$1"
local package_runner="$2"
local script="$3"
case "$package_runner" in
npm) run_and_capture "$label" npm run "$script" ;;
pnpm) run_and_capture "$label" corepack pnpm run "$script" ;;
yarn) run_and_capture "$label" yarn run "$script" ;;
esac
}

run_python_docstring_coverage() {
local measured_projects=0
while IFS= read -r project_dir; do
Expand Down Expand Up @@ -1515,7 +1508,7 @@ jobs:
trusted_pnpm_lock_matches_base
prepare_writable_pnpm_store
run_and_capture "JavaScript/TypeScript dependencies (pnpm offline install, lifecycle hooks disabled)" \
corepack pnpm install \
pnpm install \
--offline \
--frozen-lockfile \
--trust-lockfile \
Expand Down Expand Up @@ -1625,9 +1618,9 @@ jobs:
;;
pnpm)
if [ -n "$package_name" ] && [ -f pnpm-workspace.yaml ]; then
run_and_capture "Tauri frontendDist build (${package_dir})" corepack pnpm --filter "$package_name" run build
run_and_capture "Tauri frontendDist build (${package_dir})" pnpm --filter "$package_name" run build
else
run_and_capture "Tauri frontendDist build (${package_dir})" bash -c 'cd "$1" && corepack pnpm run build' bash "$package_dir"
run_and_capture "Tauri frontendDist build (${package_dir})" bash -c 'cd "$1" && pnpm run build' bash "$package_dir"
fi
;;
yarn)
Expand Down Expand Up @@ -2004,11 +1997,11 @@ jobs:
fi

if [ -n "$package_runner" ] && jq -e '.scripts["check:python-docstrings"] // empty' package.json >/dev/null; then
run_package_script_and_capture "Repository docstring coverage" "$package_runner" check:python-docstrings
run_and_capture "Repository docstring coverage" "$package_runner" run check:python-docstrings
elif [ -n "$package_runner" ] && jq -e '.scripts["docstring:coverage"] // empty' package.json >/dev/null; then
run_package_script_and_capture "JavaScript/TypeScript docstring coverage" "$package_runner" docstring:coverage
run_and_capture "JavaScript/TypeScript docstring coverage" "$package_runner" run docstring:coverage
elif [ -n "$package_runner" ] && jq -e '.scripts["docs:coverage"] // empty' package.json >/dev/null; then
run_package_script_and_capture "JavaScript/TypeScript docstring coverage" "$package_runner" docs:coverage
run_and_capture "JavaScript/TypeScript docstring coverage" "$package_runner" run docs:coverage
else
append "### JavaScript/TypeScript docstring coverage"
append ""
Expand All @@ -2020,19 +2013,19 @@ jobs:
if [ -z "$package_runner" ]; then
:
elif jq -e '.scripts.coverage // empty' package.json >/dev/null; then
run_package_script_and_capture "JavaScript/TypeScript coverage script" "$package_runner" coverage
run_and_capture "JavaScript/TypeScript coverage script" "$package_runner" run coverage
javascript_coverage_ran=1
elif jq -e '.scripts.test // empty' package.json >/dev/null; then
if javascript_test_script_collects_coverage; then
case "$package_runner" in
npm) run_and_capture "JavaScript/TypeScript test coverage" npm test ;;
pnpm) run_and_capture "JavaScript/TypeScript test coverage" corepack pnpm test ;;
pnpm) run_and_capture "JavaScript/TypeScript test coverage" pnpm test ;;
yarn) run_and_capture "JavaScript/TypeScript test coverage" yarn test ;;
esac
else
case "$package_runner" in
npm) run_and_capture "JavaScript/TypeScript test coverage" npm test -- --coverage ;;
pnpm) run_and_capture "JavaScript/TypeScript test coverage" corepack pnpm run test --coverage ;;
pnpm) run_and_capture "JavaScript/TypeScript test coverage" pnpm run test --coverage ;;
yarn) run_and_capture "JavaScript/TypeScript test coverage" yarn test --coverage ;;
esac
fi
Expand Down
117 changes: 11 additions & 106 deletions .github/workflows/pr-review-merge-scheduler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -617,17 +617,11 @@ jobs:
# order every tick (the org repos API response order), so the same early
# repositories always exhaust the shared budget and every later repository
# starves indefinitely even with zero-open-thread, all-green PRs
# (ContextualWisdomLab/.github#1219). Left unset here so the sweep step
# below derives it from a persistent per-execution counter (or, as a
# fallback, wall-clock time) instead of `github.run_number`: run_number
# increments on every trigger of this workflow (push,
# pull_request_target, pull_request_review, workflow_run), not only the
# sweep schedule, so it cannot give the "bounded by repository_count
# ticks" guarantee a rotation is meant to provide. Wall-clock time alone
# is also insufficient, since this single-flight/non-cancelling job can
# run up to 60 minutes and a delayed real execution can let more than
# one 900s window elapse, occasionally repeating a modulo offset
# (ContextualWisdomLab/.github#1223 review finding).
# (ContextualWisdomLab/.github#1219). `github.run_number` increments on
# every run of this workflow, so rotating the walk order by it spreads the
# same fixed total budget across repositories over successive ticks instead
# of raising it.
ORG_SWEEP_ROTATION_INDEX: ${{ github.run_number }}
# A repository the sweep credential structurally cannot read (the OpenCode
# app is not installed there / the PR_REVIEW_MERGE_TOKEN lacks it) returns
# HTTP 403 "Resource not accessible by integration". That is an access-grant
Expand Down Expand Up @@ -832,95 +826,8 @@ jobs:
echo "::error::ORG_SWEEP_BRANCH_UPDATE_LIMIT must be -1 or a non-negative integer; got '${ORG_SWEEP_BRANCH_UPDATE_LIMIT}'. Fix the ORG_SWEEP_BRANCH_UPDATE_LIMIT repository variable."
exit 1
fi
# Unset in production (see the env-block comment above). Primary
# source: a persistent `ORG_SWEEP_ROTATION_COUNTER` repository
# variable on this (.github) repository, incremented by exactly
# one at the start of every actual org-queue-sweep execution. A
# wall-clock tick (one per 900s) is *not* sufficient on its own:
# this job is single-flight/non-cancelling with up to a 60-minute
# timeout, so a delayed or backlogged execution can let more than
# one 900s window elapse between two real sweep runs, and if that
# gap happens to be an exact multiple of the repository count the
# modulo offset repeats -- reintroducing the exact starvation
# #1220 fixed (CodeRabbit review finding on #1223). A persistent
# per-execution counter advances by exactly one every time the
# sweep body actually runs, regardless of how much wall-clock time
# a slow prior run consumed. Falls back to the wall-clock tick,
# which still strictly improves on the pre-#1220 fixed order, only
# if the counter read/write itself is unavailable (permissions,
# transient API failure) -- a fairness mechanism must never fail
# the sweep's much more important review-dispatch/merge work.
# Tests inject ORG_SWEEP_ROTATION_INDEX directly for determinism,
# which this only fills in when absent.
#
# Two known, accepted limitations of this counter (Devin review on
# #1223), neither of which is fixed here:
# - Read-modify-write is not atomic. A schedule-triggered run and a
# manual `repository_dispatch` org_sweep run use different
# concurrency groups and can therefore execute concurrently, in
# which case both could read the same counter value and pick the
# same rotation offset for that one pair of runs. The REST
# Variables API has no compare-and-swap primitive to close this
# without a broader concurrency-group redesign shared across
# every trigger type this workflow serves; the consequence is
# bounded and self-correcting (one occasionally-repeated offset,
# not a stuck one), so it is accepted rather than redesigned.
# - Whether the PATCH/POST below ever succeeds in production
# depends on the resolved token actually holding repository
# Variables-write scope, which is not independently verifiable
# from inside this workflow. If it does not, every run silently
# but safely degrades to the wall-clock fallback below (logged
# via ::warning:: each time), which is still strictly better
# than the pre-#1220 fixed order -- never a hard failure, and
# observable in the run log for whoever holds that token.
if [ -z "${ORG_SWEEP_ROTATION_INDEX:-}" ]; then
counter_variable_name="ORG_SWEEP_ROTATION_COUNTER"
# Distinguish a *successful* read (the variable exists; its
# value, valid or not, is authoritative) from a *failed* read
# (transient error, permissions, or the variable genuinely
# doesn't exist yet -- indistinguishable from here). Only a
# successful read may PATCH: a transient failure that silently
# became "treat as 0" would let the PATCH below clobber an
# already-accumulated counter value back down to 1, restarting
# the rotation sequence instead of degrading to the wall-clock
# fallback the design intends (Devin review finding on #1223).
if counter_current="$(
gh api "repos/${GITHUB_REPOSITORY}/actions/variables/${counter_variable_name}" \
--jq '.value' 2>/dev/null
)"; then
if ! [[ "$counter_current" =~ ^[0-9]+$ ]]; then
counter_current=0
fi
# Force base-10: a manually-seeded value with a leading zero
# (e.g. "08") passes the digit-only check above but bash's
# unprefixed arithmetic parses a leading-zero literal as
# octal, and "08"/"09" are not valid octal digits -- errors
# under set -e. $((10#...)) is the same guard already used
# elsewhere in this file (STALE_OPENCODE_MINUTES).
counter_next=$(( 10#$counter_current + 1 ))
if gh api "repos/${GITHUB_REPOSITORY}/actions/variables/${counter_variable_name}" \
-X PATCH -f "value=${counter_next}" >/dev/null 2>&1; then
ORG_SWEEP_ROTATION_INDEX="$counter_next"
else
echo "::warning::read ${counter_variable_name}=${counter_current} but could not PATCH it; falling back to a wall-clock rotation tick for this run only"
ORG_SWEEP_ROTATION_INDEX=$(( $(date -u +%s) / 900 ))
fi
elif gh api "repos/${GITHUB_REPOSITORY}/actions/variables" \
-X POST -f "name=${counter_variable_name}" -f "value=1" >/dev/null 2>&1; then
# The read failed, so this is only safe as a first-run
# create: POST fails on its own if the variable actually
# already exists (a real read outage rather than a genuinely
# missing variable), which correctly falls through to the
# wall-clock branch below instead of resetting a value this
# run could not see.
ORG_SWEEP_ROTATION_INDEX=1
else
echo "::warning::could not read/write ${counter_variable_name}; falling back to a wall-clock rotation tick for this run only"
ORG_SWEEP_ROTATION_INDEX=$(( $(date -u +%s) / 900 ))
fi
fi
if ! [[ "$ORG_SWEEP_ROTATION_INDEX" =~ ^[0-9]+$ ]]; then
echo "::error::ORG_SWEEP_ROTATION_INDEX must be a non-negative integer; got '${ORG_SWEEP_ROTATION_INDEX}'."
echo "::error::ORG_SWEEP_ROTATION_INDEX must be a non-negative integer; got '${ORG_SWEEP_ROTATION_INDEX}'. This is derived from github.run_number and should never be malformed."
exit 1
fi

Expand All @@ -938,12 +845,10 @@ jobs:
' <<<"$repositories_json"
)
sweep_target_count=${#sweep_targets[@]}
# Rotate the fixed walk order by ORG_SWEEP_ROTATION_INDEX (see
# above: a persistent per-execution counter, falling back to a
# wall-clock tick) so the same organization-wide review-dispatch
# /branch-update budget lands on a different starting repository
# each execution instead of always exhausting on the same early
# repositories (#1219). Total dispatches per execution are
# Rotate the fixed walk order by the run number so the same
# organization-wide review-dispatch/branch-update budget lands on a
# different starting repository each tick instead of always exhausting
# on the same early repositories (#1219). Total dispatches per tick are
# unchanged; only which repositories receive them rotates over time.
rotation_offset=0
if [ "$sweep_target_count" -gt 0 ]; then
Expand All @@ -955,7 +860,7 @@ jobs:
)
fi
fi
echo "Sweeping ${sweep_target_count} repositories starting at rotation offset ${rotation_offset} (rotation tick ${ORG_SWEEP_ROTATION_INDEX})."
echo "Sweeping ${sweep_target_count} repositories starting at rotation offset ${rotation_offset} (run number ${ORG_SWEEP_ROTATION_INDEX})."

failures=0
unavailable=0
Expand Down
Loading
Loading