agentsclimarketplace

Br idempotency

Skill Lonsdale201/wp-agent-skills/better-route/br-idempotency

Configure better-route 1.1 replay-cache idempotency with IdempotencyMiddleware and Idempotency-Key. Use for ArrayIdempotencyStore, TransientIdempotencyStore, WpdbIdempotencyStore, installSchema, identity-aware canonical keys, body fingerprints, key conflicts, replay headers, key validation, custom methods/resolvers, or choosing between classic and atomic idempotency. Use AtomicIdempotencyMiddleware instead when concurrent duplicate side effects must be prevented.From its SKILL.md

Install
npx -y skills add Lonsdale201/wp-agent-skills --skill br-idempotency

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 21 stars21 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

5.2 KB, ~1.0k tokens by cl100k_base, as published. Nobody here has run it

better-route: replay-cache idempotency

Use IdempotencyMiddleware when replaying a completed response is useful but simultaneous duplicate execution is acceptable or impossible at another layer. It checks the store, invokes the handler, and stores only after completion; it does not reserve first.

For payments, order creation, subscriptions, account provisioning, or any irreversible side effect, use br-atomic-idempotency instead.

Production setup

use BetterRoute\Middleware\Write\IdempotencyMiddleware;
use BetterRoute\Middleware\Write\WpdbIdempotencyStore;

register_activation_hook(__FILE__, static function (): void {
    (new WpdbIdempotencyStore())->installSchema();
});

$idempotency = new IdempotencyMiddleware(
    store: new WpdbIdempotencyStore(),
    ttlSeconds: 600,
    requireKey: true,
);

$router->post('/drafts', $handler)
    ->protectedByMiddleware('bearerAuth')
    ->middleware([$auth, $idempotency]);

Store choices:

  • Use WpdbIdempotencyStore as the durable production default and call installSchema().
  • Use TransientIdempotencyStore only when transient lifecycle/cache flush semantics are acceptable.
  • Use ArrayIdempotencyStore only for tests or one-process checks; normal PHP requests do not share its state.

Cross-database wpdb table names containing . are rejected.

1.1 request contract

The middleware applies to POST, PUT, PATCH, and DELETE by default. Override methods if the route needs a different set.

Idempotency-Key must be printable ASCII and no longer than maxKeyLength (default 200). Missing required keys return 400 idempotency_key_required; malformed keys return 400 idempotency_key_invalid.

The default storage key deeply canonicalizes route, authenticated/native WordPress identity, and client key. The default fingerprint deeply canonicalizes route, method, identity, JSON/body params, and request params. Reordered associative keys remain equivalent; ordered lists remain order-sensitive.

On retry:

  • same storage key + same fingerprint replays the stored response and adds Idempotency-Replayed: true;
  • same storage key + changed fingerprint returns 409 idempotency_conflict;
  • two concurrent first requests can both execute because classic middleware has no reservation.

Response behavior

WP_REST_Response is normalized to a Better Route response before storage so status, data, and string headers can be replayed safely. Returned WP_Error is not stored. Thrown exceptions are not stored because the middleware never reaches its store call.

A returned Response with a 4xx/5xx status is still a completed return value and can be cached. Decide whether that is appropriate; throw for transient failures or use a custom policy/store if only selected statuses should persist.

For wpdb replay, return arrays/scalars or BetterRoute\Http\Response; arbitrary domain objects are not a supported persisted response contract.

Custom scope

$idempotency = new IdempotencyMiddleware(
    store: $store,
    requireKey: true,
    keyResolver: static fn ($context, string $clientKey): string =>
        'tenant:' . current_tenant_id() . ':' . $clientKey,
    fingerprintResolver: static fn ($context): string =>
        hash('sha256', canonical_domain_payload($context->request)),
);

Custom resolvers own collision resistance and canonicalization. Include every security/business dimension that distinguishes operations; do not concatenate attacker-controlled fields with an ambiguous delimiter.

Review checklist

  • Choose atomic middleware when simultaneous duplicates would be unsafe.
  • Run auth before idempotency; native WP identity is a fallback, not a replacement for route auth.
  • Install the wpdb schema before traffic.
  • Choose a TTL that covers real client retry delays.
  • Keep keys bounded and generate one key per logical operation.
  • Verify identical replay, changed-payload conflict, malformed key, missing key, and two concurrent first requests.
  • Plan expired-row cleanup for high-volume wpdb tables; on-access expiry alone does not purge every unused old key.

Related skills

  • Use br-atomic-idempotency for reservation-before-handler semantics.
  • Use br-routes for access intent and middleware ordering.
  • Use br-error-contract for idempotency error codes.

References

  • Verified source paths:
    • src/Middleware/Write/IdempotencyMiddleware.php
    • src/Middleware/Write/WpdbIdempotencyStore.php
    • src/Middleware/Write/TransientIdempotencyStore.php
    • src/Middleware/Write/StoredResponseCodec.php

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.