partial, contract-owned (2026-07-15)

Spec: F42 — PR Merge & Branch Hygiene

Status: partial, contract-owned (2026-07-15)

1. Problem & CEO Job

Job: Trust the signal — but the signal degrades when branches rot. This repo has 24+ open branches: 9 Dependabot PRs, 3 fleet branches with unreviewed variants, tmp branches from completed work. Stale Dependabot updates accumulate conflicts. Unmerged feature branches diverge from main. Merge debt compounds — the longer you wait, the more it costs.

2. User Stories & Acceptance Criteria

  • As a developer, I want ≤ 10 open branches at any time, so that the branch list shows only active work.

    • Every open branch has an associated PR (draft or ready).
    • Every open branch rebased on main within 7 days.
  • As a dependency maintainer, I want Dependabot PRs merged or closed within 7 days.

    • Minor-level: reviewed and merged within 7 days.
    • Major-level: reviewed within 7 days, closed with reason if not mergeable.
  • As a reviewer, I want abandoned PRs auto-closed.

    • PR inactive for 14 days → bot comment “Still needed?”.
    • PR inactive for 21 days → auto-closed.
  • As a developer, I want squash-merge with auto-delete-branch.

    • All merges use squash-merge.
    • Branch auto-deleted after merge.
    • MERGE_ORDER.md tracks composeable branch sequence.

3. Scope Boundaries

  • In: Branch hygiene rules, stale detection, squash-merge policy, MERGE_ORDER.md, current branch cleanup.
  • Out: Code review process, release branching strategy, hotfix workflow, Dependabot patch auto-merge (dropped per owner decision 2026-07-02 — Dependabot PRs remain manual-review only).

4. Data Model

No model changes. GitHub repo settings + .github/workflows/ only.

5. API Contract

No API changes.

6. UI / UX

No application UI changes.

7. Test Plan

#CaseType
1Stale PR comment at 14 daysCI workflow
2Stale PR auto-close at 21 daysCI workflow

8. Current Behavior

24+ open branches as of 2026-06-12:

  • 1 active branch: fix/deploy
  • 9 Dependabot branches: accumulated patch/minor/major updates
  • 6 fleet branches: feat/fleet-A/B/C + their -r03 variants
  • 2 tmp branches: tmp/pr26, tmp/pr27 (dead)
  • The stale PR workflow is now present, but no repository-owned evidence proves live dispatch or enforcement of branch association, rebase age, merge style, branch deletion, or merge ordering.

Immediate cleanup:

  1. Close tmp/pr26, tmp/pr27
  2. Review fleet branches — merge or close
  3. Review all Dependabot PRs — merge patch, review minor/major

9. Error States

  • If stale automation comments on an actively reviewed PR, maintainers need a suppression label rather than manual churn every round.
  • If MERGE_ORDER.md conflicts with actual code dependencies, the dependency graph wins and the doc must be corrected immediately.

10. Diagrams & Docs Touched

  • .github/workflows/repo-stale.yml
  • MERGE_ORDER.md if implemented
  • Contribution/process docs that define branch hygiene

11. Implementation Audit

Edge Cases Catalog (formerly §10, 2026-06-14; 3 items): recently-pushed-but-stale branches still stale if no diff movement, Dependabot auto-merge needs allowlist for critical chains (auth/billing/mobile), fleet worktree branches need different hygiene rules from durable branches. Full catalog in git history.

#ClaimStatusEvidence
1.github/workflows/repo-stale.yml (14-day stale + 7-day close, Mon–Fri 08:00 UTC)🚧 partial.github/workflows/repo-stale.yml and scripts/tests/test_repo_stale_workflow.py; source matches, live GitHub execution is unverified
2MERGE_ORDER.mdN/ANot needed — main-branch-only workflow makes explicit ordering unnecessary

11.1 .github/workflows/repo-stale.yml

name: Stale PR management
on:
  schedule:
    - cron: "0 8 * * 1-5"   # 08:00 UTC Mon–Fri
  workflow_dispatch:         # manual trigger for cleanup

permissions:
  contents: read
  issues: write
  pull-requests: write

jobs:
  stale:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/stale@v10
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          days-before-stale: 14
          days-before-close: 7            # → 21 days total before closing
          stale-pr-message: >
            This PR has been inactive for 14 days and is marked as stale.
            **Is this branch still needed?**
            - If yes → rebase on main and push a commit to dismiss this label.
            - If no → close the PR; the branch will be cleaned up automatically.
            ⏳ Auto-close in 7 days if no activity.
          close-pr-message: >
            This PR was automatically closed after 21 days of inactivity.
            Reopen when ready to continue — the branch is preserved.
          exempt-pr-labels: "wip,security,dependencies,automation"
          exempt-draft-pr: true
          operations-per-run: 100
          enable-statistics: true

11.2 MERGE_ORDER.md (if implemented)

If the sequence of dependent PRs grows complex enough to require explicit ordering, a MERGE_ORDER.md at the repo root tracks the merge queue. Format:

# Merge Order — 2026-06

| Priority | Branch | PR | Depends on | Status |
|----------|--------|----|------------|--------|
| 1 | feat/X | #123 | — | ✅ merged |
| 2 | feat/Y | #124 | feat/X | 🚧 in review |

