Skip to content

fix(reorg): unbreak main — flake_path pin, workflow entrypoints, fail-closed review-gate - #154

Merged
luna-whymage merged 1 commit into
mainfrom
fix/reorg-followup
Oct 21, 2026
Merged

luna-whymage merged 1 commit into
mainfrom
fix/reorg-followup

Conversation

@branben

@branben branben commented Oct 21, 2026 •

Copy link
Copy Markdown
Owner

What

Follow-up to #152 (merged as 166b490). The reorg left four breakages sitting uncommitted in the working tree, so they never made it into the merge. main is red because of one of them.

Closes the red CI on main and on school/1nzr-behaviour (both fail on the same test).

The four breakages

1. main is RED — one failure class, all three legs

tests/test_review_build_gate.py::test_build_verify_pins_flake_to_director_checkout
AssertionError: assert PosixPath('.../school-core') == PosixPath('.../school-core/src/core')

The test asserts the pre-reorg value, Path(director.__file__).resolve().parent. director.py now lives at src/core/director.py, so its package dir is src/core — which has no flake.nix. The verify gate would silently skip its flake check.

Rewritten to pin the repo root: asserts (flake_dir / "flake.nix").exists() and that flake_dir is not the module's own package dir (the cwd-dependence the test was originally guarding against).

2. school-loop.yml invoked five moved modules by pre-move root paths

The workflow was broken silently — it does not run on PRs, so nothing surfaced it.

Line Before After
149 from school_mail import ... from src.tools.school_mail import ...
374 python orca_precondition.py python src/crew/orca_precondition.py
405 python gateway_preflight.py python src/tools/gateway_preflight.py
424 python worktree_bloat_guard.py python src/tools/worktree_bloat_guard.py
495 python crew_ledger_reconcile.py python src/crew/crew_ledger_reconcile.py

3. ci.yml:293 imported school_mail by its pre-move path

from school_mail import notify_build_failure → from src.tools.school_mail import notify_build_failure.

4. The review-gate fail-open — the PR's only REQUIRED check

ci.yml passed --head "origin/${{ github.event.pull_request.head.sha }}", which is not a ref name. git diff failed on stderr, the error was discarded, and the gate read stdout only — so it reported 0 changed files and PASSed on every PR since #117.

  • scripts/review_gate.py: git() now raises on non-zero exit; new resolve_ref() verifies each ref with rev-parse before diffing; an empty diff is now a failure, not a pass.
  • ci.yml: both invocations now pass --head "HEAD".

Verification

Check Result
tests/test_review_build_gate.py (RED on main) 7 passed in 0.28s
tests/test_review_gate.py (+4 regression tests) 15 passed in 4.36s
review_gate.py --base origin/main --head HEAD 5 changed files, 118 added lines, PASS (was 0 files / silent PASS)
workflow entrypoints resolve all 5 targets exist on disk
YAML valid

The 4 new gate tests were RED-verified against the original gate: the failure text is the #117 bug verbatim — review-gate: 0 changed file(s), 0 added line(s) / PASS - all mechanical checks clean.

Why main went red without anyone noticing

review-gate is the only required check, and it was fail-open. A green review-gate on main was not evidence the tree was sound — it was evidence the gate could not see the tree. This PR closes that.

Not included

  • ci.yml's ruff CORE= list still names onboard.py and a2a_bridge.py, which no longer exist. Harmless (ruff warns and exits 0) but a silent scope shrink — separate cleanup.
  • The behaviour batch (conductor.py, issue_bridge.py, tests/test_conductor_issue_path.py, tests/test_issue_bridge.py) belongs on school/1nzr-behaviour per bb1b968's split.

Summary by Sourcery

Restore post-reorganization workflow paths and make the required review gate fail closed instead of silently passing invalid or empty diffs.

Bug Fixes:

  • Restore workflow and CI entrypoints after the source-tree reorganization.
  • Prevent the review gate from passing when Git refs cannot be resolved or when no changes are detected.
  • Correct the build verification test to validate the repository flake configuration rather than the moved module directory.

Enhancements:

  • Make review-gate Git operations fail closed with explicit ref validation and empty-diff reporting.

CI:

  • Update CI and school-loop workflows to use the relocated Python modules and run the review gate against the checked-out HEAD.

Tests:

  • Add regression coverage for unresolvable refs and empty diffs, and update the build-gate test for the reorganized source layout.

RetriggerView in GreptileConfidence Score: 4/5

Fix the cache commands before merging; both workflow jobs still fail at the cache refresh.

Findings

  1. P1 Cache refresh still fails ▶
  2. P2 Checkout pin loses coverage ▶
Fix with agent prompt
### Issue 1
.github/workflows/school-loop.yml:462
Both cache steps run `python src/tools/populate_board_cache.py`, which puts `src/tools`, not the checkout root, on Python's import path. The script then fails at `from src.tools.repo_default import default_repo` with `ModuleNotFoundError: No module named 'src'`. Neither job installs the project or sets `PYTHONPATH`, so later steps that execute issues or publish the board are skipped.

