Skip to content

A wallet alert can be raised but never resolved #8

Description

@OliverD25

GET /v1/admin/wallet-alerts lists wallet receives that match no deposit
payment — coins in custody that no user has been credited for. It filters on
WalletTxoAlert.status == "open"
(src/crypto_processing_api/api/admin.py:147).

Nothing in the codebase ever sets that status to anything else, and nothing
ever sets resolved_at.
The column exists
(src/crypto_processing_api/ledger/models.py:498); the only writer is the
insert in src/crypto_processing_api/workers/reconciliation.py:287.

So an operator who does the work — reads
docs/runbook-usdt-attribution.md,
finds the user, credits them through the review queue — has no way to clear the
alert. The queue only grows, and a queue that only grows stops being read,
which is exactly how the next real one gets missed.

What to build

POST /v1/admin/wallet-alerts/{id}/resolve, taking a short note, setting
status and resolved_at, and recording the acting key id.

Constraints

  • This must move no money. It records that a human looked. Crediting a user
    is a separate action that already exists
    (POST /v1/admin/deposits/{id}/resolve), and the two must not be fused — an
    operator clearing an alert must not be able to mint a balance by accident.
  • Reuse the shape of the existing admin write endpoints in
    src/crypto_processing_api/api/admin.py: admin scope, key.key_id as the
    actor, 409 if it is already resolved.
  • The route needs a response model and an operation_id like every other route
    (src/crypto_processing_api/api/schemas.py). Adding one means running
    python scripts/export_openapi.py and committing the result, or CI fails.
  • Add the new response to the byte corpus in
    tests/integration/test_wire_bytes.py — regenerate it with
    WIRE_GOLDEN_WRITE=1. A route with no pinned bytes fails
    test_every_route_has_an_operation_id_and_pinned_bytes.

Worth deciding

Whether a resolved alert stays listable (?status=resolved). An audit trail an
operator cannot read back is not much of one.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: apiHTTP surface: routers, schemas, middlewarearea: opsOperator surface: alerts, health, reconciliation, runbooksgood first issueGood for newcomers

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions