Skip to content
Closed
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
62b81ca
chore(ci): remove orphaned required-workflow-bootstrap job from dispa…
claude Aug 31, 2026
902d8ec
Merge origin/main into fix/hollow-path-opencode-dispatch-bootstrap
Aug 31, 2026
b00e374
fix(ci): bound required-workflow-bootstrap awk extraction to its own job
claude Aug 31, 2026
d841254
fix(ci): remove grep -q from test_strix_quick_gate.sh pipeline checks
claude Aug 31, 2026
d862626
Merge origin/main into fix/hollow-path-opencode-dispatch-bootstrap
claude Sep 1, 2026
a470f29
Merge remote-tracking branch 'origin/main' into fix/hollow-path-openc…
claude Sep 1, 2026
db106d5
test(ci): close main's post-#1546 scheduler coverage regression
claude Sep 1, 2026
85c2469
docs(gap-baseline): record post-#1546 scheduler coverage regression
claude Sep 1, 2026
6f40a06
test(ci): document nested REST fixture helpers
seonghobae Sep 1, 2026
0e0856e
Merge remote-tracking branch 'origin/main' into fix/hollow-path-openc…
claude Sep 1, 2026
febf097
fix(ci): repair review-dispatch blob pin after merging current main
claude Sep 1, 2026
d528a9f
Merge remote-tracking branch 'origin/fix/main-coverage-gap-scheduler-…
claude Sep 1, 2026
0be68ad
fix(tests): drain dispatch fixture stdin to break CI dependency cycle
seonghobae Sep 1, 2026
2bad915
Merge remote-tracking branch 'origin/main' into fix/hollow-path-openc…
claude Sep 1, 2026
22c7357
merge: sync with origin/main (4fff1e2e, includes #1564/#1587)
claude Sep 1, 2026
665946b
test(ci,noema): port stale-test fixes from #1598 (post-#1587/#1564)
claude Sep 1, 2026
f918bac
merge: sync with origin/main (5768f2bd, absorbs #1592's overlapping f…
claude 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
6 changes: 0 additions & 6 deletions .github/workflows/opencode-review-dispatch.yml
Comment thread
seonghobae marked this conversation as resolved.
Comment thread
seonghobae marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,6 @@ permissions:
contents: read

jobs:
required-workflow-bootstrap:
name: required-workflow-bootstrap
runs-on: ubuntu-latest
steps:
- run: echo "OpenCode repository-dispatch review run materialized."

validate-pr-metadata:
name: validate-pr-metadata
if: github.event_name == 'repository_dispatch'
Expand Down
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ this file. The format follows Keep a Changelog, and versioned releases follow
Semantic Versioning where the repository publishes a release.

## [Unreleased]
- Close a 99% `scripts/ci` coverage regression on protected main: merged #1546 added an
uncovered `live_head_matches` helper, an uncovered no-active/no-stale-runs fall-through in
`prepare_autofix_slot`, and an uncovered "current-head autofix run is already queued or
running" wait path in `pr_review_fix_scheduler.py::inspect_pr`, while the pre-existing
conflicted-draft and conflicted-unauthorized `inspect_pr` returns and the REST
`fetch_workflow_names_by_check_suite_rest` pagination/name-filtering/permission-denied paths
in `pr_review_merge_scheduler.py` remained untested. Every PR rebasing onto main inherited
this failure via the `coverage-evidence` required check regardless of its own diff; this adds
test-only coverage for all of the above with no production code change.
- Avoid redundant merge-scheduler wakes when the trusted receipt predicate
already finds a substantive exact-head OpenCode verdict. Missing, stale, or
fallback-only evidence still dispatches review work, while receipt lookup or
Expand Down Expand Up @@ -150,6 +159,13 @@ Semantic Versioning where the repository publishes a release.
then rejected via 429/404/timeout). New regression tests pin the default
to the policy module's canonical value and forbid the total-routes
constant from reappearing as the account-cap fallback.
- Remove the orphaned `required-workflow-bootstrap` job from
`opencode-review-dispatch.yml`: it only echoed a materialization message and
was never referenced by any `needs:` clause in that repository_dispatch-only
workflow, which fires only in an already-trusted, non-PR context (the
matching trust-boundary bootstrap that the pattern is for stays in the
`pull_request_target`-triggered `opencode-review.yml`, whose branch-protection
contract still requires it).
- Fix a dangling reference #1468 left in `docs/product-goal-directive.md`
(flagged by Devin Review on that PR): the standing operating directive
still named the removed `free_family_diversity` evidence field instead of
Expand Down
48 changes: 48 additions & 0 deletions docs/product-technical-gap-baseline.md
Original file line number Diff line number Diff line change
Expand Up @@ -2344,6 +2344,54 @@ contract assertion, and `docs/adr/0003-contextual-orchestrator-vendored-free-zdr
"today" reference. Landed in the same PR (`#1463`) as the streaming revert,
not split out, since the revert is unsafe without it.

## 2026-09-01 post-#1546 `scripts/ci` coverage regression on protected main: root-caused and closed

**Context**: `#1546` (merged, exact head `5686de41660d51a7a7f22b8840dfa6ccfe5ff3f1`) reconciled
unbounded exact-head review agents and, as part of a 90-line expansion of
`scripts/ci/pr_review_fix_scheduler.py`, added a `live_head_matches` helper, a no-active/no-stale
fall-through branch in `prepare_autofix_slot`, and an "already queued or running" wait branch in
`inspect_pr` — none of which any test exercised directly. This compounded a narrower, older gap in
the same file (`inspect_pr`'s conflicted-draft and conflicted-unauthorized returns) and in
`scripts/ci/pr_review_merge_scheduler.py::fetch_workflow_names_by_check_suite_rest` (pagination,
missing-suite-id/blank-name filtering, non-access-error propagation), first found and attempted in
now-closed, unmerged `#1547`/`#1551`/`#1554` — none of whose evidence or diffs transferred here;
this pass re-derived the current gap from a clean `origin/main` clone rather than assuming those
predecessors were still accurate against `#1546`'s shifted line numbers and new branches. Verified
directly: `coverage report --show-missing` on unmodified `main` showed
`scripts/ci/pr_review_fix_scheduler.py` at 97% (missing 116-121, 459->466, 495, 503, 546) and
`scripts/ci/pr_review_merge_scheduler.py` at 99% (missing 1003, 1008->1005, 1012) — total repo-wide
99%, below the `pyproject.toml` `fail_under = 100` gate. Because `opencode-review-dispatch.yml`'s
`coverage-evidence` job measures the **merged** PR tree (base + head) and hard-fails below 100%,
every PR rebasing onto main inherited this failure regardless of its own diff — org-wide impact,
not scoped to one PR.

**Fix**: `#1567` (test-only, no production code) adds direct unit coverage for `live_head_matches`
(case-insensitive match, mismatch, malformed-payload paths), `prepare_autofix_slot`'s empty-run
fall-through, the `inspect_pr` conflicted-draft/conflicted-unauthorized/already-queued cases, and
the `fetch_workflow_names_by_check_suite_rest` pagination/filtering/error-propagation paths.
Verified on the fix commit (`db106d50f2134ece147bc5318e389aeb124d198c`): `coverage run -m pytest
tests -q` (2251 passed, 1 skipped, 21 subtests), `coverage report` (repo-wide 100%, both files
individually 100% statement and 100% branch), `interrogate` (100.0%).

**Devin Review raised a false positive on the fix itself**, claiming
`test_live_head_matches_compares_case_insensitively_and_fails_closed` left non-object-payload,
non-string-SHA, and wrong-length-SHA branches uncovered. Re-verified against the actual gate rather
than accepted at face value: `live_head_matches` has exactly one `if` statement (two arcs, both
exercised by the committed test), and its final `return (isinstance(...) and len(...) == 40 and
...)` is a single boolean expression with no `if`/`else` of its own — `coverage.py`'s branch mode
(what `fail_under = 100` actually measures here) tracks control-flow arcs between statements, not
sub-clause condition coverage within one expression. The cited cases are additional test
thoroughness, not something the gate is currently failing on; confirmed by a full-suite run on the
exact same head showing both files at 100% branch coverage with zero missing branches. Replied with
this evidence on the review thread and did not widen the PR's diff for a claim that does not hold
against this repo's own tooling.

**One test in the full suite remains a known, pre-existing flake**, unrelated to this change:
`tests/test_opencode_required_verdict_regression.py::test_scheduler_wake_reuses_trusted_receipt_predicate`
intermittently exits 141 (SIGPIPE) under full-suite parallel load; reproduces identically on
unmodified `origin/main` and passes cleanly in file isolation. Not remediated here — out of scope
for a coverage-gap-only PR, and not itself a coverage regression.

## 5. 실행 루프와 고객의 다음 행동

각 hourly pass는 아래 순서를 유지한다.
Expand Down
12 changes: 6 additions & 6 deletions tests/test_opencode_agent_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,12 +469,12 @@ def test_opencode_ignores_superseded_cancelled_rollup_checks():
def test_opencode_target_coverage_materializes_only_after_authorized_dispatch():
"""Keep PR-controlled test execution off the pull_request_target path."""
workflow = Path(".github/workflows/opencode-review-dispatch.yml").read_text(encoding="utf-8")
assert "required-workflow-bootstrap:" in workflow
assert "OpenCode repository-dispatch review run materialized." in workflow
bootstrap_start = workflow.index(" required-workflow-bootstrap:\n")
bootstrap_end = workflow.index("\n validate-pr-metadata:", bootstrap_start)
bootstrap_job = workflow[bootstrap_start:bootstrap_end]
assert "\n if:" not in bootstrap_job
# required-workflow-bootstrap is the trusted-source-resolution sentinel needed
# only where the org ruleset targets a pull_request_target entrypoint
# (opencode-review.yml). This repository_dispatch-only workflow is not itself
# a required-workflow path, so it must not carry a copy-pasted, need-less
# orphan of that job.
assert "required-workflow-bootstrap:" not in workflow
assert (
"github.event.pull_request.head.repo.full_name == github.repository"
not in workflow
Expand Down
1 change: 1 addition & 0 deletions tests/test_opencode_required_verdict_regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ def test_scheduler_wake_reuses_trusted_receipt_predicate(
elif [[ "$*" == *"/pulls/7/reviews"* ]]; then
printf '[%s]' "$FAKE_REVIEWS"
elif [[ "$*" == *"repos/ContextualWisdomLab/.github/dispatches"* ]]; then
cat >/dev/null
Comment thread
github-actions[bot] marked this conversation as resolved.
printf 'dispatch\n' >>"$DISPATCH_CALLS"
fi
""",
Expand Down
2 changes: 1 addition & 1 deletion tests/test_pr_review_autofix_nvidia_nim_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
DOCTORING_RECORD = Path("docs/doctoring/hourly-nvidia-nim-autofix.md")
CHANGELOG = Path("CHANGELOG.md")
REVIEW_DISPATCH_WORKFLOW = Path(".github/workflows/opencode-review-dispatch.yml")
REVIEW_DISPATCH_BLOB_SHA = "3677f408bd6b99577fd7d5923fbd67c91f437ae0"
REVIEW_DISPATCH_BLOB_SHA = "0814541a9d79e72298fe4fea463224688bb6bd54"


def _workflow_text(path: Path) -> str:
Expand Down
49 changes: 49 additions & 0 deletions tests/test_pr_review_fix_scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,40 @@ def test_prepare_autofix_slot_preserves_new_head_workers_after_head_advance(monk
workflow_repository=fix.DEFAULT_AUTOFIX_REPOSITORY,
dry_run=False,
) is None


def test_prepare_autofix_slot_returns_directly_with_no_active_or_stale_runs(monkeypatch):
"""An empty Actions run list needs no reconciliation and skips cancellation."""
monkeypatch.setattr(fix, "run_json", lambda _args: {"workflow_runs": []})
monkeypatch.setattr(
fix,
"force_cancel_workflow_runs",
lambda *_args: pytest.fail("no stale runs must not attempt cancellation"),
)

assert fix.prepare_autofix_slot(
"owner/repo",
make_pr(),
workflow=fix.DEFAULT_AUTOFIX_WORKFLOW,
workflow_repository=fix.DEFAULT_AUTOFIX_REPOSITORY,
dry_run=False,
) is False


def test_live_head_matches_compares_case_insensitively_and_fails_closed(monkeypatch):
"""Live head lookup normalizes case and rejects malformed or mismatched payloads."""
head = "a" * 40

monkeypatch.setattr(fix, "run_json", lambda _args: {"head": {"sha": head.upper()}})
assert fix.live_head_matches("owner/repo", make_pr(headRefOid=head))

monkeypatch.setattr(fix, "run_json", lambda _args: {"head": {"sha": "b" * 40}})
assert not fix.live_head_matches("owner/repo", make_pr(headRefOid=head))

monkeypatch.setattr(fix, "run_json", lambda _args: {"nothead": {}})
assert not fix.live_head_matches("owner/repo", make_pr(headRefOid=head))


def test_terminal_failed_check_triggers_rca_without_prior_opencode_review():
"""Exact-head check evidence can start RCA without a circular review prerequisite."""
pr = make_pr(
Expand Down Expand Up @@ -1329,6 +1363,21 @@ def test_fix_inspect_skip_wait_and_error_paths(monkeypatch):
monkeypatch.setattr(fix, "issue_comments", lambda repo, number: [{"body": f"{fix.FIX_MARKER} head_sha={'a' * 40} epoch={int(time.time())} -->"}])
assert fix.inspect_pr("owner/repo", make_pr(), args) == ("wait", ("recent autofix marker exists for this head",))

assert fix.inspect_pr(
"owner/repo", make_pr(mergeStateStatus="DIRTY", isDraft=True), args
) == ("skip", ("draft PR",))
assert fix.inspect_pr("owner/repo", make_pr(mergeStateStatus="DIRTY"), args) == (
"skip",
("merge conflict is not authorized for repair",),
)

monkeypatch.setattr(fix, "issue_comments", lambda repo, number: [])
monkeypatch.setattr(fix, "prepare_autofix_slot", lambda *_args, **_kwargs: True)
assert fix.inspect_pr("owner/repo", make_pr(), args) == (
"wait",
("current-head autofix run is already queued or running",),
)

pr1 = make_pr(number=1)
pr2 = make_pr(number=2)
monkeypatch.setattr(fix, "fetch_open_prs", lambda repo, max_prs: [pr1, pr2])
Expand Down
70 changes: 70 additions & 0 deletions tests/test_pr_review_fix_scheduler_rest_workflow_identity.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,73 @@ def fake_api(path: str) -> Any:
assert merge.is_strix_context(context)
assert merge.strix_evidence_state(pr) == expected_state
assert fix.current_head_failed_checks(pr) == ()


def test_fetch_workflow_names_by_check_suite_rest_paginates_past_100(
monkeypatch: Any,
) -> None:
"""A first page of exactly 100 runs must fetch a second page and merge both."""
head_sha = "e" * 40
page1 = [
{"check_suite_id": i, "name": f"workflow-{i}"} for i in range(100)
]
page2 = [{"check_suite_id": 100, "name": "workflow-100"}]
calls: list[str] = []

def fake_api(path: str) -> Any:
"""Return deterministic paginated workflow-run fixtures."""
calls.append(path)
if path.endswith("page=1"):
return {"workflow_runs": page1}
if path.endswith("page=2"):
return {"workflow_runs": page2}
raise AssertionError(f"unexpected path {path}")

monkeypatch.setattr(merge, "gh_api_json", fake_api)

names = merge.fetch_workflow_names_by_check_suite_rest("owner/repo", head_sha)

assert names == {i: f"workflow-{i}" for i in range(101)}
assert calls == [
f"repos/owner/repo/actions/runs?head_sha={head_sha}&per_page=100&page=1",
f"repos/owner/repo/actions/runs?head_sha={head_sha}&per_page=100&page=2",
]


def test_fetch_workflow_names_by_check_suite_rest_skips_entries_missing_suite_id_or_name(
monkeypatch: Any,
) -> None:
"""A run with no check-suite id or a blank name must not populate the map."""
head_sha = "f" * 40

def fake_api(path: str) -> Any:
"""Return workflow runs that exercise incomplete-identity filtering."""
return {
"workflow_runs": [
{"check_suite_id": None, "name": "orphaned run"},
{"check_suite_id": 900, "name": ""},
{"check_suite_id": 901, "name": "kept run"},
]
}

monkeypatch.setattr(merge, "gh_api_json", fake_api)

names = merge.fetch_workflow_names_by_check_suite_rest("owner/repo", head_sha)

assert names == {901: "kept run"}


def test_fetch_workflow_names_by_check_suite_rest_propagates_non_access_errors(
monkeypatch: Any,
) -> None:
"""A page-fetch failure unrelated to integration access must fail closed."""
head_sha = "0" * 40

def fake_api(path: str) -> Any:
"""Simulate a non-access REST failure that must propagate."""
raise RuntimeError("gh: HTTP 502 (exhausted retries)")

monkeypatch.setattr(merge, "gh_api_json", fake_api)

with pytest.raises(RuntimeError, match="HTTP 502"):
merge.fetch_workflow_names_by_check_suite_rest("owner/repo", head_sha)
Loading