The dependency graph always wins over the doc — update MERGE_ORDER.md immediately when dependencies change.

12. Open Questions

  1. Fleet branches purpose: Ask team. Archive if abandoned.
  2. Branch naming: Enforce via PR description template, not CI.

13. Bug / Change Log

2026-07-02 — Decision: dependabot patch auto-merge dropped — not needed

Type: Owner Decision / Documentation Change

Summary:

  • The product owner has reviewed the prior 2026-07-02 correction entry (which flagged auto-merge-dependabot.yml as absent and presented the choice of implement-or-drop) and decided: drop the promise. auto-merge-dependabot.yml will not be created; Dependabot PRs remain manual-review only.
  • Removed from §2 AC: “Patch-level: auto-merge if CI green.” Dependabot minor/major review timelines remain.
  • Removed from §3 Scope In: “Dependabot auto-merge”. Moved to Out with a note.
  • Removed from §11: row 2 (auto-merge-dependabot.yml ⚠️ gap) deleted; the “Open gap” note deleted; §11.2 (ABSENT gap YAML) deleted. Remaining rows renumbered (former row 3 MERGE_ORDER.md is now row 2).
  • The prior 2026-07-02 “CI workflow drift correction” entry remains as historical record of how the gap was discovered. This entry supersedes its action-required outcome: the decision has been made.

Impact:

  • Documentation only. No code, CI workflow, or behavior changed.

2026-07-15 — Migrate F42 into the Contract Graph

Type: Contract and evidence-boundary correction

Summary:

  • Added source-level proofs for the actual repo-stale.yml configuration, including its self-hosted runner and actions/stale@v10 version.
  • Corrected the spec’s embedded workflow example from v9 to the shipped v10 action.
  • Preserved explicit gaps for live GitHub execution and all unchecked branch/merge policy promises.

2026-07-02 — CI workflow drift correction: stale.yml rename + auto-merge-dependabot.yml absent

Type: Documentation truth fix (supersedes the claims in the entry below of the same date)

Summary:

  • Correction 1 — filename: The stale workflow was documented throughout this spec as .github/workflows/stale.yml. The actual file is .github/workflows/repo-stale.yml. The 14/7-day behaviour (stale→close, Mon–Fri 08:00 UTC) is confirmed correct — only the filename was wrong. All references updated: §11 row 1, §11.1 heading.
  • Correction 2 — auto-merge absent: .github/workflows/auto-merge-dependabot.yml does NOT exist on main. The prior §13 entry (also dated 2026-07-02) incorrectly marked it ✅ confirmed. Verified: ls .github/workflows/ — no such file; .github/dependabot.yml is schedule-only with no merge keys; ci-fe.yml contains only a dep-age check job, not auto-merge. Changes made: §11 row 2 changed from ✅ match → ⚠️ gap; §11.2 heading and note updated; §2 AC “Patch-level: auto-merge if CI green” unchecked ([x] → [ ]).

Action required — decision for repo owner: The patch-level auto-merge capability was specified (§2 AC, §3 Scope) and designed (§11.2 YAML) but never implemented. The owner must choose one of:

  • (a) Implement: Create .github/workflows/auto-merge-dependabot.yml from the §11.2 design — this is a security/repo-policy decision (auto-approve + auto-merge of third-party dependency PRs). Re-check the AC when shipped.
  • (b) Drop the promise: Remove auto-merge from §2 AC and §3 Scope; update §11 row 2 to N/A. Dependabot PRs remain manual-review only. Do NOT create the workflow without explicit owner sign-off.

2026-07-02 — Spec drift fix: check 3 confirmed-shipped ACs in §2

Type: Documentation truth fix

Summary:

  • AC “Patch-level: auto-merge if CI green” checked ([x]): confirmed by §11 row 2 ✅ (.github/workflows/auto-merge-dependabot.yml with --squash --delete-branch on version-update:semver-patch).
  • AC “PR inactive for 14 days → bot comment ‘Still needed?’” checked ([x]): confirmed by §11 row 1 ✅ (.github/workflows/stale.yml days-before-stale: 14).
  • AC “PR inactive for 21 days → auto-closed” checked ([x]): confirmed by §11 row 1 ✅ (days-before-stale: 14 + days-before-close: 7 = 21 days total).
  • Remaining [ ] ACs (PR-per-branch enforcement, rebase-within-7-days, minor/major 7-day merge, squash-for-all-merges, branch-auto-delete-for-all, MERGE_ORDER.md) stay unchecked: no §11 rows confirm enforcement of these policy/process ACs beyond the Dependabot path.

2026-06-14 — Spec restructured to TEMPLATE.md canonical order (§1–§13)

Type: Documentation Change

Summary:

  • §9 Implementation Audit (non-standard position) moved to §11; canonical 4-column table added (3 rows).
  • §10 Edge Cases absorbed into §11 Implementation Audit note.
  • §11 Error States → §9, §12 Diagrams & Docs Touched → §10, §13 Open Questions → §12.

Reason:

  • Align with TEMPLATE.md canonical section order per SP fleet restructuring pass.

Impact:

  • Spec authors and future implementation agents.

None yet (first version — no bugs or changes to the process itself).