Skip to content

docs: durable task store + delivery idempotency design (#2)#43

Merged
BunsDev merged 1 commit into
mainfrom
docs/issue-2-durable-store-design
Jul 7, 2026
Merged

docs: durable task store + delivery idempotency design (#2)#43
BunsDev merged 1 commit into
mainfrom
docs/issue-2-durable-store-design

Conversation

@BunsDev

@BunsDev BunsDev commented Jul 7, 2026

Copy link
Copy Markdown
Member

Design-for-review ahead of implementing #2, per maintainer direction (SQLite via rusqlite, design doc first).

Key decisions proposed in docs/durable-task-store.md:

  • Embedded SQLite via rusqlite (WAL, single-writer) in a new crates/store crate — zero-infra self-hosting, compose stays single-container, Postgres graduation path behind the same type if hosted scale demands it
  • Persist-then-ack: HMAC → require X-GitHub-Delivery (400 without) → insert delivery with ON CONFLICT DO NOTHING (duplicate → 200 + no-op) → insert task queued → notify → 200. Store down = 500, so GitHub retries instead of losing work
  • The tasks table IS the queue — the mpsc channel and its silent try_send drop path are removed; workers claim atomically via UPDATE … RETURNING
  • Restart recovery: orphaned running rows re-queue at boot (attempt-capped so a crash-looping task lands failed); the marker-backed status comment (Add marker-backed comments and maintainer command protocol #13) keeps the user surface deduplicated across restarts
  • Supersession moves into the store (tombstone queued reviews by supersede_key), replacing the in-memory registry; the Resolve Check Run head SHA and target ref correctly #8 mid-flight staleness gate is unchanged
  • No payload archival — routing coordinates + payload hash only, per docs/security.md posture
  • Three phased PRs: store + idempotency (mpsc kept), durable claims + recovery (mpsc removed, in-memory TaskStore retired), then the README/compose/demo truth pass

Test plan maps 1:1 to #2's acceptance criteria (duplicate delivery, queue-full inversion, restart recovery, ignored routing, Cave continuity).

Refs #2 (implementation PRs will close it).

Proposes embedded SQLite (rusqlite, WAL) behind a new crates/store crate:
persist-then-ack webhook handling keyed by X-GitHub-Delivery, a tasks table
as the queue (atomic claims, startup recovery, supersession tombstones),
task_attempts audit records, and Cave list continuity across restarts.
Phased into three separately-mergeable PRs.

Signed-off-by: Val Alexander <bunsthedev@gmail.com>
Copilot AI review requested due to automatic review settings July 7, 2026 03:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a proposed design document for implementing issue #2’s durable task store and GitHub delivery idempotency in coven-github, intended as a design-for-review precursor to phased implementation PRs.

Changes:

  • Introduces a SQLite (rusqlite) durable store design, including schema, config surface, and migration strategy.
  • Specifies end-to-end webhook idempotency flow keyed by X-GitHub-Delivery and a persist-then-ack contract.
  • Describes worker-side durable claiming, restart recovery, and supersession behavior moving from memory into the store.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +77 to +79
# Directory for durable adapter state (SQLite database + WAL files).
# The doctor command checks it is creatable/writable.
path = "data/coven-github.db"
installation_id INTEGER,
repo TEXT, -- owner/name when parseable
payload_hash TEXT NOT NULL, -- sha256 of raw body
routing TEXT NOT NULL, -- 'task:<id>' | 'ignored:<reason>'
Comment on lines +212 to +221
| Component | Change |
|---|---|
| new `crates/store` | `Store`: open/migrate, delivery insert-or-dup, task enqueue+tombstone, claim, terminal updates, attempt records, Cave list query, startup recovery |
| `crates/webhook/routes.rs` | Delivery-id gate; persist-then-ack; drop `task_tx`; `list_tasks` reads the store |
| `crates/worker/lib.rs` | Claim loop replaces `mpsc` recv; terminal states write to the store; supersession check reads `state='superseded'` instead of the in-memory registry |
| `crates/github/tasks.rs` | In-memory `TaskStore` retired; `TaskListItem`/`TaskListStatus` stay as the API projection |
| `crates/config` | `[storage] path` + doctor checks |
| `crates/server/main.rs` | Open store, run recovery, wire Notify |
| `compose.yaml` | Named volume for `/data` |
| `README.md` | Durable queue row: planned → implemented (only once true) |
@BunsDev BunsDev merged commit 26090d0 into main Jul 7, 2026
2 checks passed
@BunsDev BunsDev deleted the docs/issue-2-durable-store-design branch July 7, 2026 03:41
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.

2 participants