Skip to content

Never leave a claimed slot marked and unsent - #6

Merged
jeffwall-curlewlabs merged 1 commit into
mainfrom
fix/claim-never-strands-a-mark
Oct 5, 2026
Merged

jeffwall-curlewlabs merged 1 commit into
mainfrom
fix/claim-never-strands-a-mark

Conversation

@jeffwall-curlewlabs

Copy link
Copy Markdown
Contributor

A clock claims a slot's mark, reads the ledger, then sends. In v0.2.0, two paths can leave the mark in place with nothing sent. Every later tick then reads the slot as sent, and only GitHub's backstop delivers it, late. It's one slot per failure, since the next slot has a mark of its own.

  1. The ledger read after the claim fails. It now releases the mark, the same way a failed send already did.

  2. The claim's create lands, but GitHub answers otherwise. gh_api retries a POST whose answer was lost, so:

    • The retry is told the ref already exists, and the clock takes its own mark for another clock's.
    • If the lost answer was the last attempt's, the claim fails with the mark already in place.

    Each claim's note now carries a random id, so its blob is that claim's alone. A claim that is refused or fails reads the mark, and holds it when the mark points at its own blob.

What's still not covered: a clock that can neither create nor read the mark, or one stopped between its claim and its send. Either way GitHub's backstop delivers the slot late, as the README says.

Tests:

  • Unit tests for a failed ledger read, which must release the mark so the next tick sends.
  • Unit tests for each create outcome: a refused retry of its own create, a create that landed but failed, a create that never landed, and another claim's mark.
  • The new tests fail against v0.2.0's code.
  • The live check now claims the same mark twice with one id, which is what a retried create that landed looks like, and confirms the claim holds it. That depends on the note hashing to the blob GitHub created.

Run from a Mac against this repository: unit tests on Python 3.14 and 3.10, and the full live check with --require-clock-check.

The version goes to 0.2.1.

A clock claims a slot's mark, then reads the ledger, then sends. Two paths
left the mark in place with nothing sent, so every later tick read the slot
as sent and only GitHub's backstop delivered it, late:

- The ledger read after the claim failed. It now releases the mark, as a
  failed send already did.
- The claim's create applied but GitHub answered otherwise. gh_api retries
  a POST whose answer was lost, and the retry is told the ref exists, so
  the clock took its own mark for another clock's; or the lost answer was
  the last attempt's, and the claim failed with the mark in place. Each
  claim's note now carries a random id, so its blob is that claim's alone,
  and a claim that is refused or fails reads the mark and holds it when the
  mark points at its own blob.

The live check claims the same mark twice with one id, which is what a
retried create that applied looks like, and confirms the claim holds it:
that rests on the note hashing to the blob GitHub made.
@jeffwall-curlewlabs
jeffwall-curlewlabs merged commit 741b33a into main Oct 5, 2026
10 checks passed
@jeffwall-curlewlabs
jeffwall-curlewlabs deleted the fix/claim-never-strands-a-mark branch October 5, 2026 21:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant