Skip to content

[Review Changes]: T3 - Server-side change detection engine #34253

@valentinpalkovic

Description

@valentinpalkovic

T3: Server-side change detection engine

Overview

Implement the server-side ChangeDetectionService and GitDiffProvider in core-server. This service consumes the builder's dependency map, runs git diff, traces affected stories using the three-category BFS algorithm (new/modified/affected), and publishes per-story change statuses to the StatusStore.

Depends on: T1, T3a, T3b

Scope

In scope

GitDiffProvider (new):

  • Encapsulates git CLI calls via child_process
  • Single fixed diff mode — all uncommitted changes:
    • git diff --name-only HEAD — modified/deleted tracked files
    • git diff --name-only HEAD --diff-filter=A — newly tracked (staged) files
    • git ls-files --others --exclude-standard — untracked new files
  • Returns { changedFiles: string[], newFiles: string[] } or throws a typed error

ChangeDetectionService (new):

  • Instantiated in storybookDevServer() before previewBuilder.start()
  • Registers builder.onModuleGraphChange(cb) early — if undefined, change detection is unavailable
  • Reads features.changeDetection (boolean). If false, skip instantiation and log "Change detection disabled."
  • On each callback: runs git diff, traces changed files through the dependency map using three-category BFS:
    • new → story file is in the added-files set (untracked/newly tracked)
    • modified → story(ies) at the minimum reachable BFS distance from a changed file. Ties at the same level → all marked modified
    • affected → stories reachable at greater distances than the minimum level
  • Publishes results to StatusStore using a diff patch strategy (set added/updated, unset removed)
  • Debounces live-update rescans
  • Exposes a scan readiness signal (promise) for addon-mcp

StatusStore writes (uses types from T3a + T3b):

  • typeId: 'storybook/change-detection'
  • value: 'status-value:new', 'status-value:modified', or 'status-value:affected'
  • data: { changedFiles: string[] }
  • sidebarContextMenu: false

Out of scope

  • StatusValue type extension (T3a, T3b)
  • Manager-side consumption (T7)
  • Any UI changes (T5)
sequenceDiagram
    participant Builder as builder-vite
    participant CDS as ChangeDetectionService
    participant Git as GitDiffProvider
    participant SIG as StoryIndexGenerator
    participant SS as StatusStore

    Builder->>CDS: onModuleGraphChange(dependencyMap)
    CDS->>Git: git diff HEAD + git ls-files --others
    Git-->>CDS: changedFiles + newFiles
    CDS->>SIG: match file paths to story specifiers
    CDS->>CDS: three-category BFS trace (new/modified/affected)
    CDS->>SS: diff patch (set new/modified/affected, unset removed)
Loading

Acceptance Criteria

  • Modifying a component marks nearest stories as modified and further stories as affected
  • Changing Button.module.css marks Button.stories.tsx as modified but Header.stories.tsx as affected (greater import distance)
  • If two stories are at the same minimum distance, both are modified
  • Adding a new story file marks its stories as new
  • Reverting a file removes its stories from the StatusStore (diff patch)
  • If not in a git repo, no statuses written; startup message logged
  • Setting changeDetection: false disables the feature; startup message logged
  • All uncommitted changes (staged, unstaged, untracked) are detected
  • Live file changes trigger debounced rescan
  • Scan readiness signal exposed and resolves after first scan

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions