Compare commits

..
2 Commits
Author SHA1 Message Date
dongarandClaude Opus 5.5 51a821f895 nisse-review: read code from a git clone kept between runs
CI / checks (push) Skipped
CI / checks (pull_request) Failing after 1m21s
CI / e2e (pull_request) Skipped
Archives were downloaded and unpacked afresh for every run, which doesn't
scale to very large repositories. Each repository is now cloned once, with
its whole history, under scratch/repos/<owner>/<name>/ (head/ the clone,
base/ a worktree when read). A run fetches every branch and the PR's
refs/pull/N/head, checks out the head exactly, and fails if that head is
gone. Only the latest repository is kept for now.

Git runs walled off: none of the host's git configuration, links checked
out as plain files, no hooks, submodules or LFS, only the Gitea URL's
protocol, and the token as an http.extraHeader for that URL in git's
environment only. A stop ends a git command; a cut-short first clone is
removed. The reader never shows .git. GiteaClient.archive is gone.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk
2026-10-17 15:46:44 +00:00
dongarandClaude Opus 5.5 080205db7e nisse-review: a stop ends a review in progress; quieter repo failures
CI / checks (push) Skipped
CI / checks (pull_request) Failing after 1m15s
CI / e2e (pull_request) Skipped
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 15:41:55 +00:00
2 changed files with 0 additions and 44 deletions

No files matched your search

-5
View File
@@ -2111,7 +2111,6 @@ class LoopAgent:
result = delegation.run( result = delegation.run(
self._store.transcript(item.id, "helper"), brief=brief, branch=branch self._store.transcript(item.id, "helper"), brief=brief, branch=branch
) )
lost: GitError | None = None
try: try:
# The milestone takes the helper's work (or, on failure, only # The milestone takes the helper's work (or, on failure, only
# its own back) as uncommitted changes: harness branches never # its own back) as uncommitted changes: harness branches never
@@ -2123,8 +2122,6 @@ class LoopAgent:
git._git("branch", "-q", "-D", branch) git._git("branch", "-q", "-D", branch)
except GitError as exc: except GitError as exc:
self._fact(item, f"after helper {number}: {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(): for intent in self._store.pending_intents():
# Cut off rather than finished: discarded all the same, never # Cut off rather than finished: discarded all the same, never
# resumed blindly (L8, L9). # resumed blindly (L8, L9).
@@ -2133,8 +2130,6 @@ class LoopAgent:
and intent.payload.get("branch") == branch and intent.payload.get("branch") == branch
): ):
self._store.abort_intent(intent.id, cause=f"delegation {result.status}") 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: if result.usable and result.handback is not None:
self._fact(item, f"helper {number} finished: {result.handback.render()}") self._fact(item, f"helper {number} finished: {result.handback.render()}")
return f"the helper finished:\n{result.handback.render()}", True return f"the helper finished:\n{result.handback.render()}", True
-39
View File
@@ -338,42 +338,3 @@ def test_a_vm_lost_just_before_the_step_blocks_before_any_model_call(
agent, _ = agent_for(world, project, model, clock=Clock()) agent, _ = agent_for(world, project, model, clock=Clock())
agent.intake() agent.intake()
assert list(blocks(world).values()) == ["unreachable"] 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