Publish work the executor committed itself, and gate when there is none
CI / checks (push) Skipped
CI / checks (pull_request) Successful in 1m15s

On the first live run the executor committed its milestone itself, as
its plan asked. The publisher only published a commit it made, found a
clean tree, reported "no changes to publish", and left the agent in
EXECUTING, where every message is answered "busy".

- publish(): with nothing left to commit, publish anyway when the branch
  has commits origin/<base> lacks; report no changes only when it has
  none.
- push_followup(): same for review fixes, comparing HEAD with what the
  remote branch holds (ls-remote; pushes go by URL, so there is no
  tracking ref).
- Nothing to publish now gates to AWAIT_INPUT, and the reply returns to
  the still-approved milestone plan.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE
This commit is contained in:
dongarandClaude Opus 5.5 committed 2026-09-29 16:17:41 +00:00
1 parent 8283e9eb1c
commit f97e459bc7
6 files changed
+119 -11

No files matched your search

+13
View File
@@ -53,6 +53,19 @@ class GitRepo:
def has_changes(self) -> bool:
return bool(self._run("status", "--porcelain"))
def commits_since(self, ref: str) -> int:
"""How many commits HEAD has that ref lacks. The executor may commit
its own work, so a clean tree does not mean nothing to publish."""
return int(self._run("rev-list", "--count", f"{ref}..HEAD"))
def remote_sha(
self, remote_url: str, branch: str, *, token: str | None = None
) -> str | None:
"""What the remote's branch points at, or None if it has no such
branch. Pushes go by URL, so there is no tracking ref to read."""
out = self._run("ls-remote", remote_url, f"refs/heads/{branch}", secret=token)
return out.split()[0] if out else None
# -- mutation ---------------------------------------------------------
def init(self, *, default_branch: str = "main") -> None: