Priority: P1 — ambiguous-outcome class at the TollGate layer. Independent of gonuts fixes.
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 30/100
Research direction
Start with src/merchant/merchant.go:506-538 to trace the Receive timeout and normal session-grant path; then review the proposed payment-saga state names for Rust parity. The issue calls for a durable pending-payment store, late-completion handling, and startup and periodic reconciliation, so first map those existing entry points before choosing an implementation. Done means the late-success and restart-reconciliation acceptance tests pass and /usage reflects a granted session.
Written by the indexing model from the issue text.
Description
Priority: P1 — ambiguous-outcome class at the TollGate layer. Independent of gonuts fixes.
Problem
PurchaseSession wraps Receive in a 30s timeout, but the goroutine keeps running. When Receive completes after the timeout response was sent: funds land in the operator wallet, no session is granted, no record exists, and the customer was told "timed out, try again" — so they pay again. Duplicate value consumed for one session; every timeout has this tail risk.
Why it matters
Timeouts are routine (mobile-network mints). The current code converts each one into a potential silent confiscation with a lying error message. Same family as #403 but via the timeout path, and invisible in logs beyond a Receive-completed line nobody correlates.
Current behavior (source refs)
src/merchant/merchant.go:506-538— goroutine +selecttimeout; on timeout the notice returns immediately, goroutine abandoned.src/merchant/merchant.go:519-529— late result (success or error) is logged and dropped.- No pending-payment record anywhere (sessions are created only post-timeout-window).
Desired invariant
No Receive outcome is discarded: a late success is reconciled into a granted session (or refund) durably; a late failure clears the pending record; the customer-visible timeout message states that the payment may still complete and how to check (
GET /usage).
Proposed scope
- Durable pending-payment record keyed by token Ys hash, written before launching Receive (this is also the idempotency key — coordinate with the payment-saga design for Rust parity, Rust issues #5/#6).
- Late-completion handler: on late success → same grant path as normal completion (session + gate + record COMPLETE); on late failure → record FAILED.
- Startup + periodic reconciliation: records in RECEIVE state older than timeout → query mint proof state (NUT-07) → resolve.
- Timeout notice copy updated to reflect "may complete; check usage" (wire-compatible text change only).
Areas / files
src/merchant/merchant.go, new small store (JSONL or bbolt sub-bucket; flash-aware), startup reconciliation in merchant init.
Acceptance criteria
- Fault test: Receive completes at t=35s, timeout returned at t=30s → session granted at t=35s,
/usagereflects it, record COMPLETE. - Kill between receive-start and completion → restart reconciliation resolves by mint state.
Required tests
- Unit: late-completion grant path; reconciliation decision table.
- Integration (cloud-lab): slow-mint proxy lane.
Failure-injection tests
- Proxy delays swap response 35s (payment completes late).
- Proxy drops response entirely; mint did consume inputs (mint-side state says spent) → reconciliation grants session.
Compatibility
Notice text change only.
Dependencies
Conceptually pairs with the Rust payment-saga issue (Amperstrand/tollgate-module-basic-rust#5) — implement to the same state names for test parity.
Out of scope
- Refund issuance on late success + unreachable client (session grant suffices; refund policy lives in #403's resolution).
- Dominant language
- Go
- Stars
- 12
- Forks
- 14
- Avg merge
- 1d 5h
- Merged PRs (30d)
- 246
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from OpenTollGate/tollgate-module-basic-go
-
Session event emits the customer's MAC address in the p tag — spec-invalid value on every payment responsePossibly taken @Amperstrand claimed this 2 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
OpenTollGate/tollgate-module-basic-go#949 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
OpenTollGate/tollgate-module-basic-go#833 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
OpenTollGate/tollgate-module-basic-go#813 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
OpenTollGate/tollgate-module-basic-go#804 ·
Maintainers usually reply within 1 day
-
go-battery needs an ndsctl on PATH: TestPurchaseSessionGuardHoldsThroughTheOutcomeUnknownWindow fails on bare hosts (passes with stub)Possibly taken @Amperstrand claimed this 7 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
OpenTollGate/tollgate-module-basic-go#726 · 2 comments ·
Maintainers usually reply within 1 day
All issues in OpenTollGate/tollgate-module-basic-go
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Maintainers usually reply within 1 day
-
ViewData can pair the in-flight proposal with the prepared flag of another proposalPossibly taken @HagarMeir claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
hyperledger/SmartBFT#710 ·
Maintainers usually reply within 1 day
-
agent-butler-finding chore
Difficulty 1/5 Under an hour Newbie friendliness 90/100
jordansmall/spindrift#5575 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
open-telemetry/opentelemetry-go-compile-instrumentation#1512 ·
Maintainers usually reply within 3 days
-
Difficulty 1/5 Under an hour Newbie friendliness 86/100
OpenPrinting/go-mfp#124 ·
Maintainers usually reply within 1 day