Repository navigation
Roll squabble out as a GitHub App on all repos of both accounts, hosted on owned compute (owner rulings 2026-10-01) #122
Copy link
Copy link
Open
Labels
decisionA ruling is required before work can proceedA ruling is required before work can proceedscope:estateAffects many or all repos across the estateAffects many or all repos across the estate
Description
Owner rulings (2026-10-01, selector)
- Rollout route: a GitHub App with access to all repositories. It is installed on the
hyperpolymathuser account and themetadatasticianorganisation, so every existing and future repo is covered. No per-repo workflow files, noactions.lockchurn, no copy in the template. The other options were rejected: a job insidestandards/governance-reusable.yml, a per-repo workflow plus template, and template-only. - Hosting: owned compute (farm). This closes
docs/CHARTER.adocopen point 1 (it was already provisionally "farm").
Recorded as D266 / D267 on the owner decision ledger (hyperpolymath/standards#787).
Scope at 2026-10-01
398 non-archived owned repos on hyperpolymath + 50 non-archived repos on metadatastician = 448, measured via GraphQL totalCount.
What exists
crates/squabble-app: an axum server bound to127.0.0.1:7741with three routes (/health,/api/v1/diagnose,/api/v1/fight). No webhook route and no octocrab/App-auth leg. Its own doc comment says the webhook leg is "honestly absent".verify-satisfiedis onfeat/verify-satisfied(feat: squabble verify-satisfied — the definition of done for a PR (exit 5 if not) #119), not onmain. The App's verdict should come from that one implementation (see apps-ack-gate.sh is a second implementation of verify-satisfied — make it a caller #118: apps-ack-gate should be a caller of it too). The App would be a third caller, not a third implementation.- No release binaries are published (
gh release listis empty).
What is missing
- Webhook ingress on farm compute. GitHub must reach it. That needs a public ingress in front of the loopback server: a tunnel or reverse proxy that terminates TLS and verifies
X-Hub-Signature-256. Estate doctrine applies: no 8080-class ports, and the server itself stays on loopback. - Webhook route and event handling. Candidate events:
pull_request,check_suite.completed,check_run.completed,pull_request_review,status, andcheck_run.requested_actionfor the "Squabble!" button. - App authentication. JWT signed with the App private key, then a per-installation token. The private key lives only on the farm host; it is never committed and never put in a workflow.
- Output as an advisory check run. It is never required: the check asks whether every other check and review is satisfied, so making it required would leave it waiting on itself. It must run after the other checks finish, not on
pull_request.opened. - Pacing. One installation token covers many repos, so a burst across 448 repos can hit the REST secondary limit (the 403 that reads "API rate limit exceeded" while
rate_limitshows core 5000/5000). Debounce per head SHA and queue the work. - Permissions — candidate list, derived from the endpoints the code calls; verify each against GitHub's per-endpoint permission tables before registering:
rules/branches/{b}: Metadata (read)branches/{b}/protectionandactions/permissions{,/selected-actions}: Administration (read)actions/jobs/{id}: Actions (read)- PR, review and review-thread GraphQL: Pull requests (read)
- check-run rollup: Checks (read), and write to post its own check run
- legacy statuses: Commit statuses (read)
- workflow files for
fight: Contents (read)
Owner-only steps (an agent cannot do these)
- Register the App: manifest or settings UI. This produces the App ID and the private key.
- Install it with All repositories on
hyperpolymath(user) and onmetadatastician(org). - Choose the ingress (tunnel or proxy) on the farm host.
Acceptance criteria
- A webhook route with signature verification; an unsigned or wrongly signed delivery gets 401 (test with a planted bad signature).
- Each PR head gets one advisory
squabblecheck run whose verdict matchessquabble verify-satisfied <o>/<r> <N>for the same head. Shown with a paired control: one done PR and one not-done PR. - The check run is in no ruleset's
required_status_checkson any repo. - A repo created after the install gets the check on its first PR without any per-repo change (positive control).
- Rate behaviour: a 448-repo burst finishes without a secondary-limit 403, or with paced retry, and a 403 is never reported as a verdict.
-
docs/CHARTER.adocopen point 1 is marked resolved (farm, 2026-10-01).
Blocked first on the owner-only registration step. Increments land in this order: webhook + auth on loopback with recorded fixtures, then ingress, then install.
🤖 Generated with Claude Code
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
decisionA ruling is required before work can proceedA ruling is required before work can proceedscope:estateAffects many or all repos across the estateAffects many or all repos across the estate
Activity