Skip to content

fix: prevent premature RUN_PAYROLL_CALCULATED on re-calculate#1401

Open
jeffredodd wants to merge 1 commit intomainfrom
fix/payroll-recalculate-stale-data-race-condition
Open

fix: prevent premature RUN_PAYROLL_CALCULATED on re-calculate#1401
jeffredodd wants to merge 1 commit intomainfrom
fix/payroll-recalculate-stale-data-race-condition

Conversation

@jeffredodd
Copy link
Copy Markdown
Contributor

Summary

  • Fixes a race condition where re-calculating a payroll (Edit -> Calculate -> Edit -> Calculate) causes an immediate auto-transition to the Overview page before the new calculation completes
  • Root cause: payrollsCalculate is a plain function (not a React Query mutation), so it doesn't invalidate the query cache. When setIsPolling(true) fires, stale calculatedAt from the first calculation satisfies isCalculatedStatus immediately
  • Fix: tracks the calculatedAt timestamp before each calculation via a ref and guards the transition with an isNewCalculation check

Test plan

  • Added regression test that fails against the old code and passes with the fix (TDD-verified)
  • All 17 existing + new tests pass
  • Manual QA: Edit Correction -> Calculate -> Edit -> Calculate should stay on Overview with Edit + Submit buttons, waiting for user action

Made with Cursor

When re-calculating a payroll (Edit -> Calculate -> Edit -> Calculate),
the polling useEffect would immediately fire RUN_PAYROLL_CALCULATED
using stale cached data from the first calculation. This caused an
auto-transition to the Overview page before the new calculation
completed.

Root cause: payrollsCalculate is called as a plain function (not a
React Query mutation), so it does not invalidate the query cache.
When setIsPolling(true) triggers the useEffect, the stale cached
calculatedAt satisfies isCalculatedStatus immediately.

Fix: Track the calculatedAt timestamp before each calculation via a
ref. The useEffect now guards against stale data by checking that
calculatedAt has actually changed before firing the transition.

Made-with: Cursor
@jeffredodd jeffredodd marked this pull request as ready for review March 30, 2026 02:23
Copilot AI review requested due to automatic review settings March 30, 2026 02:23
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a race condition in the payroll recalculation flow where stale calculatedAt data could trigger RUN_PAYROLL_CALCULATED immediately, causing a premature transition before the new calculation finishes.

Changes:

  • Track the pre-calculation calculatedAt timestamp via a ref and require a new timestamp before firing RUN_PAYROLL_CALCULATED.
  • Update the polling transition logic to gate on isNewCalculation.
  • Add a regression test covering re-calculation when the payroll was already previously calculated.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/components/Payroll/PayrollConfiguration/PayrollConfiguration.tsx Adds previousCalculatedAtRef and guards the calculated transition until calculatedAt changes.
src/components/Payroll/PayrollConfiguration/PayrollConfiguration.test.tsx Adds a regression test ensuring stale calculatedAt does not trigger RUN_PAYROLL_CALCULATED during re-calc.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants