Skip to content

Two holds opened by one attempt in the same tick raise a bare sqlite3.IntegrityError instead of a HoldError #221

Description

@thedancingdeveloper

Found during the operational end-to-end review (#218), pinned rather than fixed.

The mechanism

holds is keyed on (project_id, item_id, attempt, asked_at), and asked_at is a float. Two questions raised by one attempt within the same clock tick collide on that key, and the collision surfaces as a bare sqlite3.IntegrityError escaping WorkQueue.hold.

HoldError exists for exactly this kind of refusal and is what callers handle. A raw driver exception is not caught by anything, so it does not become a disposition, does not become an outcome, and reaches the worker as an unclassified crash.

Reachability

Effectively unreachable against a real clock — it needs two holds from one attempt inside the same float tick — and reachable immediately with an injected one, which is how it was found.

That makes it low priority and worth recording anyway: this repository's own vocabulary distinguishes "cannot happen" from "has not been seen to happen", and this is the second.

What the fix has to decide

Not simply catching the error. The question underneath is whether one attempt may hold twice at all:

  • If yes, the key is wrong — asked_at is being used as an identity and is not one. A counter or an explicit hold id would be.
  • If no, then the second call should be refused with a HoldError saying so, in the same terms as the existing refusal when an item already has an unanswered question.

The second reads more consistent with D12 and with already has an unanswered question, but that is a design call, not a bug fix, and I have not made it.

Blind spots

  • Whether any real caller can raise two holds in one attempt has not been traced. oversight_bridge and the executors are the candidates.
  • Whether other tables in work.py use a float timestamp as part of a primary key has not been checked.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:dispatchQueue, claims, worker supervision, admission controltype:taskUnit of implementation work

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions