Repository navigation
Move the rollback workflow's steps into tested scripts and enforce the one-line run: rule - #1006
Merged
Merged
Conversation
anth-volk
force-pushed
the
sim-rollback-workflow-scripts
branch
from
November 4, 2026 15:11
0f45cd0 to
063fe6d
Compare
anth-volk
added a commit
that referenced
this pull request
Nov 4, 2026
Review of #1006 found that [ci_scripts] could list a baseline file again for a check whose rule is enforced, and the entries in it would be tolerated: validate checks only that a listed file exists, and guard compares only [rule.baseline] counts. The same holds for the two other enforced checks, whose listed baselines are empty. - A new validation test fails: an enforced check's listed baseline holds an entry, and validate reports nothing. Tests that an enforced check may list an empty baseline, and a ratcheted one may list entries, pass. - The write-baselines command test now expects the message to say that a check without a baseline in [ci_scripts] is not recorded, and fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Nov 4, 2026
Review of #1006: - python -m scripts.rules validate, which the rules-registry guard runs, now fails when [ci_scripts] lists a baseline with an entry for a check whose rule is enforced. Before, an entry added there was tolerated, because validate checked only that the file exists and guard compares only [rule.baseline] counts. An enforced check may list no baseline or an empty one; a ratcheted check may list entries. - ci-scripts --write-baselines says that a check without a baseline in [ci_scripts] is not recorded. - docs/engineering/skills/ci-workflows.md says the two listed empty baselines stay empty because validate refuses entries in them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Nov 4, 2026
Review round 2 of #1006 found no defect and noted that, with the scripts' set -u, a variable the rollback job stopped setting would now fail the scripts, while every test passed because the tests set the variables themselves. A test now pins the job's env:. The CiScripts docstring says what the rules tool requires: a check may leave its baseline out, and an enforced check lists none or an empty one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
force-pushed
the
sim-rollback-workflow-scripts
branch
from
November 4, 2026 16:51
802ff23 to
bb9061d
Compare
anth-volk
added a commit
that referenced
this pull request
Nov 4, 2026
Review of #1006 found that [ci_scripts] could list a baseline file again for a check whose rule is enforced, and the entries in it would be tolerated: validate checks only that a listed file exists, and guard compares only [rule.baseline] counts. The same holds for the two other enforced checks, whose listed baselines are empty. - A new validation test fails: an enforced check's listed baseline holds an entry, and validate reports nothing. Tests that an enforced check may list an empty baseline, and a ratcheted one may list entries, pass. - The write-baselines command test now expects the message to say that a check without a baseline in [ci_scripts] is not recorded, and fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Nov 4, 2026
Review of #1006: - python -m scripts.rules validate, which the rules-registry guard runs, now fails when [ci_scripts] lists a baseline with an entry for a check whose rule is enforced. Before, an entry added there was tolerated, because validate checked only that the file exists and guard compares only [rule.baseline] counts. An enforced check may list no baseline or an empty one; a ratcheted check may list entries. - ci-scripts --write-baselines says that a check without a baseline in [ci_scripts] is not recorded. - docs/engineering/skills/ci-workflows.md says the two listed empty baselines stay empty because validate refuses entries in them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Nov 4, 2026
Review round 2 of #1006 found no defect and noted that, with the scripts' set -u, a variable the rollback job stopped setting would now fail the scripts, while every test passed because the tests set the variables themselves. A test now pins the job's env:. The CiScripts docstring says what the rules tool requires: a check may leave its baseline out, and an enforced check lists none or an empty one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…failing) Tests for moving the six multi-line run: blocks of simulation-rollback.yml into scripts under .github/scripts/, and for enforcing sim.ci.multiline-run-is-script without a baseline file. - test_simulation_rollback_scripts.py runs each new script with fake uv and gcloud first on PATH, or beside a fake copy of the sibling script it calls, and checks its exact calls, $GITHUB_OUTPUT and exit status. It also checks that each moved step keeps every setting it had (if, id, working-directory and env) and calls its script. - The #744 tests of how the routing restore reads a deployment run's kept plans now run rollback-restore-routing.sh instead of extracting the step's inline shell, and the step lookups read each step with the scripts it calls. - Two rules-tool tests check that [ci_scripts] may leave out a check's baseline: every finding of that check then fails, and writing baselines skips it. - A routing discovery test pins the rollback workflow's two writing steps; it passes before and after the move. Against the current code, 34 entry tests and both rules-tool tests fail. Three rewritten rollback structure tests pass, since they read each step together with its scripts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The six multi-line run: blocks that #744 added to simulation-rollback.yml now live in tested scripts under .github/scripts/, each called from a single-command step: - rollback-restore-routing.sh: Restore Modal routing - rollback-resolve-pending-publication.sh: Resolve the unfinished routing publication - rollback-read-release-identity.sh: Read the restored release identity - rollback-stable-service-state.sh: Resolve the stable service - rollback-restore-entrypoint-traffic.sh: Restore entrypoint traffic - rollback-verify-stable-service.sh: Verify the stable service serves the restored release Four script bodies are the old inline shell unchanged. The traffic restore and the verification call their sibling scripts through the script's own directory instead of a path from the repository root. The scripts add set -u; every variable they read is set by the job or step env: or by the runner. Every step keeps its if, id, working-directory and env, so the identity and service outputs and exit statuses are unchanged. As before, the stable service step records url=null or an empty revision instead of failing when jq finds no URL or no single revision at 100 percent; its script says so. With the baseline empty, sim.ci.multiline-run-is-script is enforced: rules/baselines/ci-multiline-run.txt is deleted, the rule loses its [rule.baseline], and [ci_scripts] lists no baseline for the check. The rules tool now lets [ci_scripts] leave out a check's baseline, and then fails on every finding of it. docs/engineering/skills/ci-workflows.md describes the enforcement. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #1006 found that [ci_scripts] could list a baseline file again for a check whose rule is enforced, and the entries in it would be tolerated: validate checks only that a listed file exists, and guard compares only [rule.baseline] counts. The same holds for the two other enforced checks, whose listed baselines are empty. - A new validation test fails: an enforced check's listed baseline holds an entry, and validate reports nothing. Tests that an enforced check may list an empty baseline, and a ratcheted one may list entries, pass. - The write-baselines command test now expects the message to say that a check without a baseline in [ci_scripts] is not recorded, and fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #1006: - python -m scripts.rules validate, which the rules-registry guard runs, now fails when [ci_scripts] lists a baseline with an entry for a check whose rule is enforced. Before, an entry added there was tolerated, because validate checked only that the file exists and guard compares only [rule.baseline] counts. An enforced check may list no baseline or an empty one; a ratcheted check may list entries. - ci-scripts --write-baselines says that a check without a baseline in [ci_scripts] is not recorded. - docs/engineering/skills/ci-workflows.md says the two listed empty baselines stay empty because validate refuses entries in them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 2 of #1006 found no defect and noted that, with the scripts' set -u, a variable the rollback job stopped setting would now fail the scripts, while every test passed because the tests set the variables themselves. A test now pins the job's env:. The CiScripts docstring says what the rules tool requires: a check may leave its baseline out, and an enforced check lists none or an empty one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
force-pushed
the
sim-rollback-workflow-scripts
branch
from
November 4, 2026 16:56
bb9061d to
b64dca0
Compare
anth-volk
marked this pull request as ready for review
November 5, 2026 13:00
anth-volk
added a commit
that referenced
this pull request
Nov 5, 2026
Brings in #1006, which moved the rollback workflow's steps into scripts and enforced sim.ci.multiline-run-is-script, and the release commit after it. The only conflict was docs/generated/rules.md, in the list of ratcheted rules: main removed the multiline rule's line, and this branch removed the weight-stripping rule's line. The file is regenerated with python -m scripts.rules render from the merged registry, in which both rules are enforced with no baseline, so the list is empty. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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 #1005
Same-Repository Draft PR Check
PolicyEngine/policyengine-sim-api, not a personal fork.Changelog
changelog.d/<name>.<type>.md, whose type is breaking, added, changed, fixed or removed.Summary
Phase 1 step 1.7, last part. Stacked on #1004, which moves the deploy workflow's seven blocks and teaches the routing writer discovery to read the scripts a step calls.
The six multi-line
run:blocks that #744 added tosimulation-rollback.ymlnow live in tested scripts under.github/scripts/, each called from a single-command step:rollback-restore-routing.shrollback-resolve-pending-publication.shrollback-read-release-identity.shrollback-stable-service-state.shrollback-restore-entrypoint-traffic.shrollback-verify-stable-service.shWith the baseline then empty,
sim.ci.multiline-run-is-scriptis enforced:rules/baselines/ci-multiline-run.txtis deleted, the rule loses its[rule.baseline], and[ci_scripts]lists no baseline for the check, so any multi-linerun:block in a workflow fails thequality-guardsjob. The rules tool now lets[ci_scripts]leave out a check's baseline (scripts/rules/model.py,load.py,ci_scripts.py): every finding of that check then fails, and--write-baselinesskips it and says so.python -m scripts.rules validate, which therules-registryguard runs, also fails when[ci_scripts]lists a baseline with an entry for a check whose rule is enforced, so neither this rule's baseline nor the two empty ones listed for the other enforced checks can tolerate a finding again.docs/engineering/skills/ci-workflows.mddescribes the enforcement.Behaviour is unchanged. A PyYAML comparison of the workflow on
mainand on this branch shows identical top-level keys, job settings and step keys other thanrun:; only these six steps'run:text differs. Four script bodies are the old inline shell, byte for byte. The traffic restore and the verification call their sibling scripts (set-cloud-run-simulation-entry-revision.sh,cloud-run-simulation-entry-smoke.sh) through the script's own directory instead of a path from the repository root. The scripts addset -u; every variable they read is set by the job or stepenv:or by the runner. The step IDsidentityandserviceand the outputs later steps read are written by the same commands.Kept as it was, for a follow-up: "Resolve the stable service" writes
url=$(jq -er …)andrevision=$(jq -er …)insideechoarguments, where a failingjqdoes not stop abash -eshell. Without a URL it recordsurl=null, and without exactly one revision at 100 percent it records an empty revision, and the step succeeds. The script keeps this, says so in a comment, andtest_stable_service_records_what_jq_prints_when_a_value_is_missingpins it. Failing the step there would be a behaviour change, so it is not made here.Tests.
test_simulation_rollback_scripts.pyruns each new script with fakeuvandgcloudfirst onPATH(jq is real), or as a copy beside a fake sibling script that records its arguments and environment, and checks the exact calls,$GITHUB_OUTPUTand exit status. It also checks that each moved step keeps every setting it had and calls its script.test_simulation_rollback.py) now runrollback-restore-routing.shinstead of extracting the step's inline shell, and the step lookups read each step with the scripts it calls.Environment variables
Every variable the scripts read, and where it comes from. The job and step
env:blocks are unchanged.MODAL_TOKEN_ID,MODAL_TOKEN_SECRETenv:.GH_TOKENrollback-restore-routing.sh(read bygh)${{ github.token }}in the step'senv:; the job grantsactions: readfor the run and job lookups.TARGET,DEPLOY_RUN_ID,POLICYENGINE_VERSION,EXPECTED_LATEST,MODAL_ENVIRONMENT,SERVICEenv:, from theworkflow_dispatchinputs.PROJECT_ID,REGIONrollback-stable-service-state.sh; also passed to the traffic script asSIMULATION_ENTRYPOINT_GCP_*env:, from thebetaandprodenvironment variablesSIMULATION_ENTRYPOINT_GCP_PROJECT_IDandSIMULATION_ENTRYPOINT_GCP_REGION(region defaults tous-central1). The job setsenvironment: ${{ inputs.target }}, andtargetisbetaorprod.SIMULATION_ENTRYPOINT_*rollback-restore-entrypoint-traffic.shenv:, from the jobenv:, theentrypoint_revisioninput and stepservice'srevisionoutput.EXPECTED_*,STABLE_URL,EXPECTED_REVISION,PREVIOUS_REVISIONrollback-verify-stable-service.shenv:, from stepsidentityandserviceand theentrypoint_revisioninput.gcloudgoogle-github-actions/authwith thebetaandprodenvironment secretsSIMULATION_ENTRYPOINT_GCP_WIF_PROVIDERandSIMULATION_ENTRYPOINT_GCP_DEPLOY_SERVICE_ACCOUNT.GITHUB_REPOSITORY,RUNNER_TEMP,GITHUB_OUTPUTTesting
--write-baselinesmessage, and the fourth makes them pass:projects/policyengine-simulation-entry: the tests intest_simulation_rollback_scripts.py, the rewritten tests intest_simulation_rollback.py, the rollback writers test and the routing discovery tests intest_routing_workflow_invariants.py, andtest_deployment_assets_routing.py::test_a_failing_routing_command_fails_its_step_and_joband::test_routing_jobs_never_allow_command_failures(157 passed).scripts/rules/tests/test_ci_scripts.py:CompareTest.test_a_check_without_a_baseline_fails_every_finding,CompareTest.test_writing_baselines_skips_a_check_without_oneand the threeEnforcedCheckBaselineTesttests;scripts/rules/tests/test_cli.py:CiScriptsCommandTest.test_write_baselines_records_the_findings.python -m scripts.rules ci-scriptspasses with no baseline file;python scripts/run_quality_guards.py,python -m scripts.rules validateandpython -m scripts.rules guard --base-ref origin/mainpass.shellcheckandactionlintpass on the new scripts and the workflow.🤖 Generated with Claude Code