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
4 changes: 1 addition & 3 deletions .github/workflows/strix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,7 @@ jobs:
# here and consumed through `needs`. See
# docs/doctoring/required-workflow-path-filter-boundary.md.
# Fails OPEN: an unreadable, empty, or truncated file list scans everything.
if: >-
github.event_name != 'pull_request_target' ||
(github.event.action != 'closed' && github.event.action != 'converted_to_draft')
if: github.event_name != 'pull_request_target' || (github.event.action != 'closed' && github.event.action != 'converted_to_draft')
runs-on: ubuntu-24.04
timeout-minutes: 5
permissions:
Expand Down
41 changes: 41 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,47 @@
- Raised `hourly-review-repair.yml`'s discovery ceiling from 50 to 200 while rotating deterministic 50-PR deep-inspection windows by hourly run number. The scheduler hydrates only the selected window and stops immediately after its single dispatch, preserving access to newer PRs without quadrupling expensive review/check/comment work. See `docs/doctoring/hourly-review-repair-single-file-consolidation.md`'s 2026-09-03 follow-up.

## [Unreleased]
- **Fix current-main contract drift that blocked the unscoped
`agent-review-runtime-quality-ci.yml` "Verify scheduler and
contextual-orchestrator review-repair contracts" step (which discovers and
runs the full `tests/` directory with no positional arguments).** First,
`strix.yml`'s `changed-scope` job had drifted from its byte-identical
siblings in `security-scan.yml`/`sast-semgrep.yml`: PR #1869's
`converted_to_draft` generalization folded its `if:` condition onto a
multi-line `>-` block scalar, and the extra continuation lines survived
`test_gate_job_is_byte_identical_across_the_five_workflows_apart_from_if`'s
`if:`-line-only normalization. Collapsed it back to one physical `if:` line
with the same expression -- no semantic change. Second,
`test_noema_close_cleanup_selects_only_the_closed_pr_across_shared_display_titles`
still looked up a step named "...for the closed pull request" and passed
`CLOSED_PR_NUMBER`, both retired by the same PR #1869 when it generalized
`noema-review.yml`'s `cancel-closed-pr-runs` cleanup step to "...for the
inactive pull request" (env renamed to `INACTIVE_PR_NUMBER`/
`INACTIVE_PR_HEAD_SHA`/`PR_ACTION`) and added a `live_target_matches`
live-PR re-verification before every cancellation pass (mirroring
`strix.yml`'s identical job) -- `tests/test_noema_review_gate.py`'s
equivalent tests were already updated for this at the time, but this one
was missed. Updated the test to the current step name and env vars and
taught its fake `gh` to answer the new `pulls/<number>` live-state lookup;
the PR #1507 "sibling Noema runs evade cancellation" `pull_requests[]`
matching invariant it protects is unchanged and still correctly
implemented in production. Third,
`test_dispatch_strix_reruns_scan_job_not_sibling_publisher` only mocked
`rerun_actions_job`, so in any environment with a real `gh` CLI on `PATH`
its `dispatch_strix_evidence` call still ran the genuine
`live_dispatch_head_matches` re-read, which invoked the unmocked `fetch_pr`
against the real GitHub API for a synthetic PR that does not exist there --
returning a live/head mismatch and `"stale_head"` instead of the expected
`"rerun"` (and, absent `gh` entirely, failing even earlier with a missing
executable). Added `monkeypatch.setattr(sched, "fetch_pr", lambda *_args:
[pr])` alongside the existing `rerun_actions_job` mock so the live-head
check observes the same fixture `pr` as authoritative, matching how every
other call in this test path is already isolated from real GitHub state.
Fourth, the Strix shell contract still expected job-level concurrency after
PR #1878 moved same-PR coalescing to workflow admission; it now asserts the
admission-level key and rejects the obsolete delayed key. Fifth, the
consolidated review-recovery fixtures now use the 17 daily UTC schedules
adopted by main instead of the retired hourly expressions.
- Remove the central `org-queue-sweep` runner and its organization-wide
repository walk. Native PR/review events, auto-merge, trigger-aware
same-PR cancellation, and each repository's daily `scan-pr-queue` recovery
Expand Down
5 changes: 3 additions & 2 deletions scripts/ci/test_strix_quick_gate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,10 @@ assert_strix_workflow_pr_trigger_hardened() {

assert_file_contains "$workflow_file" "branches: [main, develop, master]" "strix workflow scans GitHub Flow and Git Flow protected branches"
assert_file_contains "$workflow_file" "pull_request_target:" "strix workflow uses trusted PR trigger"
assert_file_contains "$workflow_file" "admit-current-head:" "strix workflow admits the live pull request head before provider concurrency"
assert_file_contains "$workflow_file" "admit-current-head:" "strix workflow admits the live pull request head before provider execution"
assert_file_contains "$workflow_file" "needs: [changed-scope, admit-current-head]" "strix provider queue waits for live-head admission"
assert_file_contains "$workflow_file" 'strix-security-scan-${{ needs.admit-current-head.outputs.target_repository }}-${{' "strix workflow defines one admitted repository and PR concurrency group"
assert_file_contains "$workflow_file" 'strix-security-scan-${{' "strix workflow coalesces by repository and PR before job admission"
assert_file_not_contains "$workflow_file" 'strix-security-scan-${{ needs.admit-current-head.outputs.target_repository }}-${{' "strix concurrency is not delayed until job admission"
assert_file_contains "$workflow_file" "cancel-superseded-pr-runs:" "strix workflow runs superseded-head cleanup outside the provider scan queue"
assert_file_not_contains "$workflow_file" "format('closed-pr-{0}-{1}'" "strix cleanup does not need a second concurrency queue"
assert_file_contains "$workflow_file" 'echo "pr_number=${GITHUB_RUN_ID}"' "strix workflow preserves independent push and schedule evidence"
Expand Down
6 changes: 3 additions & 3 deletions tests/test_github_hourly_conflict_repair.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,11 @@ def test_reusable_scheduler_enables_policy_for_hourly_callers() -> None:
assert "--resolve-unreviewed-conflicts" in workflow


def test_central_repository_has_hourly_self_caller() -> None:
"""The central repository itself is scanned instead of relying on product callers."""
def test_central_repository_has_daily_self_caller() -> None:
"""The central repository gets one daily recovery without a product caller."""
workflow = _CALLER.read_text(encoding="utf-8")

assert 'cron: "21 * * * *"' in workflow
assert 'cron: "21 6 * * *"' in workflow
assert "uses: ./.github/workflows/pr-review-fix-scheduler.yml" in workflow
# The consolidated file resolves per-repository parameters through a
# github.event.schedule lookup table rather than flat `key: value`
Expand Down
34 changes: 17 additions & 17 deletions tests/test_hourly_review_repair_callers.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
# and both are asserted separately as static `with:` values rather than
# carried per-target.
_EXPECTED_TARGETS: dict[str, list[dict[str, str]]] = {
"2 * * * *": [
"2 0 * * *": [
{
"name": "afipc",
"target_repository": "ContextualWisdomLab/aFIPC",
Expand All @@ -59,7 +59,7 @@
"concurrency_group": "afipc-hourly-review-repair",
},
],
"4 * * * *": [
"4 1 * * *": [
{
"name": "lineageweave",
"target_repository": "ContextualWisdomLab/LineageWeave",
Expand All @@ -68,7 +68,7 @@
"concurrency_group": "lineageweave-hourly-review-repair",
},
],
"9 * * * *": [
"9 2 * * *": [
{
"name": "psychometrics-commons",
"target_repository": "ContextualWisdomLab/psychometrics-commons",
Expand All @@ -77,7 +77,7 @@
"concurrency_group": "psychometrics-commons-hourly-review-repair",
},
],
"10 * * * *": [
"10 3 * * *": [
{
"name": "originweave",
"target_repository": "ContextualWisdomLab/OriginWeave",
Expand All @@ -86,7 +86,7 @@
"concurrency_group": "originweave-hourly-review-repair",
},
],
"14 * * * *": [
"14 4 * * *": [
{
"name": "quarantine-sandbox",
"target_repository": "ContextualWisdomLab/quarantine-sandbox-runtime",
Expand All @@ -95,7 +95,7 @@
"concurrency_group": "quarantine-sandbox-hourly-review-repair",
},
],
"16 * * * *": [
"16 5 * * *": [
{
"name": "nonnest2",
"target_repository": "ContextualWisdomLab/nonnest2",
Expand All @@ -104,7 +104,7 @@
"concurrency_group": "nonnest2-hourly-review-repair",
},
],
"21 * * * *": [
"21 6 * * *": [
{
"name": "github",
"target_repository": "ContextualWisdomLab/.github",
Expand All @@ -113,7 +113,7 @@
"concurrency_group": "github-hourly-review-repair",
},
],
"23 * * * *": [
"23 7 * * *": [
{
"name": "clearfolio",
"target_repository": "ContextualWisdomLab/clearfolio",
Expand All @@ -122,7 +122,7 @@
"concurrency_group": "clearfolio-hourly-review-repair",
},
],
"27 * * * *": [
"27 8 * * *": [
{
"name": "accounting-information-platform",
"target_repository": "ContextualWisdomLab/accounting-information-platform",
Expand All @@ -131,7 +131,7 @@
"concurrency_group": "accounting-information-platform-hourly-review-repair",
},
],
"34 * * * *": [
"34 9 * * *": [
{
"name": "contextual-orchestrator",
"target_repository": "ContextualWisdomLab/contextual-orchestrator",
Expand All @@ -140,7 +140,7 @@
"concurrency_group": "contextual-orchestrator-hourly-review-repair",
},
],
"37 * * * *": [
"37 10 * * *": [
{
"name": "disksage",
"target_repository": "ContextualWisdomLab/disksage",
Expand All @@ -149,7 +149,7 @@
"concurrency_group": "disksage-hourly-review-repair",
},
],
"43 * * * *": [
"43 11 * * *": [
{
"name": "governance-risk-compliance",
"target_repository": "ContextualWisdomLab/governance-risk-compliance",
Expand All @@ -164,7 +164,7 @@
# lookup makes that sharing explicit and still dispatches each
# repository exactly once per hour, via the matrix in
# dispatch-review-repair.
"49 * * * *": [
"49 12 * * *": [
{
"name": "fast-mlsirm",
"target_repository": "ContextualWisdomLab/fast-mlsirm",
Expand All @@ -180,7 +180,7 @@
"concurrency_group": "metering-billing-platform-hourly-review-repair",
},
],
"53 * * * *": [
"53 13 * * *": [
{
"name": "bandscope",
"target_repository": "ContextualWisdomLab/bandscope",
Expand All @@ -189,7 +189,7 @@
"concurrency_group": "bandscope-hourly-review-repair",
},
],
"56 * * * *": [
"56 14 * * *": [
{
"name": "inkspan",
"target_repository": "ContextualWisdomLab/inkspan",
Expand All @@ -198,7 +198,7 @@
"concurrency_group": "inkspan-hourly-review-repair",
},
],
"58 * * * *": [
"58 15 * * *": [
{
"name": "orgmetra",
"target_repository": "ContextualWisdomLab/Orgmetra",
Expand All @@ -207,7 +207,7 @@
"concurrency_group": "orgmetra-hourly-review-repair",
},
],
"59 * * * *": [
"59 16 * * *": [
{
"name": "semantic-data-portal",
"target_repository": "ContextualWisdomLab/semantic-data-portal",
Expand Down
26 changes: 24 additions & 2 deletions tests/test_noema_orchestrator_workflow_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ def test_noema_close_cleanup_selects_only_the_closed_pr_across_shared_display_ti
) -> None:
"""Execute cleanup against a shared-head-SHA fixture and cancel only the closed PR.

The `cancel-closed-pr-runs` job/step retained their names, but PR #1869
("retire review scans when PRs return to draft") generalized this step
to also cover `converted_to_draft`, renaming it to "...for the inactive
pull request" and adding a `live_target_matches` re-verification against
the live PR (mirroring `strix.yml`'s identical job) before every
cancellation pass. This fixture drives that live lookup to a `closed`
PR #7 at the fixture's shared head SHA so the protected invariant below
is exercised exactly as before.

Real jq/bash execution (not text-grepping): PR #7 (closing) and PR #8
(unrelated, open) both have runs on the same head commit; only #7's
matches the PR-scoped selector cancel_runs applies, and a `completed`
Expand All @@ -36,7 +45,7 @@ def test_noema_close_cleanup_selects_only_the_closed_pr_across_shared_display_ti
script = textwrap.dedent(
workflow_step(
workflow_text("noema-review.yml"),
"Cancel queued and running Noema reviews for the closed pull request",
"Cancel queued and running Noema reviews for the inactive pull request",
).split(" run: |\n", 1)[1].split("\n noema-review:", 1)[0]
)
workflow_path = ".github/workflows/noema-review.yml"
Expand Down Expand Up @@ -89,6 +98,13 @@ def test_noema_close_cleanup_selects_only_the_closed_pr_across_shared_display_ti
runs_file = tmp_path / "runs.json"
runs_file.write_text(json.dumps(runs), encoding="utf-8")
calls_file = tmp_path / "calls.txt"
# The closing PR's live state, returned by the `live_target_matches`
# re-verification `cancel_runs` performs before every status query and
# before every individual cancellation (added by PR #1869 alongside the
# `converted_to_draft` generalization; mirrors strix.yml's identical
# job). Head SHA matches the fixture runs above so the closed-PR-#7
# cleanup is verified live and proceeds exactly as before that change.
live_pr_json = json.dumps({"state": "closed", "draft": False, "head": {"sha": "a" * 40}})
fake_gh = tmp_path / "gh"
fake_gh.write_text(
"""#!/usr/bin/env bash
Expand All @@ -100,6 +116,9 @@ def test_noema_close_cleanup_selects_only_the_closed_pr_across_shared_display_ti
status="$(printf '%s' "$url" | sed -E 's/.*status=([a-z_]+)&.*/\\1/')"
jq --arg status "$status" '{workflow_runs: [.workflow_runs[] | select(.status == $status)]}' \\
"$FAKE_RUNS_FILE"
elif [[ "$*" == *"/pulls/"* ]]; then
printf '%s\n' "$*" >>"$FAKE_CALLS_FILE"
printf '%s\n' "$FAKE_LIVE_PR_JSON"
else
printf '%s\n' "$*" >>"$FAKE_CALLS_FILE"
fi
Expand All @@ -113,10 +132,13 @@ def test_noema_close_cleanup_selects_only_the_closed_pr_across_shared_display_ti
**os.environ,
"PATH": f"{tmp_path}{os.pathsep}{os.environ.get('PATH', '')}",
"TARGET_REPOSITORY": "ContextualWisdomLab/demo",
"CLOSED_PR_NUMBER": "7",
"INACTIVE_PR_NUMBER": "7",
"INACTIVE_PR_HEAD_SHA": "a" * 40,
"PR_ACTION": "closed",
"CURRENT_RUN_ID": "999",
"FAKE_RUNS_FILE": str(runs_file),
"FAKE_CALLS_FILE": str(calls_file),
"FAKE_LIVE_PR_JSON": live_pr_json,
},
capture_output=True,
text=True,
Expand Down
1 change: 1 addition & 0 deletions tests/test_strix_rerun_job_selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def record_rerun(repo: str, job_id: str, *, dry_run: bool, action: str) -> None:
reruns.append((repo, job_id, action))

monkeypatch.setattr(sched, "rerun_actions_job", record_rerun)
monkeypatch.setattr(sched, "fetch_pr", lambda *_args: [pr])

assert (
sched.dispatch_strix_evidence(
Expand Down
Loading