swap-fees: free-mint path grants 199 steps for 100 paid (allotment 11,940,000 ms vs 6,000,000 expected)
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 48/100
Research direction
Start by running the named test, test_swap_fees.py::TestSwapFees::test_fee_mint_payments_do_not_break_the_free_mint_path, in tests/cloud-lab and compare it with an isolated run. Then inspect the allotment calculation in src/upstream_session_manager/ and the kind-1022 event emission in src/merchant/; first establish whether the event represents a per-payment grant or a session total. Done means the product behavior is confirmed and the test passes with the free-mint allotment matching that behavior.
Written by the indexing model from the issue text.
Description
Summary
test_swap_fees.py::TestSwapFees::test_fee_mint_payments_do_not_break_the_free_mint_path fails on current main: a 100-step payment on the FREE mint is granted 11,940,000 ms of allotment — exactly 199 steps — where the test demands 100 × 60,000 = 6,000,000. The anomaly is in the generous direction (customer receives ~2× what was paid for). Funds-adjacent: allotment accounting is wrong somewhere.
Severity: S2 candidate. 4 of 5 fee tests in the same file pass; only the free-mint-path check fails.
Verified on
- Commit:
68ad5144ab09cb4723d8f3f655cbba1ac7ea9de5(main, 2026-10-07) - Lane:
tests/cloud-labdocker lab, client pytest run
Evidence (verbatim)
> assert allotment == 100 * 60000, (
E AssertionError: Free-mint allotment 11940000 should equal the full 100 steps (6000000): {'p': ['c6:a5:b8:02:91:1e'], 'device-identifier': ['mac', 'c6:a5:b8:02:91:1e'], 'allotment': ['11940000'], 'metric': ['milliseconds'], 'start-time': ['1791388848']}
E assert 11940000 == (100 * 60000)
test_swap_fees.py:301: AssertionError
FAILED test_swap_fees.py::TestSwapFees::test_fee_mint_payments_do_not_break_the_free_mint_path
1 failed, 4 passed in 3.41s
Note 11,940,000 == 199 × 60,000 exactly.
Reproduce
git clone https://github.com/OpenTollGate/tollgate-module-basic-go && cd tollgate-module-basic-go
git checkout 68ad5144ab09cb4723d8f3f655cbba1ac7ea9de5
cd tests/cloud-lab
export TG_GO_VERSION="$(jq -r '.go.version' ../../packaging/build-inputs.json)"
docker compose up -d # builds mint, mint-fees (100 ppk) and upstream
docker compose run --rm client -q test_swap_fees.py ; echo EXIT=$? # or -sv for full output
Expected: 5/5 pass. Actual: 4 passed, 1 failed with the allotment assertion above.
Docker-29 caveat: if the client image fails to build (failed to parse stage name "golang:-bookworm"), apply the Dockerfile.client ARG fix from the companion issue first.
Troubleshooting guide
- First hypothesis — test isolation / accumulation: the paying client in the failing test is
c6:a5:b8:02:91:1e. Check whether earlier tests in the same session reuse that MAC and whetherallotmentin the session event is a per-payment grant or a session TOTAL (renewal accumulation). 199 = 100 + 99 is suspiciously close to "this payment plus an earlier 99-step grant".- Repro A (isolation): run only the one test —
docker compose run --rm client -q test_swap_fees.py::TestSwapFees::test_fee_mint_payments_do_not_break_the_free_mint_path— if it passes alone, the bug is state leakage between tests (shared MAC, wallet not reset, or the session renewal math accumulating across payments). - Repro B (unit seam): the allotment math lives in
src/upstream_session_manager/(usage trackers, renewal thresholds) andsrc/merchant/(session event emission). Look at where the kind-1022 event'sallotmenttag is computed for a SECOND payment by the same MAC.
- Repro A (isolation): run only the one test —
- Second hypothesis — fee-path contamination of the free path: the test's premise is that paying the free mint while the wallet ALSO knows the 100-ppk fee mint must not change the free grant. If the fee-resolution logic (per #440/#447-era work) applies a fee-derived step count or renewal top-up to the free path, you'd see inflated grants. Compare the wallet's credited amount for the free-mint token before/after the fee-mint tests ran.
- What 99 would mean: if an earlier test granted 99 steps (or a renewal added 99), find the emitter of that grant and why the free-path payment sees it merged.
Fix hints
- If accumulation-by-design: the session event should either report per-payment allotment or the test should assert on the delta — but get the PRODUCT answer first: is
allotmentspecified as total-session or per-payment? The wire spec (OpenTollGate/tollgate) is the authority. - If leakage: reset the client MAC between tests or drain the session in the fixture.
References
- Lane docs:
tests/cloud-lab/README.md(tg-mint-fees, swap-fee expectations) - Fee-math history: #409 (below-swap-fee pre-check), #440/#447 (fee error classification)
- Dominant language
- Go
- Stars
- 12
- Forks
- 14
- Avg merge
- 1d 5h
- Merged PRs (30d)
- 240
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
-
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 3 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
-
rebrand-literal-gutter: uhttpd section-vocabulary check trips on a COMMENT (uhttpd.luci in 92-tollgate-admin-setup:178)Possibly taken @Amperstrand claimed this 3 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
OpenTollGate/tollgate-module-basic-go#723 ·
Maintainers usually reply within 1 day
All issues in OpenTollGate/tollgate-module-basic-go
Similar issues
-
Difficulty 1/5 Under an hour Newbie friendliness 85/100
Maintainers usually reply within 1 day
-
kind/bug
Difficulty 1/5 1-3 hours Newbie friendliness 85/100
kubernetes-sigs/vsphere-csi-driver#4351 ·
Maintainers usually reply within 1 day
-
component/gpu-kubelet-plugin component/helm needs-triage
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
kubernetes-sigs/dra-driver-nvidia-gpu#1559 ·
Maintainers usually reply within 1 day
-
workflow: redundant goroutine in scheduleRetryPossibly taken @moodbased claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
Maintainers usually reply within 2 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
JuliusBrussee/caveman#1266 · 2 comments ·
Maintainers usually reply within 1 day