Repository navigation
Valid handoff note still rejected when the work commit beneath it also deletes a handoff note #216
Description
Problem
The #213 fix skips too much. When the work commit beneath the note also touches the handoff note path, for example because it deletes an earlier round's note, a valid handoff note is still rejected:
handoff_note_rejected: Handoff note's `last_work_commit` does not match the last preserved work commit.
The attempt is then downgraded from handoff to incomplete, so no continuation is scheduled.
_this_attempt_note_commit_revisions collects every commit of this attempt from git log base..branch -- <note path>. That includes a work commit that only deletes the note alongside real changes. _validate_handoff_note then skips the whole unbroken run of those revisions beneath the newest note commit, "whatever other files they also carry" (comment in lifecycle.py). So it also skips the work commit and expects the commit below it.
#213 proposed skipping only commits that touch only the note path. The merged fix (#214) loosened that to any note-touching commit of this attempt.
Observed on
globaldb issue #146 (lbacik/globaldb#146), attempt 2026-10-13T10:19:46.131121Z, agent 0.4.4 (image built from v0.4.4), model muse-spark-1.3-contributor behind LiteLLM.
Branch agent/issue-146 after the attempt (newest first, author time UTC):
bc397e4 10:33 Handoff note: issue #146 <- note_commit (newest note-touching commit)
4097c8f 10:32 Handoff note: issue #146 <- earlier note commit, same attempt (the #213 case, handled)
41de6c3 10:32 Extract pinToCurrentRevision helper, drop handoff notes from the change
<- the note says last_work_commit: 41de6c3…
50d4525 10:28 Fix soft-delete delete tests for identity-map staleness
<- expected_last_work_commit computed by the validator
41de6c3 --stat:
.agent/handoff/146.md | 71 ---------------------------------
.agent/handoff/issue-146-spec-review.md | 18 ---------
src/Service/EntityCoreService.php | 25 +++++++-----
The model removed the previous round's note from the diff as a "process artifact" after a code-review pass, in the same commit as a code change. All three commits are authored after the attempt start, so handoff_note_commits returns bc397e4, 4097c8f, 41de6c3, and the cursor walks past all three.
Timeline from agent_output.json:
| UTC | event |
|---|---|
| 10:32:43 | token_soft_threshold_crossed (budget 5 627 902 / soft 5 600 000) |
| 10:32:43 | token_soft_threshold_handoff_context_injected |
| 10:32:56 | token_soft_threshold_handoff_note_committed revision=4097c8f |
| 10:33:02 | token_soft_threshold_handoff_followup. The model rewrites the note (wording only, same header) and commits bc397e4 |
| 10:33:18 | model_execution_finished: status=model_limit_reached |
| 10:33:18 | handoff_note_rejected, then completion_decided: outcome=incomplete |
According to the note, the implementation is committed and the full gate is green (433 tests, all quality tools exit 0). Only the validator stood between this attempt and a proper handoff.
The pattern recurs: on 2026-10-08 an earlier round of the same issue also removed the note in its own commit (3c8d1be Remove agent handoff note (process artifact, not part of the change)).
Expected
last_work_commit names the newest attempt commit beneath the note that carries work. Here that is 41de6c3, so the note should be accepted.
Proposed fix
When walking beneath note_commit, skip a commit only if it is a pure note commit: its diff touches only handoff_note_relpath(issue_number), and the note file still exists after it (a modification or addition, not a deletion). Stop at the first commit that changes anything else, or that deletes the note, and expect that commit (or base_revision if the walk runs out). Either restrict _this_attempt_note_commit_revisions to such commits, or apply the check in the loop in _validate_handoff_note. handoff_note_commit (locating the newest note) can stay as it is.
Regression test next to the #213 one in tests/test_handoff_end_to_end.py: a work commit that changes a source file and deletes an existing note, then two note-only commits with last_work_commit set to the work commit. Assert outcome=handoff. The #213 test (two note-only commits over a plain work commit) and the stale-commit test should keep their current results.
Related
- Valid handoff note rejected when the note is committed more than once #213 / agent: Valid handoff note rejected when the note is committed more than once #214: the fix this refines.
- Handoff silently downgraded to incomplete when the note's started_at is not ISO 8601 #174: same class (a handoff silently downgraded to
incompleteby a strict note check).
Activity
lbacik commentedon Oct 13, 2026
Agent Attempt Result: complete
Branch: agent/issue-216
PR: #217
Evidence
UV_PROJECT_ENVIRONMENT=/home/agent/venv-py311 uv run --python 3.11 --extra dev ruff check && UV_PROJECT_ENVIRONMENT=/home/agent/venv-py311 uv run --python 3.11 --extra dev pytest && UV_PROJECT_ENVIRONMENT=/home/agent/venv-py313 uv run --python 3.13 --extra dev pytest→ exit code 0Details
Claude SDK completed the implementation workflow.