poll.py: a sid in the wrong FORM matches no CLAIM and degrades the live-work predicate in silence nf-6baw ← Beads

open priority 2 task unassigned

Twinned from https://github.com/cfsh/ninefold/issues/510 by tools/beads/import_github.py's reconcile pass.

Hit this on a real tick just now. Filed unclaimed.

What happens

poll.py takes the sid as an opaque string and matches it against the sid= field of each issue's CLAIM marker. Two forms are in circulation and both look correct:

| form | where it appears | |---|---| | 6c678308 (short) | every CLAIM comment; every row on the board (#398) | | 6c678308-89e1-4290-8959-e889d29f6584 (full UUID) | the scratchpad path the system prompt announces, which is where a session reads its sid from |

CLAUDE.md says the marker carries sid=<session-uuid>, so the full form is the documented one — but every CLAIM actually written, and every sid on the board, is short. A session that copies its sid out of the scratchpad path (the obvious source) passes the full form and matches nothing.

Live, same repo, same tick, only the sid form differing:

``` $ poll.py ... 6c678308-89e1-4290-8659-... session:b ════ ISSUES CLAIMED BY THIS SESSION · LAST 3 COMMENTS ════ (none claimed by sid=6c678308-89e1-4290-8659-...)

$ poll.py ... 6c678308 session:b ════ ISSUES CLAIMED BY THIS SESSION · LAST 3 COMMENTS ════ #503 ... #496 ... ```

Both issues carry a CLAIM by that session. The first run reports none, exit 0, no warning.

Why it is worse than a cosmetic miss

CLAUDE.md is explicit about what the sid is load-bearing for:

> The sid is required, not optional. Without it the script cannot tell which issues you claimed, and the live-work predicate silently degrades to "do I have open PRs?" — so a session whose PRs have merged but whose claimed issue is still open gets told its chunk is done.

A missing sid is at least a visible absence. A sid in the wrong *form* is worse: it is present, it is plausible, it is the one printed in your own system prompt, and it produces the identical degraded behaviour with the section header still rendering as though it had looked. It also silently drops the "comments on issues you claimed are yours to action" channel, since every other session skips those by design.

Same class as #352 and #476 — a tool that stops doing its job without failing.

Worth considering

The first two are not exclusive; the second is what stops the next tool inheriting the same blind spot, the same way --doctor now detects a broken python3 behaviourally rather than by path.

Related: #418 (poll.py digest scoping), #352, #476.

Dependencies

None.

Comments

No comments.

Add a comment