Compare commits

..
3 Commits
Author SHA1 Message Date
dongarandClaude Opus 5.5 a85e855fc2 nisse-review: a stop ends a review in progress; quieter repo failures
CI / checks (push) Skipped
CI / checks (pull_request) Successful in 2m22s
CI / e2e (pull_request) Successful in 4m20s
SIGTERM used to stop only new rounds: a review in progress ran on until
systemd killed it 90s later. Now the scheduler's stop sets the driver's
cancel flag, so the run ends at its next turn, and a model call in flight
is broken off (Interruptible, raising Stopped from the signal handler, only
ever inside a model call). The item goes back to ready, with nothing
drafted posted and no failure counted; replies already posted carry their
markers and are not repeated.

intake.repo_failed is logged when a repository starts failing or the reason
changes, and intake.repo_ok when it lists again, not every round.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk
2026-10-17 20:37:12 +00:00
dev-agent 52d30ccab9 Merge pull request 'nisse-dev: a VM lost as a helper's work is taken back ends the run' (#161) from dev-delegate-lost-vm into main
CI / checks (push) Successful in 2m42s
CI / e2e (push) Skipped
2026-10-17 20:37:11 +00:00
dongarandClaude Opus 5.5 76d8e36f43 nisse-dev: a VM lost as a helper's work is taken back ends the run
CI / checks (push) Skipped
CI / checks (pull_request) Successful in 2m0s
CI / e2e (pull_request) Successful in 3m54s
The property walk (seed 468, a CI run's moving seed) found it: when the
build VM went out of reach while _delegate moved the helper's work back
onto the milestone's branch, git's HostUnavailable came back as a
GitError, was noted as a fact, and the driver's run went on, calling the
model with its VM gone (no_model_on_a_lost_vm). Now a GitError caused by a
lost VM raises VMUnreachable once the delegation's intents are settled, so
the run ends and the VM is blocked, as for any other lost-VM call (#137).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk
2026-10-17 16:00:31 +00:00
2 changed files with 44 additions and 0 deletions

No files matched your search

+5
View File
@@ -2111,6 +2111,7 @@ class LoopAgent:
result = delegation.run(
self._store.transcript(item.id, "helper"), brief=brief, branch=branch
)
lost: GitError | None = None
try:
# The milestone takes the helper's work (or, on failure, only
# its own back) as uncommitted changes: harness branches never
@@ -2122,6 +2123,8 @@ class LoopAgent:
git._git("branch", "-q", "-D", branch)
except GitError as exc:
self._fact(item, f"after helper {number}: {exc}")
if isinstance(exc.__cause__, HostUnavailable):
lost = exc # the VM went: the driver's run ends too (#137)
for intent in self._store.pending_intents():
# Cut off rather than finished: discarded all the same, never
# resumed blindly (L8, L9).
@@ -2130,6 +2133,8 @@ class LoopAgent:
and intent.payload.get("branch") == branch
):
self._store.abort_intent(intent.id, cause=f"delegation {result.status}")
if lost is not None:
raise VMUnreachable(str(lost)) from lost
if result.usable and result.handback is not None:
self._fact(item, f"helper {number} finished: {result.handback.render()}")
return f"the helper finished:\n{result.handback.render()}", True
+39
View File
@@ -338,3 +338,42 @@ def test_a_vm_lost_just_before_the_step_blocks_before_any_model_call(
agent, _ = agent_for(world, project, model, clock=Clock())
agent.intake()
assert list(blocks(world).values()) == ["unreachable"]
def test_a_vm_lost_as_a_helper_hands_back_ends_the_drivers_run(
world: dict[str, Any], project: str, monkeypatch: pytest.MonkeyPatch
) -> None:
# Found by the property walk (seed 468): taking the helper's work back
# onto the milestone's branch failed for the lost VM, was noted as a git
# error, and the driver's model was called with the VM gone.
from test_loop_help import Spy, hand_back, helpers
faults = Faults(monkeypatch, world["host"])
class Leaving(Spy):
def complete(self, events, tools, model, system=None) -> list[Any]:
out = super().complete(events, tools, model, system)
if not self.turns: # gone as its work is taken back
faults.drop_on = "checkout -q -f -B"
return out
helper = Leaving(
[call("write_file", path="helped.py", content="H = 1\n")], [hand_back()]
)
model = ScriptedModel(
ready(),
RESTATE,
[
call("start_milestone", name="m"),
call("delegate", task="write helped.py"),
],
[call("run_command", command="echo never")], # never asked for
)
agent, transport = agent_for(
world, project, model, clock=Clock(), helpers=helpers(helper)
)
agent.intake()
say(transport, world, "go")
assert list(blocks(world).values()) == ["unreachable"]
assert the_item(world).position == READY
assert len(model.turns) == 1 # the driver's model wasn't called again