Skip to content

Roll squabble out as a GitHub App on all repos of both accounts, hosted on owned compute (owner rulings 2026-10-01) #122

Open

Description

@hyperpolymath

Owner rulings (2026-10-01, selector)

  1. Rollout route: a GitHub App with access to all repositories. It is installed on the hyperpolymath user account and the metadatastician organisation, so every existing and future repo is covered. No per-repo workflow files, no actions.lock churn, no copy in the template. The other options were rejected: a job inside standards/governance-reusable.yml, a per-repo workflow plus template, and template-only.
  2. Hosting: owned compute (farm). This closes docs/CHARTER.adoc open 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

What is missing

  1. 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.
  2. Webhook route and event handling. Candidate events: pull_request, check_suite.completed, check_run.completed, pull_request_review, status, and check_run.requested_action for the "Squabble!" button.
  3. 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.
  4. 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.
  5. 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_limit shows core 5000/5000). Debounce per head SHA and queue the work.
  6. 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}/protection and actions/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 on metadatastician (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 squabble check run whose verdict matches squabble 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_checks on 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.adoc open 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

https://claude.ai/code/session_01B2ARtAVppZ7x7mVY5u6nAz

Activity

  1. added
    decisionA ruling is required before work can proceed
    scope:estateAffects many or all repos across the estate
    on Oct 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    decisionA ruling is required before work can proceedscope:estateAffects many or all repos across the estate

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions