feat(worker): upstream fork auto-sync — pull+merge fork repos hourly
Merge new upstream (parent) commits into every fork in the App installation, gated by a per-repo interval (default 1h), inside the existing 5-minute tick (STEP 0, max 2 forks/tick, oldest-first). - Conflicted merges are resolved by Claude Code (merge-reconciler rules: never wholesale --ours/--theirs, verify with the repo's own typecheck+tests, commit --no-edit; Claude never pushes — harness does). - Clean merges get a single Claude Code quality pass commit. - Push path: owner PAT (gh CLI) first — the App lacks workflows:write and a workflows-touching merge is rejected for the App token; App token fallback. - Protected default branch: detected from the push result (GH006 / required-status-check) → upstream-sync-<ts> branch + PR through the normal pipeline; duplicate open sync PRs are skipped. - CI safety: after a direct push, ticks verify the fork CI at our merge sha; red CI at OUR merge (still the tip) → sha-guarded force-revert to pre-merge sha + Discord notify; never reverts foreign commits. - Discord: synced / PR opened / reverted / skipped-once on pr-agent-ops. - merge_pr gains the same PAT fallback (a PR merge touching workflows is a workflow-file push). - CLI: --sync-status, --sync-only <repo> [--dry]. - Tests: scripts/test_pr_queue_sync.py (46 assertions, monkeypatched, no network); py_compile clean. - Plan: .hermes/plans/2026-09-21-upstream-auto-sync.md
This commit is contained in:
+37
-3
@@ -10,11 +10,45 @@ repos where the PR-Agent GitHub App is installed and drives the full lifecycle:
|
||||
of waiting on them forever
|
||||
3. **AI auto-fix** → runs Claude Code (`-p`) on the PR head for up to
|
||||
`AI_FIX_MAX_TURNS` turns, then pushes the fix
|
||||
4. **Safety analysis** → parses the review body for security/major-issue
|
||||
5. **Safety analysis** → parses the review body for security/major-issue
|
||||
blockers; score must be ≥ 6/10
|
||||
5. **CI gate** → waits for the required check to pass (closes stale dependabot
|
||||
6. **CI gate** → waits for the required check to pass (closes stale dependabot
|
||||
PRs stuck failing CI for > `STALE_CI_CLOSE_DAYS`)
|
||||
6. **Approve + merge**
|
||||
7. **Approve + merge**
|
||||
|
||||
## Upstream Fork Auto-Sync
|
||||
|
||||
Since 2026-09-21 the same 5-minute tick also syncs every repo in the App
|
||||
installation whose GitHub metadata says `fork: true`: new upstream (parent)
|
||||
commits are **merged** (never rebased) into the fork's default branch, gated by
|
||||
a per-repo interval (default **1 hour**; `UPSTREAM_SYNC` config block).
|
||||
|
||||
- **Conflicted merge** → Claude Code resolves it (merge-reconciler rules: merge
|
||||
hunks by hand, never wholesale `--ours/--theirs`, run the repo's own
|
||||
typecheck/tests before committing). Claude never pushes — the harness does.
|
||||
- **Clean merge** → one Claude Code quality pass over the merged files,
|
||||
committed as `fix: auto-fix code quality [skip ci]`.
|
||||
- **Protected default branch** → detect from the push result (GH006 /
|
||||
required-status-check) and fall back to opening an `upstream-sync-*` PR that
|
||||
the normal pipeline (review → AI fix → CI → approve → merge) finishes.
|
||||
- **CI safety** → after a direct push the worker verifies the fork's CI at our
|
||||
merge commit; a red CI at OUR merge sha (still the tip, no human commits on
|
||||
top) force-reverts to the pre-merge sha. Watch stops after 6 h.
|
||||
- **Push credentials** → owner PAT (gh CLI) first because the App lacks
|
||||
`workflows:write`; App token is the fallback. Clones use the App token.
|
||||
- **State** → `/tmp/pr-queue-sync-state.json` (skip/interval/pending-verify),
|
||||
workdirs `/tmp/pr-queue-sync-work/`.
|
||||
- **Notifications** → same `pr-agent-ops` Discord webhook: synced, PR opened,
|
||||
reverted, skipped-once.
|
||||
|
||||
Manual/dev:
|
||||
```bash
|
||||
python3 scripts/pr-queue-worker.py --sync-status
|
||||
python3 scripts/pr-queue-worker.py --sync-only asepharyana/shiro-neko --dry # stops before push
|
||||
python3 scripts/pr-queue-worker.py --sync-only asepharyana/shiro-neko
|
||||
```
|
||||
Tests: `python3 scripts/test_pr_queue_sync.py` (46 assertions; no network —
|
||||
gh_api/git/Claude/push are monkeypatched).
|
||||
|
||||
## Deployment
|
||||
|
||||
|
||||
Reference in New Issue
Block a user