Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
7 changes: 7 additions & 0 deletions .github/workflows/opencode-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -320,11 +320,13 @@ jobs:
OPENCODE_SOURCE_WORKDIR: ${{ runner.temp }}/opencode-pr-head
OPENCODE_EVIDENCE_FILE: ${{ runner.temp }}/opencode-review-evidence.md
OPENCODE_FAILED_CHECK_EVIDENCE_FILE: ${{ runner.temp }}/opencode-failed-check-evidence.md
OPENCODE_CHANGED_FILES_FILE: ${{ runner.temp }}/opencode-changed-files.txt
COVERAGE_EVIDENCE_SUMMARY: ${{ needs.coverage-evidence.outputs.coverage_summary || 'Coverage evidence job did not run or did not publish coverage evidence.' }}
FAILED_CHECK_EVIDENCE_ATTEMPTS: "75"
FAILED_CHECK_EVIDENCE_SLEEP_SECONDS: "30"
run: |
set -euo pipefail
printf 'OPENCODE_CHANGED_FILES_FILE=%s\n' "$OPENCODE_CHANGED_FILES_FILE" >>"$GITHUB_ENV"

current_peer_checks_still_running() {
local owner="${GH_REPOSITORY%%/*}"
Expand Down Expand Up @@ -650,6 +652,7 @@ jobs:
printf -- "- Head SHA: \`%s\`\n\n" "$PR_HEAD_SHA"
PR_MERGE_BASE="$(git -C "$OPENCODE_SOURCE_WORKDIR" merge-base "$PR_BASE_SHA" "$PR_HEAD_SHA")"
printf -- "- Merge base SHA: \`%s\`\n\n" "$PR_MERGE_BASE"
git -C "$OPENCODE_SOURCE_WORKDIR" diff --name-only --find-renames "$PR_MERGE_BASE" "$PR_HEAD_SHA" >"$OPENCODE_CHANGED_FILES_FILE"

printf '## CodeGraph evidence\n\n'
printf 'The workflow initialized CodeGraph before this evidence file was built.\n'
Expand Down Expand Up @@ -720,6 +723,7 @@ jobs:
OPENCODE_REVIEW_WORKDIR: ${{ runner.temp }}/opencode-review-project
OPENCODE_EVIDENCE_FILE: ${{ runner.temp }}/opencode-review-evidence.md
OPENCODE_FAILED_CHECK_EVIDENCE_FILE: ${{ runner.temp }}/opencode-failed-check-evidence.md
OPENCODE_CHANGED_FILES_FILE: ${{ runner.temp }}/opencode-changed-files.txt
OPENCODE_SOURCE_WORKDIR: ${{ runner.temp }}/opencode-pr-head
run: |
set -euo pipefail
Expand All @@ -736,6 +740,9 @@ jobs:
if [ -s "$OPENCODE_FAILED_CHECK_EVIDENCE_FILE" ]; then
cp "$OPENCODE_FAILED_CHECK_EVIDENCE_FILE" "$OPENCODE_REVIEW_WORKDIR/failed-check-evidence.md"
fi
if [ -s "$OPENCODE_CHANGED_FILES_FILE" ]; then
cp "$OPENCODE_CHANGED_FILES_FILE" "$OPENCODE_REVIEW_WORKDIR/changed-files.txt"
fi

cat >"${OPENCODE_REVIEW_WORKDIR}/AGENTS.md" <<'EOF'
# OpenCode CI Review Rules
Expand Down
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
21 changes: 13 additions & 8 deletions PR_GOVERNANCE_AUDIT.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ 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. clearfolio PR #13 post-merge refresh: 2026-06-24 04:48 KST.

| Repo | Flow | Default | Auto | Rulesets | Required checks | Stale dismissal | Merge queue | Workflows | Recent merged actor |
|---|---:|---:|---:|---|---|---:|---:|---|---|
| `ContextualWisdomLab/.github` | GitHub Flow | `main` | on | `Lock default branch` | none | true | no | OpenCode Review; PR Review Merge Scheduler; Strix Security Scan | #28 `seonghobae` merge `a025be1`; #18 `seonghobae`; #17 `seonghobae` |
| `ContextualWisdomLab/.github` | GitHub Flow | `main` | on | `Lock default branch` | none | true | no | OpenCode Review; PR Review Merge Scheduler; Strix Security Scan | #41 `seonghobae` merge `b3393d5`; #38 `seonghobae` merge `928e43b`; #37 `seonghobae` merge `3c3695f` |
| `ContextualWisdomLab/bandscope` | Git Flow | `develop` | on | `Lock default branch` | `ci / build-and-test`, `dependency-review`, `security-audit`, `CodeQL`, `sbom`, `release-preflight`, `gate / build / windows`, `gate / build / macos`, `trivy-fs-scan` | false | no | OpenCode Review; PR Review Merge Scheduler; Strix Security Scan | #427 `github-actions`; #408 `seonghobae`; #405 `seonghobae` |
| `ContextualWisdomLab/clearfolio` | GitHub Flow | `main` | off | `PR` | none | false | no | OpenCode Review; Strix Security Scan | #9 `seonghobae`; #8 `seonghobae`; #7 `seonghobae` |
| `ContextualWisdomLab/clearfolio` | GitHub Flow | `main` | off | `PR` | none | false | no | OpenCode Review; PR Review Merge Scheduler; Strix Security Scan | #13 `seonghobae` merge `4bc17c6`; #9 `seonghobae`; #8 `seonghobae` |
| `ContextualWisdomLab/codec-carver` | GitHub Flow | `main` | on | `Lock default branch` | none | true | no | OpenCode Review; Scheduled PR Review Merge; Strix Security Scan | #94 `opencode-agent`; #93 `seonghobae`; #90 `seonghobae` |
| `ContextualWisdomLab/contextual-orchestrator` | GitHub Flow | `main` | off | none | none | unknown | unknown | none matched | none |
| `ContextualWisdomLab/ContextualWisdomLab.github.io` | GitHub Flow | `main` | on | `Lock default branch` | none | true | no | OpenCode Review; PR Review Merge Scheduler; Strix Security Scan | #15 `seonghobae`; #14 `seonghobae`; #13 `github-actions` auto by `github-actions` |
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, #38, and #41 are merged. Remaining open PRs #19-#27, #29-#36, #39, #40, and #42 still need current-head review/check evaluation; #42 has PR-target Strix run `28052498149` in progress for head `36cc8ca`. |
| `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` | PR #13 is merged at `4bc17c6` after same-head manual Strix run `28051319530`, same-head manual OpenCode run `28051665082`, unresolved review threads `0`, and guarded merge against head `5fe1791`. Auto-merge remains off, so direct guarded merge is the repo path. |
| `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. `clearfolio` PR #13 is complete; keep the repo on direct guarded merge until auto-merge is deliberately enabled.
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,8 @@ 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 were opened as thin rollouts. `clearfolio` PR #13 is now merged at `4bc17c6`; `codec-carver` PR #98 remains the thin rollout that deletes the legacy OpenCode app-token merge workflow.
- `clearfolio` PR #13 first failed Strix run `28027843973` because `opencode.jsonc` was missing. Later current-head proof used manual Strix run `28051319530` and manual OpenCode run `28051665082`; the final approval named the changed review-tooling files and head `5fe1791d48ddcf03dbc365cc6fa407e7cbe70a89` before guarded merge.
- `.github` PR #42 exposed that central approval normalization should not accept generic path-looking evidence when exact current-head changed files are available. The OpenCode workflow now writes `git diff --name-only --find-renames "$PR_MERGE_BASE" "$PR_HEAD_SHA"` to `OPENCODE_CHANGED_FILES_FILE`, gives the isolated review workspace `changed-files.txt`, and the normalizer rejects `APPROVE` unless the approval names one of those exact files.
- `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.
41 changes: 34 additions & 7 deletions scripts/ci/opencode_review_normalize_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,30 @@ def mentions_changed_file_evidence(reason: str, summary: str) -> bool:
return bool(CHANGED_FILE_EVIDENCE_PATTERN.search(f"{reason}\n{summary}"))


def current_changed_files() -> set[str]:
"""Return the exact current-head changed files when the workflow provides them."""
changed_files_path = os.environ.get("OPENCODE_CHANGED_FILES_FILE")
if not changed_files_path:
return set()
Comment thread
github-actions[bot] marked this conversation as resolved.
try:
return {
line.strip()
for line in Path(changed_files_path).read_text(encoding="utf-8").splitlines()
if line.strip()
}
except OSError:
return set()


def mentions_actual_changed_file(reason: str, summary: str) -> bool:
"""Return whether an approval names an exact current-head changed file."""
changed_files = current_changed_files()
if not changed_files:
return mentions_changed_file_evidence(reason, summary)
combined = f"{reason}\n{summary}"
return any(changed_file in combined for changed_file in changed_files)
Comment thread
github-actions[bot] marked this conversation as resolved.


def mentions_verification_posture(reason: str, summary: str) -> bool:
"""Return whether an approval records the concrete review surfaces checked."""
combined = f"{reason}\n{summary}".casefold()
Expand Down Expand Up @@ -379,7 +403,7 @@ def valid_control(
if admits_missing_structural_review(reason, summary):
return None
summary = repair_approval_summary(reason, summary)
if not mentions_changed_file_evidence(reason, summary):
if not mentions_actual_changed_file(reason, summary):
return None
if not mentions_verification_posture(reason, summary):
return None
Expand Down Expand Up @@ -428,14 +452,17 @@ def iter_json_objects(text: str) -> list[Any]:
# OpenCode exports may contain prose around the JSON control object.
pass

for index, character in enumerate(text):
if character != "{":
continue
index = 0
while True:
index = text.find("{", index)
if index == -1:
break
Comment thread
github-actions[bot] marked this conversation as resolved.
try:
value, _ = decoder.raw_decode(text[index:])
value, _ = decoder.raw_decode(text, index)
values.append(value)
except json.JSONDecodeError:
continue
values.append(value)
pass
index += 1

return values

Expand Down
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
Comment thread
github-actions[bot] marked this conversation as resolved.
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",
"same-head Strix and OpenCode dispatched",
)

return Decision(number, "block", "current head has no OpenCode approval")
Expand Down
4 changes: 4 additions & 0 deletions scripts/ci/strix_quick_gate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2508,6 +2508,10 @@ is_rate_limit_error() {
return 0
fi

if grep -Fq 'Too many requests. For more on scraping GitHub' "$STRIX_LOG"; then
return 0
fi

if grep -Eq '"status"[[:space:]]*:[[:space:]]*"RESOURCE_EXHAUSTED"' "$STRIX_LOG"; then
return 0
fi
Expand Down
Loading