Use `python -m src.tools.populate_board_cache` in both steps, keeping `.venv/bin/python` in this job.

### Issue 2
tests/test_review_build_gate.py:175-180
The replacement assertions no longer prove that `flake_path` points to the checkout containing `director.py`. A regression to `Path.cwd()` passes when tests run from the repository root: that directory contains `flake.nix` and differs from `src/core`. This leaves the original working-directory bug unguarded.

Keep an exact comparison with the root derived from `director.__file__`, alongside the existence check. Changing to an unrelated directory during the test would also exercise the behavior its docstring promises.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

This PR fixes workflow paths after the reorganization and makes the review gate reject Git failures and empty diffs.

  • The review gate checks real commit refs and rejects empty diffs.
  • GitHub Actions calls the Python modules from their new folders.
  • The build-gate test checks the folder that contains flake.nix.

Reviews (1) · Last reviewed commit: "fix(reorg): repoint workflow entrypoints..." · Reviewed by Greptile

…, close the review-gate fail-open

bb1b968 kept #152 reorg-only but carried four unlanded breakages. This lands them.

1. school-loop.yml invoked five moved modules by their PRE-MOVE root paths, so the
   workflow was broken silently (it does not run on PRs):
     :149  from school_mail import ...        -> from src.tools.school_mail import ...
     :374  python orca_precondition.py       -> python src/crew/orca_precondition.py
     :405  python gateway_preflight.py       -> python src/tools/gateway_preflight.py
     :424  python worktree_bloat_guard.py    -> python src/tools/worktree_bloat_guard.py
     :495  python crew_ledger_reconcile.py   -> python src/crew/crew_ledger_reconcile.py
   Verified: all five targets exist on disk; no bare root-path invocation remains.

2. ci.yml:293 imported school_mail by its pre-move path -> src.tools.school_mail.

3. tests/test_review_build_gate.py:170 asserted the PRE-REORG value
   (Path(director.__file__).resolve().parent). director.py now lives at
   src/core/director.py, so its package dir is src/core, which has no flake.nix --
   the verify gate would silently skip its flake check. Rewritten to pin the repo
   root: asserts (flake_dir / "flake.nix").exists() and that flake_dir is NOT the
   module's own package dir.
   Verified: 7 passed in 0.28s (was RED on bb1b968).

4. review-gate fail-open (the PR's only REQUIRED check). ci.yml passed
   --head "origin/${{ github.event.pull_request.head.sha }}" -- not a ref name.
   git diff failed on stderr, the error was discarded, and the gate read stdout
   only, so it reported 0 changed files and PASSed on every PR since #117.
   - scripts/review_gate.py: git() now raises SystemExit on non-zero exit; new
     resolve_ref() verifies each ref with rev-parse before diffing; an empty diff
     is now a FAILURE, not a pass.
   - ci.yml: both invocations now pass --head "HEAD".
   Verified RED->GREEN: unresolvable ref exit 1 (was exit 0 + silent PASS);
   empty diff exit 1 [empty-diff]; real head exit 0; --head HEAD exit 0.
   tests/test_review_gate.py: +4 regression tests, 15 passed in 7.00s.

NOT included here (deliberately): the behaviour batch -- conductor.py,
issue_bridge.py, tests/test_conductor_issue_path.py, tests/test_issue_bridge.py
-- which belongs on school/1nzr-behaviour per bb1b968's split.

Also NOT fixed: ci.yml's ruff CORE= list still names onboard.py and a2a_bridge.py,
which no longer exist. Harmless -- ruff warns and exits 0 -- but a silent scope
shrink; tracked separately.
@sourcery-ai

sourcery-ai Bot commented Oct 21, 2026

Copy link
Copy Markdown

Sorry @branben, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 5 hours by commenting @sourcery-ai review. Upgrade to get a review now.

@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing

@sourcery-ai

sourcery-ai Bot commented Oct 21, 2026

Copy link
Copy Markdown

Reviewer's Guide

This PR repairs the post-reorganization CI and workflow breakages by correcting moved-module paths, pinning build verification to the repository root, and replacing the review gate’s fail-open ref/diff handling with explicit validation and failure behavior.

Sequence diagram for the fail-closed review gate

sequenceDiagram
    participant CI
    participant Gate as review_gate.py
    participant Git

    CI->>Gate: main(--base origin/main, --head HEAD)
    Gate->>Git: rev-parse --verify base^{commit}
    Git-->>Gate: base commit
    Gate->>Git: rev-parse --verify head^{commit}
    Git-->>Gate: head commit
    Gate->>Git: diff base...head
    Git-->>Gate: changed files and added lines
    Gate-->>CI: PASS or mechanical-check failures

    alt ref cannot be resolved
        Git-->>Gate: non-zero exit
        Gate-->>CI: FAIL with git/ref error
    else no changed files
        Gate-->>CI: FAIL with empty-diff error
    end
Loading

File-Level Changes

Change Details Files
Make the review gate fail closed and ensure CI invokes it with a resolvable checkout ref.
  • Raise on failed git commands and validate base/head refs before diffing.
  • Treat an empty resolved diff as a gate failure and cover invalid refs and JSON reporting with regression tests.
  • Change both CI gate invocations from the invalid PR-head SHA pseudo-ref to HEAD.
scripts/review_gate.py
.github/workflows/ci.yml
tests/test_review_gate.py
Restore workflow compatibility with the post-reorganization source layout.
  • Update moved Python imports and executable entrypoints to their src/tools and src/crew paths.
  • Update related workflow comments and board-cache invocations to reflect relocated files.
.github/workflows/ci.yml
.github/workflows/school-loop.yml
Correct the build verification test to assert flake configuration is pinned to the repository root.
  • Require the captured flake path to contain flake.nix.
  • Ensure it is distinct from director.py's package directory after the src/core move.
tests/test_review_build_gate.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help


- name: Populate issue cache from GitHub
run: .venv/bin/python populate_board_cache.py
run: .venv/bin/python src/tools/populate_board_cache.py

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Cache refresh still fails

Both cache steps run python src/tools/populate_board_cache.py, which puts src/tools, not the checkout root, on Python's import path. The script then fails at from src.tools.repo_default import default_repo with ModuleNotFoundError: No module named 'src'. Neither job installs the project or sets PYTHONPATH, so later steps that execute issues or publish the board are skipped.

Use python -m src.tools.populate_board_cache in both steps, keeping .venv/bin/python in this job.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/school-loop.yml
Line: 462

Comment:
**Cache refresh still fails**

Both cache steps run `python src/tools/populate_board_cache.py`, which puts `src/tools`, not the checkout root, on Python's import path. The script then fails at `from src.tools.repo_default import default_repo` with `ModuleNotFoundError: No module named 'src'`. Neither job installs the project or sets `PYTHONPATH`, so later steps that execute issues or publish the board are skipped.

Use `python -m src.tools.populate_board_cache` in both steps, keeping `.venv/bin/python` in this job.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment on lines +175 to +180
assert (flake_dir / "flake.nix").exists(), (
f"flake_path {flake_dir} does not contain flake.nix — "
f"the verify gate would silently skip its flake check"
)
# And it must NOT be the module's own package directory (cwd-dependence).
assert flake_dir != Path(director.__file__).resolve().parent

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Checkout pin loses coverage

The replacement assertions no longer prove that flake_path points to the checkout containing director.py. A regression to Path.cwd() passes when tests run from the repository root: that directory contains flake.nix and differs from src/core. This leaves the original working-directory bug unguarded.

Keep an exact comparison with the root derived from director.__file__, alongside the existence check. Changing to an unrelated directory during the test would also exercise the behavior its docstring promises.

Prompt To Fix With AI
This is a comment left during a code review.
Path: tests/test_review_build_gate.py
Line: 175-180

Comment:
**Checkout pin loses coverage**

The replacement assertions no longer prove that `flake_path` points to the checkout containing `director.py`. A regression to `Path.cwd()` passes when tests run from the repository root: that directory contains `flake.nix` and differs from `src/core`. This leaves the original working-directory bug unguarded.

Keep an exact comparison with the root derived from `director.__file__`, alongside the existence check. Changing to an unrelated directory during the test would also exercise the behavior its docstring promises.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@luna-whymage luna-whymage left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVE.

All three pytest legs are green (py3.9 4m21s, py3.11 3m56s, py3.12 4m15s) — including tests/test_review_build_gate.py::test_build_verify_pins_flake_to_director_checkout, which is RED on main and on school/1nzr-behaviour. This PR is the fix for both.

Verified locally on top of main (5a1fdb3):

  • tests/test_review_build_gate.py — 7 passed in 0.28s
  • tests/test_review_gate.py — 15 passed in 4.36s
  • review_gate.py --base origin/main --head HEAD — 5 changed files, 118 added lines, PASS. The same invocation reported 0 changed file(s) and PASSed before the fail-closed fix, which is why main went red without the required check noticing.

Scope check: this PR touches exactly the four reorg-fallout items — the flake_path repo-root pin, the five school-loop.yml entrypoint repoints, the ci.yml school_mail import, and the review-gate fail-closed. The behaviour batch is correctly excluded; it belongs on school/1nzr-behaviour.

Non-blocking note: ci.yml's ruff CORE= list still names onboard.py and a2a_bridge.py, which no longer exist. Harmless — ruff warns and exits 0 — but a silent scope shrink, tracked separately.

@luna-whymage
luna-whymage merged commit 1054fee into main Oct 21, 2026
10 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants