Skip to content

feat(adapters): derive-on-read async state machines across 18 adapters - #44

Merged
deblasis merged 2 commits into
mainfrom
feat/async-lifecycles
Aug 14, 2026
Merged

feat(adapters): derive-on-read async state machines across 18 adapters#44
deblasis merged 2 commits into
mainfrom
feat/async-lifecycles

Conversation

@deblasis

Copy link
Copy Markdown
Contributor

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.

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
@deblasis
deblasis merged commit 6c7d4f2 into main Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant