diff --git a/.github/workflows/tests-rs-wallet.yml b/.github/workflows/tests-rs-wallet.yml index 64cc36997d9..ed8bc622717 100644 --- a/.github/workflows/tests-rs-wallet.yml +++ b/.github/workflows/tests-rs-wallet.yml @@ -201,10 +201,22 @@ jobs: --locked \ -- --no-deps -D warnings - # Mirrors the workspace job's non-shielded step for the wallet crates: - # same package subset, same `not test(~shield)` filter (shielded wallet - # tests are not run there either). - - name: Run wallet tests (non-shielded) + # No test filter: this job runs everything in the three wallet packages, + # shielded suite included. There is nothing here worth excluding — + # `wallet::shielded::` is 145 tests in ~6 s wall (~97 s of CPU) under + # nextest, and `--all-features` compiles those binaries whether or not + # they are selected, so skipping them saved execution time on artifacts + # already paid for and thrown away. + # + # This job and tests-rs-workspace.yml are mutually exclusive paths for a + # given PR, so the shielded suite has to run in BOTH or a wallet-scoped + # PR silently loses it. The workspace job carves the wallet packages out + # of its own shield exclusion for the same reason. + # + # `--no-tests fail` is the zero-match guard: a selection that matches + # nothing must fail the step, not pass green. Pinned rather than left to + # nextest's default, which is a default and not a promise. + - name: Run wallet tests run: | cargo nextest run \ --package platform-wallet \ @@ -212,7 +224,7 @@ jobs: --package platform-wallet-ffi \ --all-features \ --locked \ - -E 'not test(~shield)' + --no-tests fail env: RUST_MIN_STACK: 4194304 CARGO_PROFILE_DEV_DEBUG: "0" diff --git a/.github/workflows/tests-rs-workspace.yml b/.github/workflows/tests-rs-workspace.yml index 1c159c2c706..f9891e528bd 100644 --- a/.github/workflows/tests-rs-workspace.yml +++ b/.github/workflows/tests-rs-workspace.yml @@ -324,6 +324,20 @@ jobs: # caught minutes after merge — the same safety-net pattern as the # shielded phase. Keeping this phase's filter identical across events # keeps the `rust` codecov flag comparable between PR and push runs. + # + # `test(~shield)` is a substring match on the FULL test path, so it does + # not mean "the shielded suites" — it means "anything with the word in + # its name". The shielded phase below compensates for dpp / drive / + # drive-abci / dash-sdk, which genuinely need it: they are Orchard + # proving tests, and that phase runs them under `cargo test` in a shared + # process so one verifying key is built instead of one per test. + # + # The three wallet packages have no such compensator and no such need — + # their whole `wallet::shielded::` suite is 145 tests in ~6 s under + # nextest's process-per-test model — so excluding them dropped 145 + # shielded tests plus ~47 more that merely contain the word (input + # selection, FFI error codes, memo encoding, SQLite viewing-key rows) + # into a gap no job covered. They are carved out of the exclusion here. - name: Run non-shielded tests with nextest (parallel, compiles all packages) if: steps.coverage-cache.outputs.reuse == 'false' run: | @@ -352,7 +366,8 @@ jobs: --package keyword-search-contract \ --all-features \ --locked \ - -E 'not test(~shield) and (not binary_id(=drive-abci::strategy_tests) or test(~comprehensive_mixed_operations))' + --no-tests fail \ + -E '(not test(~shield) or package(platform-wallet) or package(platform-wallet-storage) or package(platform-wallet-ffi)) and (not binary_id(=drive-abci::strategy_tests) or test(~comprehensive_mixed_operations))' env: RUST_MIN_STACK: 4194304 CARGO_PROFILE_DEV_DEBUG: "0" @@ -370,6 +385,9 @@ jobs: # The chain simulations excluded from the phase above. PR runs skip # them (and upload no rust-strategy coverage — codecov carries the base # commit's forward); push, nightly, and dispatch runs execute them all. + # The `~shield` exclusion here IS compensated — drive-abci is in the + # shielded phase below — so it stays; `--no-tests fail` is the guard + # against the whole expression silently selecting nothing. - name: Run full chain-simulation suite (push and nightly only) id: strategy-tests if: >- @@ -380,6 +398,7 @@ jobs: --package drive-abci \ --all-features \ --locked \ + --no-tests fail \ -E 'binary_id(=drive-abci::strategy_tests) and not test(~comprehensive_mixed_operations) and not test(~shield)' env: RUST_MIN_STACK: 4194304 diff --git a/packages/rs-platform-wallet/src/wallet/platform_wallet.rs b/packages/rs-platform-wallet/src/wallet/platform_wallet.rs index c1ae06ba180..2b316334032 100644 --- a/packages/rs-platform-wallet/src/wallet/platform_wallet.rs +++ b/packages/rs-platform-wallet/src/wallet/platform_wallet.rs @@ -2303,23 +2303,24 @@ mod shield_input_selection_tests { #[test] fn regression_reports_max_from_usable_suffix_not_total_account_balance() { - // Real account snapshot: the leading address is below the reserve, so + // Account snapshot whose leading address cannot pay the fee, so // capacity must come from the usable suffix, not the account total. - assert!( - 297_264_780 <= reserve(), - "regression shape requires the leading address to stay below the reserve; \ - re-seed the balances if the versioned reserve drops under 297_264_780" - ); + // The leading balance is derived from the reserve — one credit below + // the strict `> reserve` viability threshold, the largest balance that + // must still be rejected as input 0 — so the shape holds whatever the + // versioned fee schedule does next. + let dust = reserve() - 1; + let usable = 3_623_849_220; let candidates = vec![ - (addr(1), 297_264_780), + (addr(1), dust), (addr(2), 2_000_000_000), (addr(3), 1_623_849_220), ]; let plan = plan(candidates).unwrap(); - let expected_max = 3_623_849_220 - reserve(); + let expected_max = usable - reserve(); - assert_eq!(plan.preflight.account_balance_credits, 3_921_114_000); - assert_eq!(plan.preflight.usable_balance_credits, 3_623_849_220); + assert_eq!(plan.preflight.account_balance_credits, dust + usable); + assert_eq!(plan.preflight.usable_balance_credits, usable); assert_eq!(plan.preflight.fee_reserve_credits, reserve()); assert_eq!(plan.preflight.max_shieldable_credits, expected_max); assert!(plan.preflight.can_shield); @@ -2329,11 +2330,13 @@ mod shield_input_selection_tests { assert!(!chosen.contains_key(&addr(1))); assert_eq!(chosen.values().sum::(), expected_max); + // `available` reports the usable suffix, never the account total — + // the whole point of the regression. let err = plan.select_inputs(expected_max + 1).unwrap_err(); assert!(matches!( err, PlatformWalletError::PlatformShieldCapacityExceeded { available, required } - if available == 3_623_849_220 && required == 3_623_849_221 + if available == usable && required == usable + 1 )); }