Install the pre-push hook, so pr-guard has somewhere to run #1385

Merged
coilysiren merged 1 commit from aos/claude/ee98 into main 2026-08-29 06:39:50 +00:00
Owner

Closes the resident-checkout half of #1382.

The gap

apply-agentic-os-hooks.py ran pre-commit install for pre-commit, commit-msg, and prepare-commit-msg, and stopped. pr-guard is stages: [pre-push], so on every consumer it was a configured hook with no git hook to fire it.

Measured before the fix: 5 of 15 merge-remote-main repos had a pre-push hook at all, and each of those had it because somebody ran just pre-commit-install by hand. The science seat confirmed the mechanism clean-room: fresh clone, generator only, no pre-push.

This is the failure class #1382 names. A check that does not run reads exactly like a check that passed. It also made #1383 partly moot while it stood: a guard corrected across thirteen repos still had no hook to execute in on eight of them.

Verified

Deleted .git/hooks/pre-push from a consumer, re-ran the script, hook restored. Then backfilled every resident checkout: 18 of 20 now carry it. The two that do not are correct, not gaps.

  • coilysiren/coilysiren carries .agentic-os-ignore, a deliberate repo-owned opt-out.
  • agentic-os itself is skipped by the script as the source repo. I installed its hooks directly; whether the script should stop skipping itself is a separate question I have not answered.

The other half is not this script's business

A fresh clone still gets nothing, and for a non-resident repository like housecast a fresh clone is every session rather than an edge case. That is git's init.templateDir, which is a host setting and therefore an ansible rollout, per the authoring-vs-rollout law. Proven working before proposing it:

pre-commit init-templatedir T -t pre-commit -t commit-msg -t prepare-commit-msg -t pre-push
git clone --template=T <repo>   ->  .git/hooks: commit-msg pre-commit pre-push prepare-commit-msg

Fresh clone, no install step, violating commit refused. Then, on a clone whose lane was flipped so the guard should bite, git push to main refused by pr-guard. Both halves, because only the second proves pre-push landed.

Two properties worth recording for whoever writes that role:

  • the generated hook carries --skip-on-missing-config, so a clone with no .pre-commit-config.yaml no-ops instead of erroring. That bounds the blast radius on non-catalog clones.
  • the hook hardcodes an absolute INSTALL_PYTHON for the host that generated it, so the template must be generated per host rather than committed and copied. That suits an ansible role and rules out shipping a rendered template.

Not established

Whether pr-guard's blocking half protects anything today. Sweeping the fleet, every repo that enables pr-guard is on merge-remote-main, which is exactly the lane the guard now stands down on. No pull-request or pull-request-and-merge repo enables it. So the refuse-a-direct-main-push behavior currently has no live consumer, and I had to flip a lane synthetically to test it at all. That may be intentional or may be its own gap, and it is not this PR's to decide.

Closes the resident-checkout half of `#1382`. ## The gap `apply-agentic-os-hooks.py` ran `pre-commit install` for `pre-commit`, `commit-msg`, and `prepare-commit-msg`, and stopped. `pr-guard` is `stages: [pre-push]`, so on every consumer it was a configured hook with no git hook to fire it. Measured before the fix: **5 of 15** `merge-remote-main` repos had a `pre-push` hook at all, and each of those had it because somebody ran `just pre-commit-install` by hand. The science seat confirmed the mechanism clean-room: fresh clone, generator only, no `pre-push`. This is the failure class `#1382` names. A check that does not run reads exactly like a check that passed. It also made `#1383` partly moot while it stood: a guard corrected across thirteen repos still had no hook to execute in on eight of them. ## Verified Deleted `.git/hooks/pre-push` from a consumer, re-ran the script, hook restored. Then backfilled every resident checkout: **18 of 20** now carry it. The two that do not are correct, not gaps. * `coilysiren/coilysiren` carries `.agentic-os-ignore`, a deliberate repo-owned opt-out. * `agentic-os` itself is skipped by the script as the source repo. I installed its hooks directly; whether the script should stop skipping itself is a separate question I have not answered. ## The other half is not this script's business A fresh clone still gets nothing, and for a non-resident repository like `housecast` a fresh clone is every session rather than an edge case. That is git's `init.templateDir`, which is a host setting and therefore an ansible rollout, per the authoring-vs-rollout law. Proven working before proposing it: ``` pre-commit init-templatedir T -t pre-commit -t commit-msg -t prepare-commit-msg -t pre-push git clone --template=T <repo> -> .git/hooks: commit-msg pre-commit pre-push prepare-commit-msg ``` Fresh clone, no install step, violating commit **refused**. Then, on a clone whose lane was flipped so the guard should bite, `git push` to `main` **refused** by pr-guard. Both halves, because only the second proves `pre-push` landed. Two properties worth recording for whoever writes that role: * the generated hook carries `--skip-on-missing-config`, so a clone with no `.pre-commit-config.yaml` no-ops instead of erroring. That bounds the blast radius on non-catalog clones. * the hook hardcodes an absolute `INSTALL_PYTHON` for the host that generated it, so the template must be generated per host rather than committed and copied. That suits an ansible role and rules out shipping a rendered template. ## Not established Whether `pr-guard`'s blocking half protects anything today. Sweeping the fleet, **every repo that enables `pr-guard` is on `merge-remote-main`**, which is exactly the lane the guard now stands down on. No `pull-request` or `pull-request-and-merge` repo enables it. So the refuse-a-direct-main-push behavior currently has no live consumer, and I had to flip a lane synthetically to test it at all. That may be intentional or may be its own gap, and it is not this PR's to decide.
fix(hooks): install the pre-push hook, so pr-guard has somewhere to run
All checks were successful
ci / aos-eval-tests (pull_request) Successful in 9s
ci / aos-cli-tests (pull_request) Successful in 34s
ci / gate (pull_request) Successful in 51s
614ecbbc4f
The rollout installed pre-commit, commit-msg, and prepare-commit-msg and
stopped. pr-guard is `stages: [pre-push]`, so on every consumer it was a
configured hook with no git hook to fire it. Measured before the fix: 5 of 15
merge-remote-main repos had a pre-push hook at all, and each of those got it
from someone running `just pre-commit-install` by hand.

That is the failure class in agentic-os#1382: a check that does not run reads
exactly like a check that passed. It also made agentic-os#1383 partly moot
while it stood, because a guard corrected across thirteen repos still had no
hook to execute in on eight of them.

Adding pre-push to the install list closes it for every resident checkout on
the next rollout. A fresh clone is the other half and is git's `init.templateDir`,
which is an ansible rollout rather than this script's business.

Verified: deleting .git/hooks/pre-push from a consumer and re-running the
script restores it, and a template-seeded fresh clone refuses both a violating
commit and a guarded push to main.

Refs coilyco-flight-deck/agentic-os#1382

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Agent-Role: platform
coilysiren deleted branch aos/claude/ee98 2026-08-29 06:39:51 +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!1385
No description provided.