stackflow icon indicating copy to clipboard operation
stackflow copied to clipboard

feat(core): add prune API to clear event history

Open parkwoocheol opened this issue 3 months ago β€’ 2 comments

Summary

Adds prune() API to StackflowActions in @stackflow/core to manually clear past events and inactive activities.

Motivation

Stackflow's Event Sourcing pattern causes the event history to grow indefinitely. This leads to increased memory usage and re-calculation costs in long-running sessions. A mechanism to clear old history and release memory was required.

Features

  • actions.prune(): Clears event history while preserving the current stack state.
  • State Reconstruction: Reconstructs the stack using only enter-active and enter-done activities.

parkwoocheol avatar Nov 25 '25 02:11 parkwoocheol

⚠️ No Changeset found

Latest commit: 9583f125eb710f0878b0cb2da4c5ebc1ac7e9e14

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

changeset-bot[bot] avatar Nov 25 '25 02:11 changeset-bot[bot]

πŸ“ Walkthrough

Summary by CodeRabbit

  • New Features
    • Added a prune() action that clears historical events while reconstructing and maintaining the current application state, helping optimize memory usage by removing past event data.

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

Adds a new prune() action to the public actions surface and implements it to rebuild a minimal event history from currently active activities, replace stored events, and re-aggregate the stack; a unit test verifying prune behavior was added.

Changes

Cohort / File(s) Change Summary
Interface
core/src/interfaces/StackflowActions.ts
Added public method prune(): void to StackflowActions with JSDoc describing clearing past events and reconstructing state from active activities.
Core store
core/src/makeCoreStore.ts
Exposed a store object into action construction (getStack, events.value, setStackValue) and surfaced prune() on the actions object.
Action utilities
core/src/utils/makeActions.ts
Extended makeActions to accept store in ActionCreatorOptions and implemented prune() which: reads current stack, identifies active activities, builds a synthetic sequence of DomainEvents (Initialized, ActivityRegistered*, Pushed/Step events, Popped as applicable), replaces store.events.value, re-aggregates via aggregate(...), and applies the new stack via setStackValue. Added imports for aggregate, DomainEvent, makeEvent, and Stack.
Tests
core/src/makeCoreStore.spec.ts
Added test "makeCoreStore - prune이 호좜되면, 과거의 이벀트λ₯Ό μ •λ¦¬ν•˜κ³  ν˜„μž¬ μƒνƒœλ₯Ό μœ μ§€ν•©λ‹ˆλ‹€" that seeds past events, performs pushes/pops, asserts pre-prune stack, calls prune(), then asserts only active activities remain and events trimmed to the minimal synthetic set.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant Actions as Actions.prune()
    participant Store
    participant Events as Events.value
    participant Aggregate as aggregate()

    Caller->>Actions: prune()
    Actions->>Store: getStack()
    Store-->>Actions: current Stack

    rect rgb(230,245,235)
    Note over Actions: Filter active activities\n(build activity metadata list)
    Actions->>Actions: Build synthetic events:\n- Initialized\n- ActivityRegistered* (reuse metadata)\n- Pushed / StepPushed / StepReplaced\n- Popped (if needed)
    end

    Actions->>Events: events.value = [synthetic events]

    rect rgb(245,235,235)
    Actions->>Aggregate: aggregate(events.value)
    Aggregate-->>Actions: new Stack
    end

    Actions->>Store: setStackValue(new Stack)
    Store-->>Caller: stack & events updated

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Verify event ordering and flags when building synthetic events (e.g., skipEnterActiveState, activityContext).
  • Check transitionState filtering and selection of "active" activities (enter-active vs enter-done).
  • Ensure store.events.value replacement is safe (no stale references) and aggregation is deterministic.
  • Review the new test for edge cases (empty stack, single active activity, mixed states) and timing assumptions for event dates.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
βœ… Passed checks (2 passed)
Check name Status Explanation
Title check βœ… Passed The title 'feat(core): add prune API to clear event history' clearly and accurately summarizes the main change: adding a new prune API to the core module for clearing event history, which aligns with all modified files.
Description check βœ… Passed The description is well-detailed and directly related to the changeset, explaining the motivation for the prune API, its purpose in clearing event history while preserving stack state, and the features being introduced.
✨ Finishing touches
  • [ ] πŸ“ Generate docstrings
πŸ§ͺ Generate unit tests (beta)
  • [ ] Create PR with unit tests
  • [ ] Post copyable unit tests in a comment

πŸ“œ Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 93620891a6ddc289d96742c90b0421477f3ecf88 and 9583f125eb710f0878b0cb2da4c5ebc1ac7e9e14.

πŸ“’ Files selected for processing (1)
  • core/src/utils/makeActions.ts (2 hunks)
🧰 Additional context used
πŸ““ Path-based instructions (1)
**/*.{ts,tsx}

πŸ“„ CodeRabbit inference engine (AGENTS.md)

Write source in TypeScript with strict typing enabled across the codebase

Files:

  • core/src/utils/makeActions.ts
🧬 Code graph analysis (1)
core/src/utils/makeActions.ts (4)
core/src/interfaces/StackflowActions.ts (1)
  • StackflowActions (15-70)
core/src/Stack.ts (1)
  • Stack (50-57)
core/src/event-types/index.ts (1)
  • DomainEvent (12-22)
core/src/aggregate.ts (1)
  • aggregate (7-113)
πŸ”‡ Additional comments (8)
core/src/utils/makeActions.ts (8)

1-5: LGTM!

The new imports for aggregate, DomainEvent, makeEvent, and Stack are properly typed and necessary for the prune() implementation.


12-16: LGTM!

The store parameter is properly typed and provides the necessary access to stack state, events, and mutation capability for the prune() implementation.

Also applies to: 23-23


138-143: LGTM!

The guard against pruning a paused stack is appropriate and prevents loss of pausedEvents.


145-150: LGTM!

Including "exit-active" activities in the filter correctly preserves activities that are currently transitioning out, addressing the previous review concern.


152-158: LGTM!

The event date calculation ensures monotonic time progression, and preserving the original Initialized event's eventDate maintains temporal consistency.


160-202: LGTM!

The logic correctly preserves ALL activity registrations (not just active ones) including their paramsSchema metadata, addressing the previous concern about dropping inactive registrations.


204-229: LGTM!

The reconstruction logic correctly:

  • Preserves original entry semantics (Pushed vs Replaced) to maintain isRoot computation
  • Includes all activity metadata (activityContext)
  • Reconstructs steps with proper event types and metadata (hasZIndex)
  • Skips the first step appropriately (root step is represented in activity params)

This addresses previous concerns about entry semantics and step preservation.


231-240: LGTM!

Correctly extracts and preserves Popped events for exit-active activities, maintaining temporal ordering.


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 and usage tips.

coderabbitai[bot] avatar Nov 25 '25 02:11 coderabbitai[bot]