01 / 09
That’s it. It’s all just markdown.
my-service/
.github/
docker/
migrations/
src/
api/
db/
workers/
tests/
package.json
tsconfig.json
README.md
memory/
tasks/
# my-service
## Boot protocol
Before changing anything:
1. `agsync check --no-baseline` — if it fails, repair what is
unambiguous and report the rest. Do not start on memory you
cannot trust.
2. `memory/goal.md` — what this service is for
3. `memory/decisions.md` — why it is built the way it is
4. `memory/state.md` — what is done, and what is only claimed
5. `tasks/README.md` — what is open
## Rules
- Decisions are append-only. Supersede one, never edit it.
- A task is `done` only once its Acceptance line has been run.
# Goal
Accept webhooks from payment providers and turn each one into
a ledger entry exactly once.
Success is one number: duplicate ledger entries per million
webhooks delivered. It is currently 0.
# Decisions
Append-only. Supersede an entry, never edit it. Every entry
records why, not just what.
## D-014 — Dedupe on the provider's event ID
- **Date:** 2026-08-14
- **Decision:** The worker dedupes on `event_id`, not on a
hash of the payload.
- **Rationale:** Two providers resend the same event with a
changed `received_at`, so payload hashing let duplicates
through on every retry.
- **Consequences:** `event_id` is a unique index now. Events
arriving without one are rejected at the edge.
# State
Updated 2026-08-28.
## Built and verified
- Webhook intake and `event_id` dedupe.
Verified: 2M duplicate deliveries replayed, 0 new rows.
## Built, not verified
- Replay endpoint. No test covers a partial replay, so treat
it as unproven until one does.
# Tasks
The index. Statuses: `todo`, `in-progress`, `done`,
`superseded`.
| # | File | Status |
|----|----------------------------|--------|
| 01 | 01-idempotent-retries.md | done |
# Task 01 — Idempotent retries
**Status:** done
**Related decisions:** D-014
## Acceptance
Replay 2M duplicate webhooks. The ledger gains no rows.
## Log
- 2026-08-14 — Switched dedupe to `event_id`. See D-014.
- 2026-08-27 — Load test green. Marked done.
A my-service repository. agsync reads only the markdown files listed below; the rest of the project is shown dimmed and is not selectable.
my-service/
.github/
docker/
migrations/
src/
api/
db/
workers/
tests/
package.json
tsconfig.json
README.md
AGENTS.md (selectable)
memory/
goal.md (selectable)
decisions.md (selectable)
state.md (selectable)
tasks/
README.md (selectable)
01-idempotent-retries.md (selectable)