feat(adapters): derive-on-read async state machines across 18 adapters - #44
Merged
Conversation
Close the instant-complete/never-progress gap (stunt-s0w): async resources now store _running_at/_done_at at create time and derive their current state from the injectable wall clock on every read, persist the transition, and fire the provider's signed webhook exactly once per new state — polls, lists, and webhooks always agree. Provider-real vocabularies and timings (1s -> in-flight, 3s -> terminal): onfido in_progress->complete(clear/consider), jumio PENDING->DONE/FAILED, persona created->pending->completed/declined, sendgrid processed->delivered/dropped, resend sent->delivered/bounced, twilio queued->sent->delivered/undelivered/ failed (real +15005550001 magic number wired), whatsapp sent->delivered/failed, instagram/threads publish + insights lifecycles, dune PENDING->RUNNING->COMPLETED/FAILED, anaplan task states, chainlink Functions queued->running->success/failed, helius webhook + signature status progression, erc4337 userOp pending->validated->executed/failed, eth-jsonrpc receipt exposure over time, github Actions runs queued->in_progress->completed(conclusion), cloudflare deploys active->deployed/errored, appstoreconnect build PROCESSING->READY_FOR_SALE/INVALID. Failure injection: provider-real sandbox triggers where they exist, else a documented simulate_fail simulator flag skipping success side effects. Tests updated to the new contract (single shared 3.5s sleep, fail-path assertions). adapters/README documents the pattern.
…e idempotence, twilio failed-path State-machine review on PR #44: - dune: inline-result executions stamped terminal (were 500ing the poll path on missing lifecycle keys); derive uses .get fallbacks - concurrency_key added to the single-resource poll routes of the webhook-emitting adapters (twilio/messages, persona, jumio, onfido, github runs, resend, whatsapp) so concurrent reads can't double-emit - persona resume: verifications no longer duplicate and completed/ declined webhooks fire only on the first terminal (_ever_terminal) - twilio: invalid-number failures go queued -> failed with no sent hop (real behavior — an invalid number never reaches the carrier) - flaky first-poll assertions made tolerant (resend queued|sent, persona created|pending); new TestTwilioStyleLifecycleEmitsOnce pins the exactly-once guarantee
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Close the instant-complete/never-progress gap (stunt-s0w): async
resources now store _running_at/_done_at at create time and derive their
current state from the injectable wall clock on every read, persist the
transition, and fire the provider's signed webhook exactly once per new
state — polls, lists, and webhooks always agree.
Provider-real vocabularies and timings (1s -> in-flight, 3s ->
terminal): onfido in_progress->complete(clear/consider), jumio
PENDING->DONE/FAILED, persona created->pending->completed/declined,
sendgrid processed->delivered/dropped, resend
sent->delivered/bounced, twilio queued->sent->delivered/undelivered/
failed (real +15005550001 magic number wired), whatsapp
sent->delivered/failed, instagram/threads publish + insights
lifecycles, dune PENDING->RUNNING->COMPLETED/FAILED, anaplan task
states, chainlink Functions queued->running->success/failed, helius
webhook + signature status progression, erc4337 userOp
pending->validated->executed/failed, eth-jsonrpc receipt exposure over
time, github Actions runs queued->in_progress->completed(conclusion),
cloudflare deploys active->deployed/errored, appstoreconnect build
PROCESSING->READY_FOR_SALE/INVALID.
Failure injection: provider-real sandbox triggers where they exist,
else a documented simulate_fail simulator flag skipping success side
effects. Tests updated to the new contract (single shared 3.5s sleep,
fail-path assertions). adapters/README documents the pattern.