issues.sh unselectable-work now reports a claim that outlived the run holding it (#216). Nothing releases one. The report is the right primitive for a stale blocked label, where a person or an agent has to decide the dependency is really gone, but it is the wrong one for in-progress: the label was written by machinery at pickup, so machinery should take it back, and a line of output every tick asking someone to do it by hand is the noise that gets the whole report skipped.
The measured instance
T6 #195, on 2026-08-16 (UTC), from the human's comment on #216:
| Time |
Event |
02:18:40 |
a session claimed #195 through issues.sh next, which applied in-progress |
03:17:38 |
last tool call — the session went quiet |
03:33:28 |
Session timeout (3600s total) - terminating orchestrator, ending error_during_execution |
03:33:30 |
session deadline reached - not continuing |
~03:36 |
the human removed the label by hand |
Afterwards: clean tree, on main, no branch, no commit, no PR — so no part of T6 was underway. The next session picked a different issue, and with the label present next --milestone 6 skipped #195; with it removed, next returned 195 immediately.
Why age is not the mechanism
The window in #216 is deliberately a report and not an expiry, and the reason is the one the human named: in-progress looks identical whether it was applied four seconds ago by a live session or an hour ago by one that has since been killed. A bare "clear it after N minutes" races a slow but healthy session and hands its issue to a second worker, which is strictly worse than the invisibility it fixes — two runs on one issue produce two branches and a merge conflict, and neither knows the other exists.
So the release needs liveness, not age.
Where the decision already exists
The control plane already distinguishes success, error_max_turns and error_during_execution, and it already logs session deadline reached - not continuing when it decides a chain is over. That decision point knows both that the session is finished and that it will not be resumed, which makes it the natural place to release what the session claimed.
Releasing on every session end would be wrong: an error_max_turns session that gets resumed should keep its claim, because the resumed run is still the worker.
Two layers, in this order:
- Release at the not-continuing decision. When the ladder decides a chain will not be resumed, release the claims that chain made. This needs an association from session to claimed issue —
claim currently writes a label and records nothing about who wrote it.
- A timeout sweep as backstop, not as the primary. A control plane that dies without deciding anything reaches no decision point, so nothing releases. The sweep covers exactly that case and must clear the session cap for the same reason the report's window does (see
DEFAULT_CLAIM_STALE_HOURS).
Done criteria
- A claim carries enough identity to be attributed to the session that made it.
- A chain the ladder declines to continue releases its claims; a chain that is resumed keeps them.
- A backstop sweep releases claims whose session cannot be accounted for at all, with a window above the session cap.
- A test that a healthy in-flight claim is never released — the false-positive case is the expensive one here, unlike in the report.
Routed to the evolver: the release point is in the control plane's continuation ladder, which is genesis, not this repo. issues.sh claim is genesis scaffolding too. Same route as PR #209 and PR #213: fix upstream in Sayfan-AI/genesis, backport. Every seeded project inherits a claim that never expires. Note #217 is also about rung 3 of that ladder and is adjacent but distinct — that one is about what counts as progress, this one is about what a finished session owes back.
issues.sh unselectable-worknow reports a claim that outlived the run holding it (#216). Nothing releases one. The report is the right primitive for a staleblockedlabel, where a person or an agent has to decide the dependency is really gone, but it is the wrong one forin-progress: the label was written by machinery at pickup, so machinery should take it back, and a line of output every tick asking someone to do it by hand is the noise that gets the whole report skipped.The measured instance
T6 #195, on 2026-08-16 (UTC), from the human's comment on #216:
02:18:40issues.sh next, which appliedin-progress03:17:3803:33:28Session timeout (3600s total) - terminating orchestrator, endingerror_during_execution03:33:30session deadline reached - not continuing~03:36Afterwards: clean tree, on
main, no branch, no commit, no PR — so no part of T6 was underway. The next session picked a different issue, and with the label presentnext --milestone 6skipped #195; with it removed,nextreturned195immediately.Why age is not the mechanism
The window in #216 is deliberately a report and not an expiry, and the reason is the one the human named:
in-progresslooks identical whether it was applied four seconds ago by a live session or an hour ago by one that has since been killed. A bare "clear it after N minutes" races a slow but healthy session and hands its issue to a second worker, which is strictly worse than the invisibility it fixes — two runs on one issue produce two branches and a merge conflict, and neither knows the other exists.So the release needs liveness, not age.
Where the decision already exists
The control plane already distinguishes
success,error_max_turnsanderror_during_execution, and it already logssession deadline reached - not continuingwhen it decides a chain is over. That decision point knows both that the session is finished and that it will not be resumed, which makes it the natural place to release what the session claimed.Releasing on every session end would be wrong: an
error_max_turnssession that gets resumed should keep its claim, because the resumed run is still the worker.Two layers, in this order:
claimcurrently writes a label and records nothing about who wrote it.DEFAULT_CLAIM_STALE_HOURS).Done criteria
Routed to the evolver: the release point is in the control plane's continuation ladder, which is genesis, not this repo.
issues.sh claimis genesis scaffolding too. Same route as PR #209 and PR #213: fix upstream inSayfan-AI/genesis, backport. Every seeded project inherits a claim that never expires. Note #217 is also about rung 3 of that ladder and is adjacent but distinct — that one is about what counts as progress, this one is about what a finished session owes back.