sync: a cloud card's branch comes home closing it, and the card goes from cloud to ready

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
This commit is contained in:
teahubxyzandClaude Opus 5.5 committed 2026-10-19 16:41:58 +00:00
1 parent 0b49cd36e0
commit a46570d423
1 file changed
+37 -2
+37 -2
View File
@@ -32,6 +32,7 @@ import fnmatch
import importlib.util
import json
import os
import re
import subprocess
import sys
import tempfile
@@ -133,6 +134,30 @@ def landed(work: str, ref: str, base: str) -> bool:
return git("merge-base", "--is-ancestor", ref, base, cwd=work, check=False).returncode == 0
CARD_BRANCH = re.compile(r"^claude/card-(\d+)(?:\b|-)") # a cloud session building card N (router.py's cloud lane)
def card_of(branch: str) -> int | None:
m = CARD_BRANCH.match(branch)
return int(m.group(1)) if m else None
def hand_back(repo: str, card: int, pr: int) -> bool:
"""A cloud-lane card's branch came home as `pr`: the card goes from `cloud` to `ready`, so the heartbeat adopts the PR
(it closes the card) and the council reviews and lands it like any card PR. Only a card on this repo still in the
lane moves; the note carries no beat, so the card still reads as never dispatched and is adopted, not rebuilt."""
if repo != tm.REPO:
return False
issue = tm.gh("GET", f"/repos/{repo}/issues/{card}")
if issue.get("state") != "open" or not tm.has_label(issue, "cloud"):
return False
tm.unlabel(card, "cloud")
tm.label(card, "ready")
tm.comment(card, f"☁️ The cloud session's branch came home as PR #{pr}. The heartbeat reviews and lands it like any "
f"card PR.", {"cloud": "home", "pr": pr})
return True
def ensure_pr(repo: str, work: str, branch: str, base: str, copy: str, where: str) -> int | None:
"""A PR on the home for an imported branch, unless one is open for it, it is already in the base, or a PR for it
was closed at this same commit (a human or the council said no; a new push brings it back)."""
@@ -146,10 +171,20 @@ def ensure_pr(repo: str, work: str, branch: str, base: str, copy: str, where: st
return None
log = git("log", "--reverse", "--format=%s%n%n%b%n---", f"refs/home/{base}..{ref}", cwd=work).stdout.strip()
title = (log.splitlines() or [branch])[0][:200]
body = (f"From {copy}: `{branch}` ({where}), brought in by sync.py. Time's council reviews it like any PR.\n\n"
card = card_of(branch)
closes = f"Closes #{card}\n\n" if card and not re.search(rf"\b(close[sd]?|fix(e[sd])?|resolve[sd]?)\s+#{card}\b", log, re.I) else ""
body = (f"{closes}From {copy}: `{branch}` ({where}), brought in by sync.py. Time's council reviews it like any PR.\n\n"
f"Commits:\n\n{log[:6000]}\n\n<sub>sync.py: edit this branch on {copy}; it is the copy's to write, and the "
f"next sync brings the change here.</sub>")
return tm.gh("POST", f"/repos/{repo}/pulls", {"head": branch, "base": base, "title": title, "body": body})["number"]
n = tm.gh("POST", f"/repos/{repo}/pulls", {"head": branch, "base": base, "title": title, "body": body})["number"]
# the card the branch is named for, and any the commits close (a cloud session may name its own branch)
named = {card} if card else set()
for c in sorted(named | {int(x) for x in re.findall(r"\b(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s+#(\d+)\b", log, re.I)}):
try:
hand_back(repo, c, n)
except Exception as e: # noqa: BLE001 the PR is home either way; a human can relabel the card
print(f"hand_back #{c}: {scrub(str(e))[:200]}")
return n
def sync_repo(entry: dict, home_url: str, force: bool = False) -> dict: