Skip to content

Fix claimAllRewards failure isolation, add cache-invalidation and tier-boundary test coverage - #1908

Merged
Olowodarey merged 2 commits into
Arena1X:mainfrom
Martha-code-dev:feature/martha-insightarena-batch
Sep 26, 2026
Merged

Olowodarey merged 2 commits into
Arena1X:mainfrom
Martha-code-dev:feature/martha-insightarena-batch

Conversation

@Martha-code-dev

Copy link
Copy Markdown
Contributor

Summary

closes #1803
closes #1825
closes #1856
closes #1857

  • [Backend] — Predictions Claim-All Rewards Partial Failure Isolation #1857 (claimAllRewards partial failure isolation): claimAllRewards aborted the entire batch if any single claim failed, silently skipping the user's other eligible rewards for that request. Isolated each claim in its own try/catch so one failure no longer blocks the rest, and added a results field to ClaimAllRewardsResponseDto reporting per-prediction success/failure (reusing the existing BATCH_PREDICTION_STATUS convention from submitBatchPredictions for consistency). Added a regression test proving a failing middle claim no longer prevents the other claims in the batch from succeeding.
  • [Backend] — Analytics Cache Invalidation on Market Resolution #1856 (analytics cache invalidation on market resolution): invalidateMarketResolutionCaches was already correctly wired into adminResolveMarket and correctly ordered after the write commits, but had no test coverage of that flow at all (admin.service.spec.ts only stubbed it as a bare jest.fn()). Added tests covering: invalidation firing only after market.save() succeeds, affected-user ids being collected from the market's predictions, invalidation never firing when the on-chain resolution fails, and end-to-end getMarketAnalytics/getCategoryAnalytics reads immediately after invalidation reflecting the resolved state instead of stale cached values.
  • [Backend] — Creator Events Prediction Stats Cache Invalidation Ordering #1825 (creator-events prediction stats cache invalidation ordering): invalidatePredictionStatsCache turned out to be dead code, never called from any write path in the codebase (verified via a repo-wide grep). The issue's premise assumed it was already wired into a prediction mutation flow, which isn't the case. Added tests for the function's own behavior in isolation (key construction, concurrent-call safety) and documented in the test file that it has no caller yet. Wiring it into a mutation flow is a separate, deliberate decision for whoever owns that flow's design, since guessing the intended call sites risks over- or under-invalidating.
  • [Contract] — staking-vault: tier_for Boundary Equality Not Covered #1803 (staking-vault tier_for boundary equality): the issue assumed tier_for resolves a lock tier by comparing duration against a threshold (">="/">" semantics with fallthrough to a lower tier). The actual implementation matches a tier by exact equality on duration only, with no threshold logic at all: a duration one second off from any configured tier already reverts with InvalidLockPeriod rather than falling through, as the pre-existing test_stake_with_invalid_lock_period_reverts test already demonstrates. Added tests pinning down the real exact-match behavior at each configured tier's boundary in a new tests/tier_boundary_tests.rs file.

Also included

contracts/staking-vault did not compile at all on main prior to this PR (unrelated to any of the four issues above, but a necessary prerequisite to get #1803's tests running): lib.rs referenced LockTier.min_lock_duration (the actual field is duration) and StakingError::InvalidLockTiers/NoPosition/StillLocked, none of which exist in errors.rs. This looks like leftover drift from an earlier commit (bebd2d0, #1806's fix) that never got matching struct/enum changes. Restored these references to the existing, semantically-matching variants (PositionNotFound, LockNotElapsed, matching what the pre-existing test suite already asserts at those call sites) and added the one genuinely-missing InvalidTierConfig variant. Also removed lib.rs's duplicate, buggy validate_lock_tiers function in favor of the already-correct lock::validate_tiers it was a near-exact copy of.

Disclosure: tests/staking_tests.rs still does not compile as a whole file after this fix. It also calls unstake, withdraw, deposit_fees, pending_rewards, claim_rewards, and set_paused, none of which exist anywhere in lib.rs (only initialize, stake, request_unlock, and 3 getters are implemented). This is a much larger, separate pre-existing gap, an entire feature surface missing from the contract, not a naming mismatch, and is out of scope for this PR. tests/tier_boundary_tests.rs was split out as its own file specifically so the #1803 tests can compile and run independently of that unrelated breakage. Whoever picks up implementing those methods will need staking_tests.rs's existing assertions as the spec for their intended behavior.

Test plan

  • npx jest analytics.service.spec.ts admin.service.spec.ts predictions.service.spec.ts creator-events.service.spec.ts, 130 passed
  • cargo build in contracts/staking-vault passes (was previously broken on main)
  • cargo test --test tier_boundary_tests, 5 passed
  • npx eslint clean on all touched TypeScript files
  • Three-way identity check before push (persona login, fork owner, branch)

…r-boundary test coverage

closes Arena1X#1803
closes Arena1X#1825
closes Arena1X#1856
closes Arena1X#1857

- Arena1X#1857: claimAllRewards aborted the entire batch if any single claim
  failed, silently skipping the user's other eligible rewards for that
  request. Isolated each claim in its own try/catch so one failure no
  longer blocks the rest, and added a `results` field to
  ClaimAllRewardsResponseDto reporting per-prediction success/failure
  (reusing the existing BATCH_PREDICTION_STATUS convention from
  submitBatchPredictions for consistency). Added a regression test proving
  a failing middle claim no longer prevents the other claims in the batch.
- Arena1X#1856: invalidateMarketResolutionCaches was already correctly wired into
  adminResolveMarket and correctly ordered after the write commits, but had
  no test coverage of that flow (admin.service.spec.ts stubbed it as a bare
  jest.fn() with no assertions on when/how it's called). Added tests
  covering: invalidation only firing after market.save() succeeds,
  affected-user ids being collected from the market's predictions,
  invalidation never firing when the on-chain resolution fails, and
  end-to-end getMarketAnalytics/getCategoryAnalytics reads immediately
  after invalidation reflecting the resolved state instead of stale cached
  values.
- Arena1X#1825: invalidatePredictionStatsCache turned out to be dead code, never
  called from any write path in the codebase (verified via a repo-wide
  grep). The issue's premise assumed it was already wired into a prediction
  mutation flow. Added tests for the function's own behavior in isolation
  (key construction, concurrent-call safety) and documented that it has no
  caller yet; wiring it into a mutation flow is a separate, deliberate
  decision for whoever owns that flow's design.
- Arena1X#1803: the issue assumed tier_for resolves a lock tier by comparing
  duration against a threshold (">="/">" semantics with fallthrough to a
  lower tier). The actual implementation matches a tier by *exact* equality
  on duration only, with no threshold logic at all - a duration one second
  off from any configured tier already reverts with InvalidLockPeriod
  rather than falling through, as the pre-existing
  test_stake_with_invalid_lock_period_reverts test demonstrates. Added
  tests pinning down the real exact-match behavior at each configured
  tier's boundary, in a new tests/tier_boundary_tests.rs file.

Also fixed, as a necessary prerequisite for Arena1X#1803 (the crate did not
compile at all on main): lib.rs referenced LockTier.min_lock_duration
(the actual field is `duration`) and StakingError::InvalidLockTiers/
NoPosition/StillLocked, none of which exist in errors.rs. Restored these
to the existing, semantically-matching variants (PositionNotFound,
LockNotElapsed, matching what the pre-existing test suite already asserts)
and added the one genuinely-missing InvalidTierConfig variant, then
removed lib.rs's duplicate, buggy validate_lock_tiers in favor of the
already-correct lock::validate_tiers.

Disclosure: tests/staking_tests.rs still does not compile as a whole file
after this fix - it also calls unstake/withdraw/deposit_fees/
pending_rewards/claim_rewards/set_paused, none of which exist anywhere in
lib.rs. That is a much larger, separate pre-existing gap (an entire
feature surface missing from the contract, not a naming mismatch) that is
out of scope for this PR; tests/tier_boundary_tests.rs was split out as
its own file so the Arena1X#1803 tests can compile and run independently of it.
@drips-wave

drips-wave Bot commented Sep 26, 2026

Copy link
Copy Markdown

@Martha-code-dev Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@vercel

vercel Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
insight-arena-4rll Error Error Sep 26, 2026 7:24pm UTC

@Olowodarey
Olowodarey merged commit a753caf into Arena1X:main Sep 26, 2026
1 of 2 checks passed

This branch had an error being deployed

1 failed deployment
Preview — e29c27af Deployed Sep 26, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants