Skip to content

chore: report the lifecycle milestones a run crosses - #10074

Merged
MatiPl01 merged 11 commits into
mainfrom
@matipl01/animation-progress-changes
Aug 12, 2026
Merged

MatiPl01 merged 11 commits into
mainfrom
@matipl01/animation-progress-changes

Conversation

@MatiPl01

@MatiPl01 MatiPl01 commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor

RunLifecycle tracks which phase a run is in and reports the milestones each phase change crosses. It knows nothing about animations or transitions: the owner maps Created, Started, Ended, Repeated and Aborted to its own events.

The phase changes come straight from the tables in css-animations-2 and css-transitions-2, which agree on every row. That includes the rows that move a run backwards, which a style update reaches by re-timing a run that is already going or already finished.

A milestone can be reached by more than one phase change, and the time it carries differs: a start is the interval start entering from a delay and the interval end re-entering after finishing. Hence MilestoneTime, used by the owners in #10070 and #10120.

Pausing also moves out of the progress state, fixing an animation created with playState: Paused reporting animationstart while still paused and never once it actually started.

Nothing registers a reporter yet. First step of the CSS animation callbacks series.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added animation lifecycle tracking for creation, start, repetition, completion, and abortion.
    • Added ordered milestone reporting for animation progress.
    • Added support for aborting animations through lifecycle controls.
  • Bug Fixes

    • Improved handling of infinite iterations, delays, pauses, zero iterations, and resets.
    • Prevented duplicate or invalid lifecycle notifications after completion or abortion.
    • Improved animation completion and progress-state accuracy.

Walkthrough

Animation progress now uses persistent RunLifecycle data. The provider reports phases and iterations, delegates milestone and abort handling, and updates completion rules for delays, pauses, infinite iterations, and zero iterations.

Changes

Animation lifecycle tracking

Layer / File(s) Summary
Run lifecycle model
packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/RunLifecycle.h, packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/RunLifecycle.cpp
Adds lifecycle phases, milestones, ordered reporting, repeat tracking, state queries, and abort handling.
Progress provider integration
packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/AnimationProgressProvider.h, packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/AnimationProgressProvider.cpp
Replaces local animation state with persistent lifecycle data. Updates phase and iteration progress, exposes reporting and abort APIs, and handles completion conditions for delays, pauses, infinite iterations, and zero iterations.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AnimationProgressProvider
  participant RunLifecycle
  participant MilestoneReporter
  AnimationProgressProvider->>RunLifecycle: reachPhase(phase, iteration)
  RunLifecycle->>MilestoneReporter: report ordered milestone
  AnimationProgressProvider->>RunLifecycle: abort()
  RunLifecycle->>MilestoneReporter: report Aborted milestone
Loading

Possibly related PRs

Suggested reviewers: pawicao

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: reporting lifecycle milestones crossed by a run.
Description check ✅ Passed The description directly explains RunLifecycle, milestone reporting, CSS phase changes, pausing, and the pull request scope.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch @matipl01/animation-progress-changes

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@MatiPl01 MatiPl01 self-assigned this Jul 27, 2026
@MatiPl01
MatiPl01 force-pushed the @matipl01/animation-progress-changes branch from 22939c1 to 256761e Compare July 28, 2026 07:06
@MatiPl01 MatiPl01 changed the title chore: record the lifecycle boundaries an animation crosses chore: report the lifecycle boundaries an animation crosses Jul 28, 2026
@MatiPl01
MatiPl01 changed the base branch from main to @matipl01/fix-alternate-final-iteration July 28, 2026 07:08
@MatiPl01
MatiPl01 force-pushed the @matipl01/animation-progress-changes branch from 256761e to 378a210 Compare July 28, 2026 09:05
@MatiPl01
MatiPl01 force-pushed the @matipl01/animation-progress-changes branch from 378a210 to 01932aa Compare July 30, 2026 06:39
@MatiPl01
MatiPl01 changed the base branch from @matipl01/fix-alternate-final-iteration to @matipl01/time-progress-provider July 30, 2026 06:40
@MatiPl01
MatiPl01 force-pushed the @matipl01/animation-progress-changes branch from 01932aa to c09f96a Compare July 30, 2026 09:33
@MatiPl01 MatiPl01 changed the title chore: report the lifecycle boundaries an animation crosses chore: report the lifecycle milestones a run crosses Jul 30, 2026
@MatiPl01
MatiPl01 force-pushed the @matipl01/animation-progress-changes branch from 104f765 to 421669f Compare July 30, 2026 18:12
@MatiPl01
MatiPl01 marked this pull request as ready for review July 30, 2026 18:24
@MatiPl01
MatiPl01 force-pushed the @matipl01/animation-progress-changes branch from 421669f to 0fcd6d9 Compare July 30, 2026 19:03
@MatiPl01
MatiPl01 force-pushed the @matipl01/animation-progress-changes branch from 0fcd6d9 to abbdb0a Compare July 31, 2026 18:39
Base automatically changed from @matipl01/time-progress-provider to main August 6, 2026 11:19
@MatiPl01
MatiPl01 force-pushed the @matipl01/animation-progress-changes branch from abbdb0a to 0796b3d Compare August 11, 2026 18:03

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/RunLifecycle.cpp`:
- Around line 12-28: Make abort terminal by adding aborted_ guards at the start
of RunLifecycle::reachPosition and enterStagesUpTo, returning immediately once
the lifecycle has been aborted. Ensure these guards also stop progression when
abort() is invoked reentrantly from a Created or Started reporter callback,
preventing Started, Repeated, or Ended milestones after Aborted. Add coverage
for update-after-abort and reporter reentrancy scenarios.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a5513339-eda8-4f25-ba23-63f5f25ea7f1

📥 Commits

Reviewing files that changed from the base of the PR and between 248dee7 and 0796b3d.

📒 Files selected for processing (4)
  • packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/AnimationProgressProvider.cpp
  • packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/AnimationProgressProvider.h
  • packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/RunLifecycle.cpp
  • packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/RunLifecycle.h

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/RunLifecycle.cpp (1)

14-25: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Preserve milestone order across completed-run replays.

After Ended, this code can rewind reported_ to Created. A later Started position then reports Started again. If the target remains Ended while repeat increases, the rewind is skipped and Repeated is reported after Ended; enterStagesUpTo() cannot emit a new Ended afterward.

Define the replay boundary explicitly. Keep historical milestones separate from the current stage, or rewind to a stage that preserves the already-reported Started milestone. Add tests for both Ended → Created → Started and Ended with a larger repeat.

Based on the ordered-milestone contract in RunLifecycle.h and the persistent lifecycle behavior in AnimationProgressProvider.cpp.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/RunLifecycle.cpp`
around lines 14 - 25, Update the replay handling around reported_,
enterStagesUpTo(), and repeat_ so milestone ordering remains monotonic after an
Ended run. Define an explicit replay boundary that preserves the historical
Started milestone, ensuring both Ended → Created → Started and Ended with an
increased repeat can emit Repeated without preventing a subsequent Ended
milestone. Add coverage for both scenarios, following the ordered-milestone
contract in RunLifecycle.h and persistent behavior in
AnimationProgressProvider.cpp.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In
`@packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/RunLifecycle.cpp`:
- Around line 14-25: Update the replay handling around reported_,
enterStagesUpTo(), and repeat_ so milestone ordering remains monotonic after an
Ended run. Define an explicit replay boundary that preserves the historical
Started milestone, ensuring both Ended → Created → Started and Ended with an
increased repeat can emit Repeated without preventing a subsequent Ended
milestone. Add coverage for both scenarios, following the ordered-milestone
contract in RunLifecycle.h and persistent behavior in
AnimationProgressProvider.cpp.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7a954f1b-d28e-4e00-b536-0adb10c8dd52

📥 Commits

Reviewing files that changed from the base of the PR and between 0796b3d and 70951da.

📒 Files selected for processing (2)
  • packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/AnimationProgressProvider.cpp
  • packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/RunLifecycle.cpp

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/RunLifecycle.cpp (1)

26-34: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Re-check aborted_ after reporter callbacks.

The guard in enterStagesUpTo stops only that loop.

If the Started reporter calls abort() while repeat > repeat_, reachPosition resumes and reports RunMilestone::Repeated after RunMilestone::Aborted.

If the Created reporter calls abort() during RunLifecycle::abort(), the inner call reports RunMilestone::Aborted. The outer call then reports RunMilestone::Aborted again.

Return immediately when aborted_ becomes true after each enterStagesUpTo call. Add tests for both event sequences.

Proposed fix
   enterStagesUpTo(std::min(target, rank(RunStage::Started)));
+  if (aborted_) {
+    return;
+  }
   // ...

   enterStagesUpTo(rank(RunStage::Created));
+  if (aborted_) {
+    return;
+  }
   aborted_ = true;

Based on learnings: RunLifecycle::abort() must be terminal, and no milestone may occur after Aborted, including during re-entrant reporter callbacks.

Also applies to: 42-46

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/RunLifecycle.cpp`
around lines 26 - 34, Update RunLifecycle::reachPosition and RunLifecycle::abort
to re-check aborted_ immediately after each enterStagesUpTo call and return when
it becomes true, preventing any later milestone or duplicate Aborted report
during re-entrant reporter callbacks. Add tests covering Started-triggered abort
during repeat reporting and Created-triggered abort during abort().

Source: Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In
`@packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/RunLifecycle.cpp`:
- Around line 26-34: Update RunLifecycle::reachPosition and RunLifecycle::abort
to re-check aborted_ immediately after each enterStagesUpTo call and return when
it becomes true, preventing any later milestone or duplicate Aborted report
during re-entrant reporter callbacks. Add tests covering Started-triggered abort
during repeat reporting and Created-triggered abort during abort().

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 26f123fe-582c-46ad-bb97-b3a5f33a3822

📥 Commits

Reviewing files that changed from the base of the PR and between 70951da and d0c7bcd.

📒 Files selected for processing (1)
  • packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/RunLifecycle.cpp

reachPosition reports a repeat between its two ladder walks, so a reporter
that aborted from Started still got a Repeated after the Aborted.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/RunLifecycle.cpp (1)

37-46: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Prevent duplicate Aborted reports during re-entrant aborts.

If the Created reporter calls abort() from Line 39, the nested call sets aborted_ at Line 45 and reports Aborted at Line 46. The outer call then continues and reports Aborted a second time. This produces Created, Aborted, Aborted for one cancellation. The reporter is invoked synchronously, so this path is reachable. (raw.githubusercontent.com)

Return when aborted_ becomes true after enterStagesUpTo(). Add a regression test for a Created reporter that calls abort().

Proposed fix
   enterStagesUpTo(rank(RunStage::Created));
+  if (aborted_) {
+    return;
+  }

   aborted_ = true;

Based on learnings, abort() must remain terminal under reporter re-entrancy, and no milestone may occur after Aborted.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/RunLifecycle.cpp`
around lines 37 - 46, Update RunLifecycle::abort() to re-check aborted_
immediately after enterStagesUpTo(rank(RunStage::Created)) and return if a
re-entrant Created reporter already aborted the run, preventing duplicate
Aborted reports or later milestones. Add a regression test where the Created
reporter calls abort() and verify the sequence is Created, Aborted exactly once
and remains terminal.

Sources: Learnings, MCP tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In
`@packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/RunLifecycle.cpp`:
- Around line 37-46: Update RunLifecycle::abort() to re-check aborted_
immediately after enterStagesUpTo(rank(RunStage::Created)) and return if a
re-entrant Created reporter already aborted the run, preventing duplicate
Aborted reports or later milestones. Add a regression test where the Created
reporter calls abort() and verify the sequence is Created, Aborted exactly once
and remains terminal.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6b4c443f-d393-425f-8182-e7793295f2cc

📥 Commits

Reviewing files that changed from the base of the PR and between d0c7bcd and 89c4c85.

📒 Files selected for processing (1)
  • packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/RunLifecycle.cpp

A high-water ladder can only move a run forwards, so the three backwards
rows of the css-animations-2 and css-transitions-2 event tables reported
nothing: active to before, after to active, and after to before. Chrome
fires an end, a start, and a start plus an end for those.

Milestones now carry which of the run's times they mean, since the same
milestone takes the interval start or the interval end depending on the
phase change that produced it.
@MatiPl01
MatiPl01 requested a review from pawicao August 12, 2026 08:56
Re-timing a running animation recomputes its iteration, so a high-water
mark swallowed every later boundary. The spec compares against the
previous frame and puts the boundary at the end of the iteration the run
drops back into.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/RunLifecycle.cpp`:
- Around line 62-68: Update RunLifecycle::abort() to recheck aborted_
immediately after reachPhase(RunPhase::Before) and return before reporting if a
re-entrant abort already completed it. Preserve the terminal behavior so no
milestone, including a duplicate RunMilestone::Aborted, occurs after the first
Aborted report, and add coverage for aborting from a Created reporter.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7c70e4dd-cc16-48fa-9fb6-1e35eb89acd6

📥 Commits

Reviewing files that changed from the base of the PR and between 89c4c85 and 51fe696.

📒 Files selected for processing (4)
  • packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/AnimationProgressProvider.cpp
  • packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/AnimationProgressProvider.h
  • packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/RunLifecycle.cpp
  • packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/RunLifecycle.h

Aborting from the Created reporter finishes the run inside the nested
call, and the outer one then reported Aborted a second time.
@MatiPl01
MatiPl01 merged commit ac433a6 into main Aug 12, 2026
14 checks passed
@MatiPl01
MatiPl01 deleted the @matipl01/animation-progress-changes branch August 12, 2026 12:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants