feat(gate): refuse a push from main when the lane says pull request #332

Merged
coilysiren merged 1 commit from eng/gate-knows-the-lane into main 2026-08-13 10:00:24 +00:00
Member

The repository declares its workflow in .ward/ward.yaml and nothing read it, so an agent can violate the lane with every check green.

I did exactly that, twice, thirty minutes after 17aa7b8 landed. That is #329, which I filed against myself.

gate: this repository is on the pull-request-and-merge lane, so main is not a
  branch to push. Create one, then open a pull request:
    git switch -c <owner>/<topic>

It fires at the moment of the mistake, which is the property the four red mains and this lane breach have all lacked: a correct rule, written down, with nothing enforcing it where the mistake happens.

Read from ward.yaml rather than hardcoded, so a repository on the direct lane is unaffected and one that switches later needs no second edit. The test skips itself when the declaration is not the pull-request lane, for the same reason.

On me writing this. I said on 329 that a guard written by the offender to make their own mistake impossible should be reviewed by someone else, and I meant it. That objection is answered by the lane itself — this arrives as a pull request, so someone else merges it. Building it and refusing to build it were both worse than building it where the review is structural.

Verified by mutation: removing the block fails TestTheGateReadsTheDeclaredWorkflow by name, and running the gate on main refuses with the switch command.

ward exec gate passes on this branch.

The repository declares its workflow in `.ward/ward.yaml` and nothing read it, so an agent can violate the lane with every check green. **I did exactly that**, twice, thirty minutes after `17aa7b8` landed. That is https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/329, which I filed against myself. ``` gate: this repository is on the pull-request-and-merge lane, so main is not a branch to push. Create one, then open a pull request: git switch -c <owner>/<topic> ``` It fires at the moment of the mistake, which is the property the four red mains and this lane breach have all lacked: a correct rule, written down, with nothing enforcing it where the mistake happens. **Read from `ward.yaml` rather than hardcoded**, so a repository on the direct lane is unaffected and one that switches later needs no second edit. The test skips itself when the declaration is not the pull-request lane, for the same reason. **On me writing this.** I said on 329 that a guard written by the offender to make their own mistake impossible should be reviewed by someone else, and I meant it. That objection is answered by the lane itself — this arrives as a pull request, so someone else merges it. Building it and refusing to build it were both worse than building it where the review is structural. Verified by mutation: removing the block fails `TestTheGateReadsTheDeclaredWorkflow` by name, and running the gate on `main` refuses with the switch command. `ward exec gate` passes on this branch.
feat(gate): refuse a push from main when the lane says pull request
All checks were successful
ci / test (pull_request) Successful in 30s
ci / publish-echo-image (pull_request) Has been skipped
ci / publish-observed (pull_request) Has been skipped
ci / image-build (pull_request) Successful in 16s
27e268a572
The repository declares its own workflow in .ward/ward.yaml and nothing
read it, so an agent could violate the lane with every check green. I did
exactly that twice, thirty minutes after 17aa7b8 landed, which is issue
329.

The gate now reads the declaration and refuses when the branch is main and
the lane is pull-request-and-merge, naming the fix rather than only the
rule. It fires at the moment of the mistake, which is the property four
red mains and one lane breach have all lacked tonight.

Read from ward.yaml rather than hardcoded, so a repository on the direct
lane is unaffected and one that switches later needs no second edit. The
test skips itself when the declaration is not the pull-request lane, for
the same reason.

I said on 329 that a guard written by the offender to make their own
mistake impossible should be reviewed by someone else. That objection is
answered by the lane itself: this arrives as a pull request, so someone
else merges it. Building it and refusing to build it were both worse than
building it where the review is structural.

Verified by mutation. Removing the block fails the test by name, and
running the gate on main refuses with the switch command.

Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-gaming/sirens-echo!332
No description provided.