test(pm): early-exit headroom-clamp conservation replay (PR #124 review round 4) - #142
Conversation
The F1/steemit#300 early-exit deferred-claim settlement pass shipped with no test coverage — nothing under tests/ referenced deferred_claim / early_exit / reward_cap, parimutuel_test.cpp never exercised the claim pass, and the consensus_sim PM suite has no supply-conservation assertion. Add t15_early_exit_headroom to tests/pm/replay/ (same standalone style as t14_f2_ledger, #130): model the settle-pass verbatim from pm_evaluator.cpp:647-700 and settle through the real compute_settlement. A. bucket UNCLAMPED: the default 33% cap + a VALID 90%-fee market (fees are capped only by oracle+creator+liquidity <= 100% at creation, no chain param) overdraws the pot -> uncovered=23000 charged to LP principal. Reachable with default params, not just extreme medians — the exact case 499246e fixes. B. bucket CLAMPED (real code): capped to settlement headroom (33000->10000), uncovered=0, ledger balances, early-exiter haircut instead of LP hit. C. 1680-combo sweep of valid (fees, cap, forfeit, claim): 0 unbalanced ledgers, 0 claim-induced uncovered regressions vs the no-claim baseline — the clamp is solvency-neutral. The 400 uncovered_hits are the pre-existing negative-forfeit case (F1 LP-charge target), not the claim path. Exits non-zero on any conservation failure. Not part of the CMake build (each case is a main()), consistent with the rest of tests/pm/replay/. Built and run against head dd6c5d1: all checks pass.
Added: two CI-wired consensus_sim cases (verified against a full local build)Following the standalone
VerificationBuilt the full chain + Observed values from the real run (in the test log):
Both are appended to the existing |
Summary
Adds regression coverage for the
F1/#300early-exit deferred-claim settlement pass on the PM branch — the largest new consensus-money surface added since the PR #124 review round, and one that currently ships with no test coverage:tests/referencesdeferred_claim/early_exit/reward_cap/pot_retained,tests/pm/parimutuel_test.cpp(14 cases) exercises the pure split but never the claim pass,tests/consensus_sim/scenarios/test_pm_lifecycle.cppdrives leverage-close / cancel but has no supply-conservation assertion (supply_conserved()exists in the harness but is invoked 0 times in the PM scenarios).So the headroom clamp (
499246e9), thepot_retainedclamp (#141), and the paid-claims→forfeit_poolfold were all unguarded against regression.What this adds
One replay case,
tests/pm/replay/t15_early_exit_headroom.cpp, in the same standalone style ast14_f2_ledger(#130): it models the settle-pass verbatim frompm_evaluator.cpp:647-700and settles through the realcompute_settlement(linked fromlibraries/chain/pm/parimutuel.cpp, no node/DB build required).It targets the claim that motivated
499246e9: the reward cap alone does not bound solvency, because per-market fees are capped only byoracle+creator+liquidity <= 100%at creation (pm_operations.cpp:64) with no chain-param guard, so a valid market can push fees near 100%.uncovered = 23000charged to LP principal. Reachable with default params, not just extreme governance medians. This is the bug499246e9fixes.33000 → 10000),uncovered = 0, the ledger balances — the early-exiter is haircut instead of LP principal taking the hit.(fees, cap, forfeit, claim)→ 0 unbalanced ledgers and 0 claim-induceduncoveredregressions vs the no-claim baseline, i.e. paid claims are solvency-neutral. The 400uncovered_hitsin the sweep are the pre-existing negative-forfeit_poolcase (the F1 LP-charge target), not the claim path — the test separates them explicitly.The program exits non-zero on any conservation failure.
Build & run
tests/pm/replay/build.sh t15_early_exit_headroom tests/pm/replay/out/t15_early_exit_headroom # exit 0 = all checks passNot part of the CMake build (each case is a
main()), consistent with the rest oftests/pm/replay/. Built and run against pm headdd6c5d1: all checks pass, andt10_conserve/t14_f2_ledgerre-run unchanged.Notes / open review items (no test here, flagged for the author)
gc_market(pm_evaluator.cpp~L754) does not droppm_deferred_claim_index. Currently safe because every terminal transition consumes or purges claims first (settle at L696, void viareturn_liquidity→purge_deferred_claims), but it's an invariant held across four call sites with no GC backstop — addingdrop_range(pm_deferred_claim_index)there would be cheap defense-in-depth.CHAIN_HARDFORK_14_TIMEon both testnet and mainnet) is still a release-gating item.