Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/agent_comms/standing_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -593,8 +593,8 @@ def derive(cls, branches: tuple[HeldBranch, ...]) -> tuple[Self, ...]: ...

@dataclass(frozen=True)
class BranchBehindMain(CoreActsStandingRule, HeldBranchRule):
"""A held branch needs a new base the moment main passes it. Syncing is the holder's
reflex, so Core tells the holder itself instead of waiting on a teammate relay."""
"""Outstanding branch changes need a new base when main passes them. Core tells
the holder directly; an empty historical checkout owes no new publication."""

problem: str
holder: ThreadIncarnation
Expand All @@ -620,7 +620,7 @@ def derive(cls, branches: tuple[HeldBranch, ...]) -> tuple[Self, ...]:
return tuple(cls(problem=held.problem, holder=held.holder,
repository=held.difference.repository,
branch=held.difference.branch, behind=held.difference.behind)
for held in branches if held.difference.behind and not held.queued)
for held in branches if held.difference.needs_rebase and not held.queued)

def line(self) -> str:
return (f"REBASE {self.repository.to_wire()}:{self.branch} ({self.holder.name} {self.problem}) is"
Expand Down
10 changes: 10 additions & 0 deletions src/agent_comms/work_branches.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,16 @@ class BranchDifference:
growth: SourceGrowth
unpublished: tuple[UnpushedHead, ...]

@property
def needs_rebase(self) -> bool:
"""Only outstanding committed changes need a newer base before publication.

An ancestor of main has no outgoing delta; retaining its checkout as evidence
does not create work whenever main advances. Uncommitted edits remain owned
by the checkout and the holder's before-commit synchronization.
"""
return bool(self.behind and self.files)

@property
def changes_source(self) -> bool:
"""Any file under the source tree, not only the Python modules growth counts."""
Expand Down
22 changes: 21 additions & 1 deletion tests/test_team_replay.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,6 @@ def order(self, name: str, worktree: Path, *, at: float) -> Todo:
name,
CreateProblemGoalAction(
problem=problem,
commander=self.commander,
request=self.request,
assigner=self.thread(self.commander).incarnation,
repo=self.repository,
Expand Down Expand Up @@ -472,6 +471,27 @@ def behind(name, number, queued):
assert queued.id not in told


@pytest.mark.parametrize("outstanding", (False, True))
def test_rebase_notice_requires_outstanding_branch_changes(fleet, outstanding):
built, _ = fleet
home = built.worktree("retained-history", base=built.old_main)
if outstanding:
built.commit(home, "repair.py", "repair = 1\n")
built.push(home)
todo = built.unit("history-worker", home)
storage = built.comms.registry.storage_rule
checkout = storage.order_checkout(storage.initial_roots("history-worker"), todo.id)
original = built.git(checkout, "rev-parse", "HEAD")

for index in range(2):
built.commit(built.source.checkout, "main.py", f"count = {index + 1}\n")
built.git(built.source.checkout, "push", "-q", "origin", "main")
told = {rule.problem for rule in built.observe().rules
if isinstance(rule, BranchBehindMain)}
assert (todo.id in told) is outstanding
assert built.git(checkout, "rev-parse", "HEAD") == original


def test_branch_rules_read_the_order_checkout_instead_of_the_behind_home(fleet):
built, _ = fleet
home = built.worktree('old-home', base=built.old_main)
Expand Down
Loading