Problem
Every refund from the admin console fails with 409 REFUND_GATEWAY_UNAVAILABLE. That includes recording a manual, off-platform refund, so a merchant has no way to record any refund at all.
packages/plugin/src/admin/in-process-admin-orders-client.ts:181 hard-codes readonly #gateways = {}. Its comment says "EMPTY until the payment adapters move in-process (INC-C1/C3)".
:503-507: no gateway for the order's payment method returns 409 ("cannot even record a refund against it").
:454: the refund panel therefore always reports refundable: false.
packages/plugin/src/admin/make-admin-clients.ts:62 builds new InProcessAdminOrdersClient(ctx) with no gateways.
The payment adapters have since moved in-process. stripeGatewayFromCtx (packages/plugin/src/payments/stripe-wiring.ts:59-71) already builds the Stripe gateway for checkout (packages/plugin/src/commerce/make-commerce-client.ts:48-57), and x402GatewayFromCtx does the same for x402. The admin client was never given them. Refunds worked before the service was folded into the plugin, so this is a regression from work order 02.
Proposed fix
Resolve the gateways in makeAdminClients the same way makeCommerceClient does, pass them to InProcessAdminOrdersClient's constructor, and remove the hard-coded empty map. Keep the existing fail-closed behaviour: no gateway configured still means 409.
Scope and risk
The code change is small, about 20 lines. The risk is that it moves real money. The domain refund use-case and StripePaymentGateway.refund are each tested, but they have never run together in-process.
Prerequisites
Validation
- The refund-limit contract cases run and pass in-process.
- A sandbox test with a recording fake Stripe transport: one refund makes exactly one
POST /v1/refunds carrying the idempotency key, and a replay with the same key makes no second call.
- One manual refund in Stripe test mode on a non-production deployment, checking the order timeline and the Stripe dashboard.
Found in a read-only audit of main @ 3264354.
Problem
Every refund from the admin console fails with
409 REFUND_GATEWAY_UNAVAILABLE. That includes recording a manual, off-platform refund, so a merchant has no way to record any refund at all.packages/plugin/src/admin/in-process-admin-orders-client.ts:181hard-codesreadonly #gateways = {}. Its comment says "EMPTY until the payment adapters move in-process (INC-C1/C3)".:503-507: no gateway for the order's payment method returns 409 ("cannot even record a refund against it").:454: the refund panel therefore always reportsrefundable: false.packages/plugin/src/admin/make-admin-clients.ts:62buildsnew InProcessAdminOrdersClient(ctx)with no gateways.The payment adapters have since moved in-process.
stripeGatewayFromCtx(packages/plugin/src/payments/stripe-wiring.ts:59-71) already builds the Stripe gateway for checkout (packages/plugin/src/commerce/make-commerce-client.ts:48-57), andx402GatewayFromCtxdoes the same for x402. The admin client was never given them. Refunds worked before the service was folded into the plugin, so this is a regression from work order 02.Proposed fix
Resolve the gateways in
makeAdminClientsthe same waymakeCommerceClientdoes, pass them toInProcessAdminOrdersClient's constructor, and remove the hard-coded empty map. Keep the existing fail-closed behaviour: no gateway configured still means 409.Scope and risk
The code change is small, about 20 lines. The risk is that it moves real money. The domain refund use-case and
StripePaymentGateway.refundare each tested, but they have never run together in-process.Prerequisites
Stripe-Version, and bound the two refund calls with a timeout #114: bound the two Stripe refund calls with a timeout first, so a hung Stripe call can't hang the admin request.packages/plugin/test/contracts/commerce-client-contract.ts:2573) skip because the in-process test tier supplies no gateway. Enable them first as the safety net.Validation
POST /v1/refundscarrying the idempotency key, and a replay with the same key makes no second call.Found in a read-only audit of
main@ 3264354.