feat(aosguard): own the merge decision instead of deferring it to Ward #1085

Merged
coilysiren merged 1 commit from aos/claude/wt57-aosguard-owns-merge into main 2026-08-16 03:48:53 +00:00
Owner

The forgejo surface withheld pr merge on the grounds that it "rides Ward's compiled PR workflow gate". That made a capability of this bundle conditional on a second tool existing, which is precisely what aos#778 says AOSguard must not do.

It cost something

An agent holding pr create and no pr merge either strands its work or pushes the merge commit by hand. The hand-push empties the pull request it just opened: base...head collapses the moment main contains head, so the PR renders no diff and reads merged=false.

Six pull requests in coilyco-bridge/deploy went that way today before the cause was diagnosed.

What changed

  • can merge pr on repoMergePullRequest, bounded by the same coily* owner gate every other {owner} leaf carries
  • header no longer calls this "the aos-authored ward bundle"
  • kubectl.kdl no longer claims grants "audit-log through ward" when the audit path is the generated binary's own

Every remaining ward mention in the policy now asserts independence rather than deferring. The ward#NNN citations stay: those are provenance, not reliance.

The vendored contract needed extending

The committed spec is a curated subset (45 paths), not full upstream, and specgen prunes fail-closed:

specgen: prune spec aosguard/forgejo.kdl: operationId "repoMergePullRequest" not found in spec (fail-closed)

Spliced in the POST only, plus MergePullRequestOption. The is-merged GET and cancel-auto-merge DELETE on the same path stay out, because neither is granted. 45 to 46 paths, 70 to 71 definitions, deterministic gzip preserved.

Verified, not assumed

$ aosguard ops forgejo pr merge notcoily r 1 --Do merge
aosguard: argument owner="notcoily" is outside the allowed scope (restrict owner matches [coily*])

Refused before any API call. The verb builds, exposes --Do as required, and branch protection still applies on top.

pre-commit run --all-files green, pytest tests/test_aosguard.py 19 passed, lock and build both clean.

This is an authority expansion

Not a cleanup. Agents that reach this binary can now merge pull requests in coily* repositories. Kai granted it deliberately after I flagged the alternative, which was to keep merge human-only but say so on AOS's own reasoning rather than Ward's.

Landing it ships through the aosguard release train to every host, so I have left the merge to you rather than pushing it myself. Which would also be ironic.

The forgejo surface withheld `pr merge` on the grounds that it *"rides Ward's compiled PR workflow gate"*. That made a capability of this bundle conditional on a second tool existing, which is precisely what aos#778 says AOSguard must not do. ## It cost something An agent holding `pr create` and no `pr merge` either strands its work or pushes the merge commit by hand. The hand-push **empties the pull request it just opened**: `base...head` collapses the moment main contains head, so the PR renders no diff and reads `merged=false`. Six pull requests in `coilyco-bridge/deploy` went that way today before the cause was diagnosed. ## What changed * `can merge pr` on `repoMergePullRequest`, bounded by the same `coily*` owner gate every other `{owner}` leaf carries * header no longer calls this "the aos-authored **ward** bundle" * `kubectl.kdl` no longer claims grants "audit-log through ward" when the audit path is the generated binary's own Every remaining `ward` mention in the policy now **asserts independence** rather than deferring. The `ward#NNN` citations stay: those are provenance, not reliance. ## The vendored contract needed extending The committed spec is a curated subset (45 paths), not full upstream, and specgen prunes fail-closed: ``` specgen: prune spec aosguard/forgejo.kdl: operationId "repoMergePullRequest" not found in spec (fail-closed) ``` Spliced in the **POST only**, plus `MergePullRequestOption`. The is-merged `GET` and cancel-auto-merge `DELETE` on the same path stay out, because neither is granted. 45 to 46 paths, 70 to 71 definitions, deterministic gzip preserved. ## Verified, not assumed ``` $ aosguard ops forgejo pr merge notcoily r 1 --Do merge aosguard: argument owner="notcoily" is outside the allowed scope (restrict owner matches [coily*]) ``` Refused before any API call. The verb builds, exposes `--Do` as required, and branch protection still applies on top. `pre-commit run --all-files` green, `pytest tests/test_aosguard.py` 19 passed, lock and build both clean. ## This is an authority expansion Not a cleanup. Agents that reach this binary can now merge pull requests in `coily*` repositories. Kai granted it deliberately after I flagged the alternative, which was to keep merge human-only but say so on AOS's own reasoning rather than Ward's. Landing it ships through the aosguard release train to every host, so I have left the merge to you rather than pushing it myself. Which would also be ironic.
feat(aosguard): own the merge decision instead of deferring it to Ward
All checks were successful
ci / ward-doctor (pull_request) Successful in 12s
ci / aos-cli-tests (pull_request) Successful in 17s
ci / gate (pull_request) Successful in 50s
c3566f90fa
The forgejo surface withheld `pr merge` on the grounds that "merge rides
Ward's compiled PR workflow gate". That made a capability of this bundle
conditional on a second tool existing, which is the thing aos#778 says AOSguard
must not do.

It was not only untidy. An agent holding `pr create` and no `pr merge` either
strands its work or pushes the merge commit by hand, and the hand-push empties
the pull request it just opened: base...head collapses the moment main contains
head, so the PR renders no diff and reads merged=false. Six pull requests in
coilyco-bridge/deploy went that way today.

Merge is granted now, bounded by the same coily* owner gate every other {owner}
leaf carries rather than by another tool's trusted-owner list. Verified: a
non-coily owner is refused before any API call.

Adding the verb needed the vendored contract extended, since it is a curated
subset rather than full upstream and specgen prunes fail-closed. Spliced in the
POST only, with MergePullRequestOption, leaving the is-merged GET and the
cancel-auto-merge DELETE out because neither is granted.

Also corrects two misattributions found while surveying: the header called this
"the aos-authored ward bundle", and kubectl.kdl claimed grants audit through
Ward when the audit path is the generated binary's own.

Kai granted the authority expansion deliberately.

Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
coilysiren deleted branch aos/claude/wt57-aosguard-owns-merge 2026-08-16 03:48:53 +00:00
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-flight-deck/agentic-os!1085
No description provided.