Delivery receipts: idempotent debit on merge + client lock #7
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Goal
Delivery receipts: on a merged PR in a client repo, debit the client's ledger exactly once, post a delivery comment on the issue, and lock the client if balance falls below floor. The money half of the loop.
Depends on: issues #1 (core), #6 (policy calls this — coordinate signature). Files allowed:
gitea_saas/delivery.py,tests/test_delivery.py. Do NOT modify anything else.Spec
delivery.debit_for_merge(client_id, repo, pr_number, head_sha, rate_minor):f"deliver:{repo}:{pr_number}:{head_sha}"— one debit per merge, even on duplicate webhook deliveriescore.debit(client_id, rate_minor, key, ref_type="pr", ref_id=f"{repo}#{pr_number}"){ok, balance}delivery.on_merge_webhook(client_id, repo, pr_number, head_sha):TIERS[tier]["rate_minor"]; envSAAS_TIERS_JSON), defaultSAAS_RATE_MINOR(e.g. 100 = $1/issue)intake_factory.lock(client_id)so future submits queue (no Gitea issues created while unpaid — consistent with intake model in issue #4)overdue: truein comment + lock client; the delivered work stands, new work waitsPOST /api/webhooks/gitea/merge(auth X-API-Key). Payload shape:{repo, pr, head_sha, client_id}(Gitea webhook → proxy mapper or manual POST; keep parse tolerant).Acceptance
overduenoted, client lockedVerification:
python -m pytest tests/test_delivery.py -qgreen.Lane 5 implementation complete — PR #18 (branch
issue-7, commitb5018c8) ready for manual review.Committed:
gitea_saas/delivery.py+tests/test_delivery.pyonly (per issue files-allowed).Test evidence:
python -m pytest tests/test_delivery.py -q-> 11 passedpython -m pytest -q(full suite incl. billing core) -> 37 passedgit diff --check-> cleanAcceptance mapping:
Delivered ✓ — balance after: $Xreceipt comment (test:test_merge_webhook_one_debit_at_tier_rate_with_receipt)test_duplicate_webhook_no_second_debit_no_second_comment, corereplayedno-op)test_balance_below_floor_locks_client)overduenoted, client locked (test_negative_debit_does_not_block_merge_overdue_and_lock)test_webhook_without_auth_401); malformed -> 400Note: the
POST /api/webhooks/gitea/mergeroute itself lives inserver.py, which is issue #6's file (not in this issue's allowed set). This PR ships the mountableDelivery.handle_merge_webhook(payload, key)handler returning(result, 401/400/200); the server lane wires it.