Skip to content

feat: webhook failure rollup, wallet archival, budget load test, and … - #392

Merged
Emmyt24 merged 2 commits into
Octo-Protocol-org:dev-branchfrom
adamuabdon5-del:dev-branch
Sep 28, 2026
Merged

Emmyt24 merged 2 commits into
Octo-Protocol-org:dev-branchfrom
adamuabdon5-del:dev-branch

Conversation

@adamuabdon5-del

Copy link
Copy Markdown

…Bruno CI integration

This commit resolves 4 issues across the store, API, tests, and CI workflows:

  1. Webhook delivery failure rollup (Closes Surface webhook delivery failure counts on the webhook list response so a merchant can spot a dead endpoint #342)
  • What was done: Added health rollup metrics (recent_failure_count and last_successful_delivery_at) to each entry in GET /v1/wallets/:id/webhooks without N+1 queries.
  • How it was done:
    • Defined WebhookDeliveryHealth in crates/store/src/models.rs.
    • Added webhook_delivery_health and wallet_webhook_delivery_health in crates/store/src/lib.rs. wallet_webhook_delivery_health executes a single aggregate query grouping by endpoint ID with a bounded 24-hour window for failures and MAX delivery timestamp for successes.
    • Updated WebhookView in crates/api/src/routes/webhooks.rs with recent_failure_count and last_successful_delivery_at, populated via wallet_webhook_delivery_health.
    • Added unit/integration tests covering recent failure count, healthy endpoints, and non-N+1 batched queries.
  1. Wallet archival lifecycle path (Closes Add a DELETE-adjacent archival path for wallets so a merchant can retire one without losing history #345)
  • What was done: Implemented a non-destructive archival path allowing merchants to retire wallets without losing historical audit trails, hiding archived wallets by default while preserving read access and rejecting mutations.
  • How it was done:
    • Created migration crates/store/migrations/0025_archive_wallets.sql adding archived_at TIMESTAMPTZ and index to wallets.
    • Added archived_at and is_archived() to Wallet in crates/store/src/models.rs.
    • Added StoreError::WalletArchived mapped to ApiError::Forbidden("wallet is archived").
    • Added archive_wallet, unarchive_wallet, and ensure_wallet_active to Store.
    • Updated list_wallets_for_user with include_archived filter flag (defaulting to false).
    • Added PATCH /v1/wallets/:id/archive and PATCH /v1/wallets/:id/unarchive endpoints requiring dashboard authentication.
    • Wired active wallet guards into mutating operations (create_address, submit_signed, withdrawal OTP endpoints, sponsor, and put_config) while keeping read routes accessible.
    • Added store tests for listing exclusion, mutation rejection, historical read access, and unarchive restoration.
  1. Sponsorship budget concurrency load test (Closes Add a load test for sponsorship budget reservation near the daily boundary under concurrency #346)
  • What was done: Added a gated concurrency load test validating that sponsorship budget reservation stays strictly within daily limits under 100 concurrent callers, tracking latency percentiles.
  • How it was done:
    • Implemented sponsorship_budget_reservation_under_100_way_concurrency_never_exceeds_budget in crates/store/tests/store_tests.rs.
    • Gated behind #[ignore] so it does not slow down the standard test suite.
    • Spawns 100 concurrent try_reserve_sponsored_transaction tasks against a wallet at its budget limit, measures per-request latency, asserts zero oversubscription, and logs p50/p95/p99 latency percentiles.
  1. Bruno API test collection CI runner (Closes Wire the api-tests Bruno collection into a CI-runnable integration-test target #339)
  • What was done: Wired the Bruno API test collection and challenge-signing scripts into an automated, non-interactive integration test target for local dev and CI.
  • How it was done:
    • Added @usebruno/cli to api-tests/scripts/package.json devDependencies.
    • Added just test-integration recipe in justfile that compiles the server, starts octo-server, waits for health readiness, runs bru run api-tests --env Local, and cleans up the server process.
    • Added an integration-test job in .github/workflows/ci.yml running against PostgreSQL service container.
    • Documented integration and load test execution and environment variables in CONTRIBUTING.md.

Summary

Related step / issue

Checklist

  • cargo fmt --all -- --check passes
  • cargo clippy --workspace --all-targets -- -D warnings passes
  • cargo test --workspace passes
  • No secrets (seeds/keys) logged or persisted in plaintext
  • Added/updated tests (test vectors for crypto/derivation changes)
  • Updated docs / CHANGELOG if behavior changed

How to test

…Bruno CI integration

This commit resolves 4 issues across the store, API, tests, and CI workflows:

1. Webhook delivery failure rollup (Closes Octo-Protocol-org#342)
- What was done: Added health rollup metrics (recent_failure_count and last_successful_delivery_at) to each entry in GET /v1/wallets/:id/webhooks without N+1 queries.
- How it was done:
  - Defined WebhookDeliveryHealth in crates/store/src/models.rs.
  - Added webhook_delivery_health and wallet_webhook_delivery_health in crates/store/src/lib.rs. wallet_webhook_delivery_health executes a single aggregate query grouping by endpoint ID with a bounded 24-hour window for failures and MAX delivery timestamp for successes.
  - Updated WebhookView in crates/api/src/routes/webhooks.rs with recent_failure_count and last_successful_delivery_at, populated via wallet_webhook_delivery_health.
  - Added unit/integration tests covering recent failure count, healthy endpoints, and non-N+1 batched queries.

2. Wallet archival lifecycle path (Closes Octo-Protocol-org#345)
- What was done: Implemented a non-destructive archival path allowing merchants to retire wallets without losing historical audit trails, hiding archived wallets by default while preserving read access and rejecting mutations.
- How it was done:
  - Created migration crates/store/migrations/0025_archive_wallets.sql adding archived_at TIMESTAMPTZ and index to wallets.
  - Added archived_at and is_archived() to Wallet in crates/store/src/models.rs.
  - Added StoreError::WalletArchived mapped to ApiError::Forbidden("wallet is archived").
  - Added archive_wallet, unarchive_wallet, and ensure_wallet_active to Store.
  - Updated list_wallets_for_user with include_archived filter flag (defaulting to false).
  - Added PATCH /v1/wallets/:id/archive and PATCH /v1/wallets/:id/unarchive endpoints requiring dashboard authentication.
  - Wired active wallet guards into mutating operations (create_address, submit_signed, withdrawal OTP endpoints, sponsor, and put_config) while keeping read routes accessible.
  - Added store tests for listing exclusion, mutation rejection, historical read access, and unarchive restoration.

3. Sponsorship budget concurrency load test (Closes Octo-Protocol-org#346)
- What was done: Added a gated concurrency load test validating that sponsorship budget reservation stays strictly within daily limits under 100 concurrent callers, tracking latency percentiles.
- How it was done:
  - Implemented sponsorship_budget_reservation_under_100_way_concurrency_never_exceeds_budget in crates/store/tests/store_tests.rs.
  - Gated behind #[ignore] so it does not slow down the standard test suite.
  - Spawns 100 concurrent try_reserve_sponsored_transaction tasks against a wallet at its budget limit, measures per-request latency, asserts zero oversubscription, and logs p50/p95/p99 latency percentiles.

4. Bruno API test collection CI runner (Closes Octo-Protocol-org#339)
- What was done: Wired the Bruno API test collection and challenge-signing scripts into an automated, non-interactive integration test target for local dev and CI.
- How it was done:
  - Added @usebruno/cli to api-tests/scripts/package.json devDependencies.
  - Added just test-integration recipe in justfile that compiles the server, starts octo-server, waits for health readiness, runs bru run api-tests --env Local, and cleans up the server process.
  - Added an integration-test job in .github/workflows/ci.yml running against PostgreSQL service container.
  - Documented integration and load test execution and environment variables in CONTRIBUTING.md.
@drips-wave

drips-wave Bot commented Sep 26, 2026

Copy link
Copy Markdown

@adamuabdon5-del Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

# Conflicts:
#	crates/api/src/error.rs
#	crates/api/src/lib.rs
#	crates/api/src/routes/wallets.rs
#	crates/api/tests/api_tests.rs
#	crates/store/src/error.rs
#	crates/store/src/lib.rs
#	crates/store/tests/store_tests.rs
@Emmyt24
Emmyt24 merged commit 64e671f into Octo-Protocol-org:dev-branch Sep 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment