Skip to content

PROJECT: Maintenance agent — org-wide PR triage, audit log, staged auto-merge #352

Description

@mmcky

Summary

QuantEcon carries 266 open PRs across 209 repos (2026-08-03). A large share are mechanical — dependabot bumps, sync-generated batches, disposition debt — consuming maintainer attention far out of proportion to the judgment they require. Meanwhile the org already has the ingredients for doing this work responsibly with an agent: strong per-repo CI (quantecon-book-theme runs a 103-screenshot visual regression suite), the audit plugin family in QuantEcon/skills, the status-translations collect→JSON→Pages pattern, and prior bot-identity experience (quantecon-news-reporter[bot]).

This issue proposes a maintenance agent: a scheduled agent that triages every open PR org-wide, publishes its reasoning to an auditable GitHub-native decision log, and — only after its recommendations demonstrably track maintainer decisions — graduates to auto-merging a narrow, policy-defined class of PRs. It is a sibling of the existing automation family, and a data producer for both #328 (operational telemetry) and #321 (config reporting).

The problem, measured (snapshot 2026-08-03)

Metric Value
Open PRs org-wide 266
… dependabot 50 (35 open ≥30 days)
… mmcky (largely agent-assisted batches awaiting review) 96
… pre-commit-ci 0 — its trusted autofix loop self-manages
Open ≥1 year (disposition debt, not review debt) 88
quantecon-book-theme 12 open: 9 dependabot + 3 mmcky

Illustrative case: book-theme #418 (webpack-dev-server 5→6, a major bump) — fully green incl. 103 visual regression tests, mergeable, untouched since Jul 27. The bottleneck is not information; it is a trusted process for saying "the checks that matter passed, the blast radius is understood, merge."

Design in brief

Judgment lives in the agent; authority lives in deterministic code. Five components:

  1. Collector (deterministic, nightly) — GraphQL sweep of all open PRs → dated snapshot committed to a new status-maintenance repo (same shape as status-translations: cron → collector → committed JSON → Pages dashboard).
  2. Triage agent (Claude, scheduled) — reads snapshot + policy; per PR writes a decision record (JSONL): verdict, lane, evidence (changelog delta × how the repo actually uses the package, CI nuance, advisories), risks, recommended action, policy + prompt version. Records are back-filled with the eventual human outcome, so agreement is measured with zero extra effort.
  3. Policy file (human-owned, versioned) — maintenance-policy.yml: lanes, repo tiers, rate caps, cooldowns, promotion thresholds. The agent may propose changes via PR; it can never edit policy itself.
  4. Actor (deterministic gate) — when enabled, re-validates in plain code every mechanical predicate of an "auto-merge eligible" claim (author, semver class, lockfile-only diff, required checks green — not skipped, cooldown, caps, no unresolved human comments) before calling the merge API. A hallucinated eligibility claim cannot merge anything.
  5. Reporter — Pages dashboard (triage state, agreement rate, every decision linkable) + daily/weekly brief.

Trust lanes (change class × repo tier gate every action):

  • Lane A — bot-authored patch/minor, lockfile-only, all required checks green → end state: auto-merge (rate-capped, cooldown).
  • Lane B — majors, grouped bumps, advisory-driven updates, build-tooling changes → agent writes the verification report; human one-click merges. Stays human.
  • Lane C — judgment content (features, docs, lectures, translations) → triage/label/route only. Always human.
  • Lane D — disposition debt (the 88 ≥1-year PRs) → batch close/supersede/revive proposals, mirroring the Decisions: dispositions for the 24 open lecture-proposal issues #344 motion for lecture-proposal issues.

Staged autonomy ladder: advise → measure agreement on the dashboard → delegate per-lane when a lane sustains ≥98% agreement over ≥30 decisions / 4 weeks (starting proposal) → any human revert/override freezes the lane pending review. Auto-merge is an earned end state, not a mode switch.

Safeguards for the auto-merge bar: supply-chain cooldown (released ≥5 days, no advisory since; advisory-driven bumps instead get expedited human review), per-repo/org daily merge caps, org-level kill switch variable, pre-written revert path + post-merge CI watch that auto-opens a revert PR and freezes the lane if main goes red.

Rollout

  • Phase 0 — prototype (no GitHub writes): scheduled Claude session produces a daily triage brief; lane definitions stabilize.
  • Phase 1 — plumbing: status-maintenance repo + nightly collector Action + Pages dashboard; register quantecon-maintenance App identity.
  • Phase 2 — advisor in-org: triage as a scheduled Actions workflow (an audit-family skill from QuantEcon/skills); labels + verification comments in pilot repos (book-theme, actions, 1–2 sphinx tool repos); agreement measured continuously.
  • Phase 3 — delegated merges: Lane A only, pilot repos only, behind the deterministic gate. Weekly "what I merged and why" brief.
  • Phase 4 — widen as Migrate the five native lecture CI pipelines to quantecon/actions/build-lectures #348's CI standardization makes policy portable across lecture repos.

Relationship to #328 and #321

Near-term wins (independent of the agent)

  1. book-theme: add an applies-to: security-updates group to dependabot.yml.
  2. book-theme: clear the 9-PR dependabot batch as the agent's first supervised run (patch/minor transitive bumps are Lane A shape; #418 + advisory-driven ones are Lane B) — producing the first decision records.
  3. Disposition sweep of the 88 ≥1-year PRs via the audit skill family (the Decisions: dispositions for the 24 open lecture-proposal issues #344 motion, applied to PRs).
  4. Register the bot identity early so agent actions separate from personal PRs in every future metric.

Open questions

  1. Merge method — squash everywhere or per-repo convention?
  2. Lane D auto-close: ever enabled, or always human batch-approval?
  3. Home for maintenance-policy.yml — meta or skills?
  4. Promotion threshold (98% / 4 weeks / 30 decisions is a starting proposal).
  5. Does the brief fold into the existing weekly report?
  6. Translation-repo PRs: out of scope for v1, or triage-only summaries to translation leads?

Distilled from the v0.1 design document (2026-08-03, drafted with Claude in the QuantEcon Agents project — full doc has the architecture diagram, decision-record schema, data appendix with sources, and suggested first artifacts; attached below / available on request).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions