Skip to content

Fix/payment request cancellation lifecycle - #60

Draft
dzdidi wants to merge 2 commits into
masterfrom
fix/payment-request-cancellation-lifecycle
Draft

dzdidi wants to merge 2 commits into
masterfrom
fix/payment-request-cancellation-lifecycle

Conversation

@dzdidi

@dzdidi dzdidi commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

fix: propagate Paykit cancellation through verification

Summary

Propagates Paykit Payment Request cancellation and expiry through Locks verification, public APIs, SDKs, and browser examples.

  • Adds distinct terminal verification states: cancelled and expired.
  • Strictly validates canonical Paykit terminal responses.
  • Stops verification polling after cancellation or expiry.
  • Prevents entitlement issuance for both terminal outcomes.
  • Exposes terminal state through verification-task lookup and Rust SDK responses.
  • Updates browser examples to stop polling and offer retry behavior.
  • Adds PostgreSQL persistence support for cancelled.
  • Prepares Locks and its npm SDK for v0.1.0-rc6.

Lifecycle mapping

Paykit Server status Locks verification status Entitlement
cancelled cancelled Not issued
expired expired Not issued

Protocol validation

Locks accepts terminal Paykit responses only when they use canonical tuples:

{
  "status": "cancelled",
  "confirmations": 0,
  "amount_matched": false
}
{
  "status": "expired",
  "confirmations": 0,
  "amount_matched": false
}

Unknown fields, unknown statuses, or malformed terminal tuples remain dependency/protocol failures. They do not falsely terminalize verification.

Persistence and worker behavior

  • Adds cancelled to VerificationTaskStatus.
  • Adds migration 0010_verification_task_cancelled_status.sql.
  • Supports cancelled in memory and PostgreSQL repositories.
  • Uses existing claim fencing when terminalizing tasks.
  • Stops retry polling once cancellation or expiry is persisted.
  • Issues no entitlement for either outcome.

SDK and example behavior

  • Rust SDK deserializes cancelled and expired as distinct states.
  • JS reader flow stops polling on cancelled, expired, or failed.
  • Terminal outcomes enter the retry/new-payment flow rather than continuing background polling.

Release preparation

  • Bumps Rust workspace packages from 0.1.0-rc5 to 0.1.0-rc6.
  • Updates all local package versions in Cargo.lock.
  • Bumps @synonymdev/locks-sdk from 0.1.0-rc5 to 0.1.0-rc6.
  • Retains npm public access and the rc dist-tag.

Verification

Passed locally:

cargo test --workspace -- --skip infrastructure::postgres::
npm run smoke:examples --prefix locks-sdk/bindings/js
cargo check --locked --workspace --all-targets
cargo clippy --locked --workspace --all-targets --all-features -- -D warnings
cargo fmt --all -- --check
git diff --check

npm release checks also passed:

npm run build --prefix locks-sdk/bindings/js
npm run release:audit --prefix locks-sdk/bindings/js
npm pack ./locks-sdk/bindings/js --dry-run --json

Generated package was validated as:

@synonymdev/locks-sdk@0.1.0-rc6

PostgreSQL-backed runtime tests were not executed locally because TEST_DATABASE_URL was unset.

Related PR

Pairs with Paykit Server support for:

  • SDK Rejected or Canceled → cancelled
  • SDK ProposalExpired → expired

For deployment, Locks should be updated before or together with Paykit Server so it understands the new terminal response status before Paykit begins returning it.

Signed-off-by: dzdidi <dzdidi@users.noreply.github.com>
Signed-off-by: dzdidi <dzdidi@users.noreply.github.com>
@dzdidi
dzdidi marked this pull request as draft September 25, 2026 15:28
@dzdidi
dzdidi marked this pull request as ready for review September 25, 2026 21:27
@dzdidi dzdidi closed this Sep 25, 2026
@dzdidi dzdidi reopened this Sep 25, 2026
@dzdidi
dzdidi marked this pull request as draft September 25, 2026 21:33
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