Repository navigation
Conversation
Changes to the rules registry, guard scripts and CODEOWNERS itself need review from a core developer other than the author. Deliberately narrow: pyproject.toml and workflow files are not owned. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The lint jobs ran `pip install ruff>=0.9.0` unquoted, so the shell read `>` as a redirect and CI installed the latest ruff. Install the version pinned in uv.lock instead, and select ruff's current default rules explicitly so an upgrade cannot change which rules apply. No rules are added or removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The four boundary checks listed their modules by hand, so the households and user_households packages (12 modules) were never checked. Discover the modules by filename instead, fail at collection if a pattern matches nothing, and require every connector module to be a recognised create, read, update or delete module so a new name cannot escape the checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every PR needs a tracking issue and `Fixes #ISSUE_NUMBER` as the first line of its description; a PR template starts with that line. Agents must never bypass branch rules, even with admin credentials. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Draft
2 tasks done
Multi-line workflow run blocks become tested shell scripts. The lint jobs now run .github/scripts/install_locked_ruff.sh, which reads ruff's version from uv.lock and installs it, and tests cover the lock lookup, the default lock, a missing pin and a failing pip. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added this pull request to stack #3888
October 12, 2026 19:28
This was referenced Oct 12, 2026
Draft
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #3887 +/- ##
===========================================
+ Coverage 45.22% 87.56% +42.33%
===========================================
Files 183 198 +15
Lines 11073 12211 +1138
Branches 1905 2159 +254
===========================================
+ Hits 5008 10692 +5684
+ Misses 5644 922 -4722
- Partials 421 597 +176 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
GitHub runs pull_request workflows for every PR in a stack as if each targeted the trunk, so a nine-PR stack ran the whole workflow nine times. Every job without needs now carries the stack condition, and the jobs that need them are skipped with them. A new CI complete job needs every other job and is meant to be the single required check. A skipped job counts as passing, so the gate fails on any stacked PR above the lowest unmerged one, and otherwise passes only when every job passed. Stacks therefore merge bottom-up, and nothing merges untested. check_ci_complete.sh holds the gate logic, and tests/unit/test_ci_complete_gate.py tests it and checks that every job is needed by the gate and carries the condition. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test_pr_always_runs_reusable_alembic_and_v2_integration_checks forbade any if: on the Alembic v2 and cross-database jobs, so they could never be skipped. They now carry the stacked-PR condition like every other job: they still run on every PR that isn't stacked and on the lowest unmerged PR of a stack, and CI complete, which needs them, fails on the rest. The test now allows exactly that condition and nothing else. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch is pending to be deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3886
Summary
Phase 0 of the rules workstream: make CI enforcement trustworthy before the rules registry (#3884, kept as a draft until this merges). The sim counterpart is PolicyEngine/policyengine-sim-api#754.
rules/,scripts/rules/,scripts/guards/,scripts/run_quality_guards.pyand CODEOWNERS itself, owned by@PolicyEngine/core-developers.pyproject.tomland workflow files are not owned, so dependency bots and everyday CI edits aren't blocked. The paths for the registry take effect once Add a rules registry that makes every enforced and unenforced rule visible #3884 creates them.pr.ymlandpush.ymlranpip install ruff>=0.9.0unquoted, so the shell read>as a redirect and CI installed the latest ruff. They now run.github/scripts/install_locked_ruff.sh, which installs the version pinned inuv.lock(currently 0.15.12) and prints it. Following the workstream's CI rule, the multi-line logic lives in a tested script, and the workflow step is a single line.[tool.ruff.lint] select = ["E4", "E7", "E9", "F"]makes ruff's current defaults explicit. No rules are added or removed. Stricter ruff comes in separate PRs right after the registry lands.test_data_crud_boundaries.pydiscovers modules by filename instead of listing them, sohouseholdsanduser_households(12 modules) are checked for the first time. Discovery fails at collection if a pattern matches nothing, because pytest silently skips an empty parameter list. A new test requires every connector module to be a recognised create, read, update or delete module.github-prs.mdnow requires a tracking issue andFixes #ISSUE_NUMBERon the first line of the PR description, and a new PR template starts with that line. Agents must never bypass branch rules (for examplegh pr merge --admin), even with admin credentials;AGENTS.mdpoints to both.pull_requestworkflows for every PR in a native stack as if each targetedmaster, so a nine-PR stack ran this whole workflow nine times.pr.ymljob withoutneedsnow runs only when the PR isn't stacked, or is the lowest unmerged one (github.event.pull_request.stack.base.ref == github.event.pull_request.base.ref). Jobs that need them are skipped with them.CI completejob needs every other job and runs withif: always(). A skipped job would count as passing a required check, so the gate fails on stacked PRs above the bottom, and otherwise passes only when every job passed. Stacks therefore merge bottom-up, and nothing merges untested..github/scripts/check_ci_complete.sh.tests/unit/test_ci_complete_gate.pytests it and checks that every job is needed by the gate and carries the condition.github-prs.mddocuments it, including what to do if no run starts when a PR reaches the bottom.test_alembic_workflows.pyused to forbid anyif:on the Alembic v2 and cross-database jobs, so they could never be skipped. It now allows exactly the stacked-PR condition and nothing else.JOB_RESULTS(toJSON(needs)),PULL_REQUEST_BASE_REFandSTACK_BASE_REF. All three come from GitHub Actions contexts and are set in that step'senv:. No secrets are involved.Step 0.1 is not in this PR. It makes
CI completethe single required check and turns on code-owner review in themainruleset. That's a ruleset change, applied separately after merge.Testing
pytest tests/unit/v2/test_data_crud_boundaries.py: 40 tests pass, covering 39 discovered modules (previously 27) plus the classification test.import sqlalchemytoservices/v2/households/validators.pymakes the households case fail. Before this change, nothing checked that module.writes.pymakes the classification test fail.pytest tests/unit/test_install_locked_ruff_script.py: 4 tests pass, using fakepipandruff. They cover the locked version, the repository's own lock as the default, a missing pin (fails without installing) and a failingpip. The script also passesshellcheck, and a real run against the repo's lock in a throwaway venv installs ruff 0.15.12.0.15.12from the lock.ruff format --check .andruff check .both pass.ruff check .with ruff 0.16.8 and the explicit select also passes. With 0.16.8's own defaults, it would report 867 errors.python scripts/run_quality_guards.pyandtests/unit/test_alembic_skill.pypass.make testselection passes: 2,402 tests.pytest tests/unit/test_ci_complete_gate.py: 8 tests pass. They cover the workflow shape, a non-stacked PR, the bottom of a stack, a PR higher in a stack, failed, cancelled and skipped jobs, and missing input. The gate script passesshellcheck.actionlintreports nothing on the changed workflows.🤖 Generated with Claude Code