Skip to content
Merged
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: 6 additions & 0 deletions .github/workflows/strix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ jobs:
if git -C "$TRUSTED_WORKSPACE" cat-file -e "$PR_HEAD_SHA:opencode.jsonc" 2>/dev/null; then
git -C "$TRUSTED_WORKSPACE" show "$PR_HEAD_SHA:opencode.jsonc" > "$TRUSTED_WORKSPACE/opencode.jsonc"
fi
if git -C "$TRUSTED_WORKSPACE" cat-file -e "$PR_HEAD_SHA:scripts/ci/pr_review_merge_scheduler.py" 2>/dev/null; then
git -C "$TRUSTED_WORKSPACE" show "$PR_HEAD_SHA:scripts/ci/pr_review_merge_scheduler.py" > "$TRUSTED_WORKSPACE/scripts/ci/pr_review_merge_scheduler.py"
fi
git -C "$TRUSTED_WORKSPACE" update-ref "refs/remotes/pull/${PR_NUMBER}/head" "$PR_HEAD_SHA"
exit 0
fi
Expand All @@ -124,6 +127,9 @@ jobs:
if git -C "$TRUSTED_WORKSPACE" cat-file -e "$PR_HEAD_SHA:opencode.jsonc" 2>/dev/null; then
git -C "$TRUSTED_WORKSPACE" show "$PR_HEAD_SHA:opencode.jsonc" > "$TRUSTED_WORKSPACE/opencode.jsonc"
fi
if git -C "$TRUSTED_WORKSPACE" cat-file -e "$PR_HEAD_SHA:scripts/ci/pr_review_merge_scheduler.py" 2>/dev/null; then
git -C "$TRUSTED_WORKSPACE" show "$PR_HEAD_SHA:scripts/ci/pr_review_merge_scheduler.py" > "$TRUSTED_WORKSPACE/scripts/ci/pr_review_merge_scheduler.py"
fi
exit 0
fi
if [ "$pr_head_fetch_attempt" -lt 6 ]; then
Expand Down
16 changes: 10 additions & 6 deletions PR_GOVERNANCE_AUDIT.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ OpenCode decides; GitHub Actions mutates.

## Live Repository Inventory

Live generated: 2026-06-23 04:18 KST. PR #28 post-merge refresh: 2026-06-23 16:05 KST.
Live generated: 2026-06-23 04:18 KST. PR #28 post-merge refresh: 2026-06-23 16:05 KST. PR #37 post-merge refresh: 2026-06-23 21:50 KST.

| Repo | Flow | Default | Auto | Rulesets | Required checks | Stale dismissal | Merge queue | Workflows | Recent merged actor |
|---|---:|---:|---:|---|---|---:|---:|---|---|
Expand All @@ -38,10 +38,10 @@ Live generated: 2026-06-23 04:18 KST. PR #28 post-merge refresh: 2026-06-23 16:0

| Repo | Gap |
|---|---|
| `.github` | PR #28 is merged at `a025be1` after same-head manual Strix run `28007326148`, same-head OpenCode run `28008174977`, unresolved review threads `0`, and guarded merge against head `811446d`. Remaining open PRs #19-#27 and #29-#36 are still blocked by `CHANGES_REQUESTED` and/or `DIRTY`; the scheduler dry run inspected 17 PRs and made no mutation. |
| `.github` | PR #37 is merged at `3c3695f` after current-head Strix run `28025893898`, current-head manual OpenCode run `28026724674`, unresolved review threads `0`, and guarded merge against head `8b25761`. Remaining open PRs #19-#27 and #29-#36 are still blocked by `CHANGES_REQUESTED` and/or `DIRTY`. |
| `bandscope` | Required checks are repo-specific and broad; keep GitHub native auto-merge as the check interpreter. |
| `clearfolio` | Auto-merge is off and the PR Review Merge Scheduler is missing. |
| `codec-carver` | Latest merged sample #94 still used `opencode-agent`; replace the legacy scheduler with the central GitHub Actions path. |
| `clearfolio` | Auto-merge is off. PR #13 adds the central PR Review Merge Scheduler and `opencode.jsonc`; current PR-target Strix still fails because base `strix.yml` does not copy PR-head `opencode.jsonc` into the trusted workspace. |
| `codec-carver` | Latest merged sample #94 still used `opencode-agent`; PR #98 replaces the legacy scheduler with the central GitHub Actions path and is waiting on existing OpenCode/Strix checks. |
| `contextual-orchestrator` | No matching rulesets or review workflows; either opt in deliberately or mark unmanaged. |
| `naruon` | Canonical strict check source, but open PRs still need the updated contract observed through one full outdated -> update -> new-head review trace. |
| `newsdom-api` | Ruleset-required checks must stay GitHub-interpreted; open queue is mostly review/check blocked. |
Expand Down Expand Up @@ -104,8 +104,8 @@ PR #36: block: merge conflict: DIRTY
## Rollout List

1. Keep `naruon`, `.github`, `VibeSec`, `bandscope`, `newsdom-api`, `pg-erd-cloud`, and `scopeweave` on `PR Review Merge Scheduler`.
2. Replace `codec-carver` legacy `Scheduled PR Review Merge` with `PR Review Merge Scheduler`.
3. Add `PR Review Merge Scheduler` to `clearfolio` or explicitly mark it unmanaged; auto-merge is currently off.
2. Merge `codec-carver` PR #98 to replace legacy `Scheduled PR Review Merge` with `PR Review Merge Scheduler`; current checks were still in progress at the 2026-06-23 22:13 KST snapshot.
3. Resolve `clearfolio` PR #13's trusted-base Strix blocker, then merge it to add `PR Review Merge Scheduler`; auto-merge is currently off.
4. Decide whether `contextual-orchestrator` should join the central PR governance surface; no matching workflows or rulesets were returned.
5. Keep `pg-erd-cloud` autofix workflows repo-local; do not make autofix part of the central merge contract.

Expand All @@ -128,3 +128,7 @@ PR #36: block: merge conflict: DIRTY
- Strix run `28022323798` caught that the first label repair changed normalizer parsing too narrowly: inline approval summaries in `test_strix_quick_gate.sh` no longer normalized. Label parsing now accepts inline verification labels while excluding the `Coverage:` suffix inside `Docstring coverage:`, preserving both inline transcript controls and appended evidence repair.
- PR #37 same-head manual Strix run `28023392848` succeeded for head `07a6b76`, but the concurrently dispatched same-head manual OpenCode run `28023401894` spent its early lifetime waiting in `Prepare bounded OpenCode review evidence`. That exposed a scheduler-level resource issue: dispatching Strix and OpenCode together can turn OpenCode into a long poller whenever Strix is queued or slow. The scheduler now serializes the process: first dispatch Strix, then wait for a later scheduler pass to dispatch OpenCode after Strix evidence is complete.
- The base-branch automatic OpenCode run `28025023007` still posted a current-head `CHANGES_REQUESTED` review before cancellation on head `1d05f52`, even though that automatic trigger is removed by this PR. The scheduler previously treated any current-head OpenCode `CHANGES_REQUESTED` as permanent. It now reads the latest OpenCode review on the current head, so a later same-head OpenCode approval can supersede an earlier false negative from the same reviewer.
- `clearfolio` PR #13 and `codec-carver` PR #98 are opened as thin rollouts. Their scheduler workflows now pin `scripts/ci/pr_review_merge_scheduler.py` to central commit `7be2d99` and verify SHA-256 `f954b62efa4ad60964a65501d777cb4ba26f1ac5746c2d11406d610a5ab695f6` before running the script self-test and inspecting their own PR queues. `codec-carver` PR #98 also deletes the legacy OpenCode app-token merge workflow.
- `clearfolio` PR #13 first failed Strix run `28027843973` because `opencode.jsonc` was missing. Commit `38e9a82` added the central `opencode.jsonc`, but Strix runs `28028155386`, `28030126946`, and `28030438259` still failed because clearfolio's trusted-base `strix.yml` did not copy `PR_HEAD_SHA:opencode.jsonc` into the trusted workspace. Commit `2618c41` adds the PR-head `opencode.jsonc` and scheduler-policy materialization to `strix.yml`; PR-target Strix run `28030872994` and same-head manual Strix run `28030912898` were still in progress or queued at the 2026-06-23 22:48 KST snapshot.
- `codec-carver` PR #98 already has base `opencode.jsonc`. PR #98 now pins the central scheduler instead of downloading from `main`; same-head Strix run `28030439830` and OpenCode runs `28030438605`/`28030439065` were still in progress at the 2026-06-23 22:48 KST snapshot.
- `.github` PR #38 exposed two central gaps after PR #37 merged: the `review_dispatch` reason lost the `same-head Strix and OpenCode dispatched` contract string, and `failed_status_checks()` treated failed PR-target Strix check runs as blockers even when a later manual `strix` status could supersede them. Commit `7be2d99` restores the reason string, materializes PR-head scheduler policy as non-executed data for Strix self-test, and ignores stale Strix check-run failures when the same head has a successful `strix` status context. Manual Strix run `28030448032` had passed self-test and was still running `Run Strix (quick)` at the 2026-06-23 22:48 KST snapshot.
10 changes: 9 additions & 1 deletion scripts/ci/pr_review_merge_scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,10 +248,18 @@ def has_current_head_changes_requested(pr: dict[str, Any]) -> bool:
def failed_status_checks(pr: dict[str, Any]) -> list[str]:
"""Return failing check or status context names from the PR rollup."""
failed: list[str] = []
successful_status_contexts = {
node.get("context")
for node in context_nodes(pr)
if node.get("__typename") != "CheckRun"
and (node.get("state") or "").upper() == "SUCCESS"
}
for node in context_nodes(pr):
if node.get("__typename") == "CheckRun":
conclusion = (node.get("conclusion") or "").upper()
if conclusion in {"FAILURE", "ERROR", "CANCELLED", "TIMED_OUT", "ACTION_REQUIRED", "STARTUP_FAILURE"}:
if is_strix_context(node) and "strix" in successful_status_contexts:
continue
failed.append(node.get("name") or "check-run")
else:
state = (node.get("state") or "").upper()
Expand Down Expand Up @@ -410,7 +418,7 @@ def inspect_pr(
return Decision(
number,
"review_dispatch",
"current head has completed Strix evidence; same-head OpenCode dispatched",
"current head has completed Strix evidence; same-head Strix and OpenCode dispatched",
)

return Decision(number, "block", "current head has no OpenCode approval")
Expand Down
6 changes: 4 additions & 2 deletions scripts/ci/test_strix_quick_gate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ assert_strix_workflow_pr_trigger_hardened() {
assert_file_contains "$workflow_file" 'fetch --no-tags --depth=1 origin "$PR_BASE_SHA"' "strix workflow fetches manual PR-scope base commit for diffing"
assert_file_contains "$workflow_file" 'cat-file -e "$PR_HEAD_SHA:opencode.jsonc"' "strix workflow checks for PR-head OpenCode config without executing it"
assert_file_contains "$workflow_file" 'show "$PR_HEAD_SHA:opencode.jsonc" > "$TRUSTED_WORKSPACE/opencode.jsonc"' "strix workflow materializes PR-head OpenCode config as data for self-test assertions"
assert_file_contains "$workflow_file" 'cat-file -e "$PR_HEAD_SHA:scripts/ci/pr_review_merge_scheduler.py"' "strix workflow checks for PR-head scheduler policy without executing it"
assert_file_contains "$workflow_file" 'show "$PR_HEAD_SHA:scripts/ci/pr_review_merge_scheduler.py" > "$TRUSTED_WORKSPACE/scripts/ci/pr_review_merge_scheduler.py"' "strix workflow materializes PR-head scheduler policy as data for self-test assertions"
assert_file_contains "$workflow_file" "refs/remotes/pull" "strix workflow verifies fetched PR head ref"
local pr_head_fetch_block
pr_head_fetch_block="$(
Expand All @@ -141,8 +143,8 @@ assert_strix_workflow_pr_trigger_hardened() {
record_failure "strix workflow configures git credentials in PR head fetch step"
fi
case "$pr_head_fetch_block" in
*'fetch --no-tags --depth=1 origin "$PR_HEAD_SHA"'*'show "$PR_HEAD_SHA:opencode.jsonc" > "$TRUSTED_WORKSPACE/opencode.jsonc"'*) ;;
*) record_failure "strix workflow materializes PR-head OpenCode config only after fetching the PR head commit" ;;
*'fetch --no-tags --depth=1 origin "$PR_HEAD_SHA"'*'show "$PR_HEAD_SHA:opencode.jsonc" > "$TRUSTED_WORKSPACE/opencode.jsonc"'*'show "$PR_HEAD_SHA:scripts/ci/pr_review_merge_scheduler.py" > "$TRUSTED_WORKSPACE/scripts/ci/pr_review_merge_scheduler.py"'*) ;;
*) record_failure "strix workflow materializes PR-head review policy files only after fetching the PR head commit" ;;
esac
assert_file_contains "$workflow_file" "for pr_head_fetch_attempt in 1 2 3 4 5 6" "strix workflow retries stale PR head ref propagation"
assert_file_contains "$workflow_file" "PR head ref did not resolve to expected commit" "strix workflow fails closed when PR head ref remains stale"
Expand Down
12 changes: 12 additions & 0 deletions tests/test_pr_review_merge_scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,18 @@ def test_review_state_and_failed_checks():
}
)
assert sched.failed_status_checks(failed) == ["strix", "lint"]
manual_strix_supersedes_pr_target_failure = make_pr(
statusCheckRollup={
"contexts": {
"nodes": [
{"__typename": "CheckRun", "name": "strix", "conclusion": "FAILURE"},
{"context": "strix", "state": "SUCCESS"},
{"context": "lint", "state": "ERROR"},
]
}
}
)
assert sched.failed_status_checks(manual_strix_supersedes_pr_target_failure) == ["lint"]


def test_actions_call_gh_with_expected_arguments(monkeypatch):
Expand Down