Reconciler can never clear Status/Blocked when every blocker is in another repo #11
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
sync_blocked_label.pycannot takeStatus/Blockedoff an issue whose blockers all live in another repo. It adds correctly and it never removes, so the label sticks forever and the backlog sweep keeps reporting the issue as blocked after it is free.The natural experiment, 2026-09-08
Two issues had every blocker closed within minutes of each other. The reconciler runs on a
*/15cron in each repo and reported success on every run.Status/Blockedat 08:30Runs 1171/1176/1179/1182 (07:45, 08:00, 08:15, 08:30) all green.
HANDS_OFFdoes not apply — #30 carriesKind/Feature,Priority/Low,Status/Blocked,Type/Epic, and neitherStatus/On HoldnorStatus/Abandoned. I removed the label by hand to unstick the board, so the reproduction is gone from #30; re-create it by adding a cross-repo dependency that is already closed.Two candidate mechanisms, both consistent, not yet distinguished
The Actions token is scoped to the repo it runs in, so it cannot read cfbypass while running in weblib-archive. Either:
repos/{repo}/issues/{n}/dependenciesfor a token that cannot see the other repo.depsthen comes back empty and the function takes its "no edges, no opinion" path andcontinues — never touching the label. I think this is the likelier one, because it also explains the silence: an empty list produces no log line at all.state. Thend.get("state") != "closed"is true, every cross-repo blocker counts as open forever, and the label is re-asserted rather than removed.They are easy to tell apart: log
len(deps)and the raw entries for one known cross-repo case under the Actions token. Worth doing before fixing, since the two need different fixes — 1 needs a token that can see the other repo, 2 needs the state resolved by querying the blocker's own repo directly.Why this is the fail-safe from #19 biting back
This is not a regression, it is the deliberate trade from cfbypass#19. Before that fix the rule was "only a positively open blocker blocks", and an unreadable cross-repo entry read as not-open — so the runner took the label off while cfbypass#1 was still open. The fix inverted it to "only a positively closed blocker is done", which is the right direction: a false "unblocked" sends someone to work on something that cannot be worked on, while a false "blocked" only hides available work.
But the inverted rule has no exit. Under mechanism 2 a cross-repo blocker can never be confirmed closed, so the label is permanent. #19 fixed the dangerous half and left the stuck half, and nothing measured the stuck half because the only cross-repo blockers at the time were still open.
Why it matters beyond one label
The backlog sweep in
docs/UNSUPERVISED.mdkeys onStatus/Blockedand on the dependency graph. A permanently-labelled issue is one that never comes back as workable — the exact failure bit called out on 2026-09-07: "they were unblocked/etc. and you should have started working on them". weblib-archive#30 is the largest item on the board and it would have stayed invisible.Note the cross-repo case is not an edge case here: weblib-archive#30 → cfbypass#1, #29 → weblib-fs#17, #57 → #30. The dependency graph in this org is mostly cross-repo.
Adjacent
Whatever the fix, it wants a test, and #9 is that nothing runs this repo's tests at all. The reporting side of the same problem: a job that does nothing still reports success, which is how this survived four green runs.