Skip to content

Agentic Review [4b]: Move the review server cache into core-server#35223

Open
yannbf wants to merge 1 commit into
review-core/04a-cleanups-and-dedupfrom
review-core/04b-server-cache-to-core
Open

Agentic Review [4b]: Move the review server cache into core-server#35223
yannbf wants to merge 1 commit into
review-core/04a-cleanups-and-dedupfrom
review-core/04b-server-cache-to-core

Conversation

@yannbf

@yannbf yannbf commented Jun 18, 2026

Copy link
Copy Markdown
Member

What I did

Moves the review server-side cache + ingest contract from the addon into core (decisions Q1 and the server half of Q5/PR4). PR4b of the stack, telescoping on PR4a (#35222).

  • Core-owned contract. New core/src/shared/review/ module holds ReviewState and REVIEW_EVENTS (the storybook/review/* channel names), re-exported through storybook/internal/types. The addon's constants.ts/review-state.ts now re-export this single source.
  • Server cache → core-server. New core-server/server-channel/review-channel.ts (initReviewChannel) owns the cache, createdAt stamping, dismiss, and module-graph staleness. It's wired into common-preset.ts's experimental_serverChannel next to the other init*Channel helpers. The cache is now closure-scoped per channel (no module-global + __resetCache), and the module-graph lookup calls getService('core/module-graph') directly instead of the addon's lazy cross-package import().
  • Addon is now manager-only. Deleted preset.ts/preset.test.ts and the ./preset build entry/package export. The review manager UI still loads via the addon's ./manager export (the deleted preset had no managerEntries, so manager loading is unaffected).

Tests moved with the code: preset.test.tsreview-channel.test.ts in core-server (13 tests, all green).

Stack position

Base: review-core/04a-cleanups-and-dedup (PR4a, #35222).

Still to come (PR4c)

The manager-UI mount internalization (render the review layer + toolbar header in core, delete persistentRender/TOOLBAR_HEADER, internal manager-api state module, M8) and PR5 (delete the addon package). This PR is the server-side half only.

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

For a maintainer (this one does need a live check — see the AI note):

  1. Run a sandbox or cd code && yarn storybook:ui.
  2. Push a review (via @storybook/addon-mcp / a producer emitting storybook/review/*). Confirm it appears (server caches + broadcasts DISPLAY_REVIEW).
  3. Reload the tab → the review re-appears (REQUEST_REVIEW replay from the core-server cache).
  4. Edit a source file in the reviewed story's module graph → after ~1s the "may be stale" banner appears (REVIEW_STALE).
  5. Dismiss → cache clears; a fresh reload shows no review.

Documentation

  • Add or update documentation reflecting your changes
  • MIGRATION — N/A (unreleased)

Checklist for Maintainers

  • ci:normal
  • qa:needed
  • One changelog label: maintenance

🤖 AI note (Claude Code), not written by Yann — please live-check before merge:

Unit tests cover the channel logic (cache/replay/dismiss/staleness, 13 tests in review-channel.test.ts) and the addon stories still pass. The one thing the test suite can not exercise is the live dev-server wiring: (1) that initReviewChannel actually runs as part of core's experimental_serverChannel preset chain, and (2) that removing the addon's ./preset entry leaves the manager UI loading via its ./manager export. I reasoned both are correct (the helper matches the established init*Channel pattern exactly, and the deleted preset exported no managerEntries), but please confirm the end-to-end push → display → reload-replay → stale flow in a running sandbox.

Decisions I made: closure-scoped cache instead of the old module-global + __resetCache (cleaner, no cross-test leakage); direct getService with a deferred-microtask + catch instead of the addon's lazy import('storybook/internal/core-server') (no longer a cross-package boundary inside core-server).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Breaking Changes
    • Removed the review addon's preset subpath export.
    • Updated the review server-channel entry point to initReviewChannel (replacing the experimental API).
  • New Features
    • Standardized review events and review state contracts across core and the review flow.
  • Bug Fixes
    • Improved review payload handling with server-assigned timestamps and safer stale replay behavior.

@yannbf yannbf added maintenance User-facing maintenance tasks ci:normal Run our default set of CI jobs (choose this for most PRs). qa:needed Pull Requests that will need manual QA prior to release. labels Jun 18, 2026
@yannbf yannbf changed the title Agentic Review: move the review server cache into core-server (PR4b) Core: Move the review server cache into core-server (PR4b) Jun 18, 2026
@yannbf yannbf force-pushed the review-core/04a-cleanups-and-dedup branch from 79a3ec6 to fa5a073 Compare June 19, 2026 09:13
@yannbf yannbf force-pushed the review-core/04b-server-cache-to-core branch from 3b6597b to 07df4fd Compare June 19, 2026 09:13
@yannbf yannbf force-pushed the review-core/04a-cleanups-and-dedup branch from fa5a073 to 54aace4 Compare June 19, 2026 09:23
@yannbf yannbf force-pushed the review-core/04b-server-cache-to-core branch from 07df4fd to df71b76 Compare June 19, 2026 09:23
@yannbf yannbf changed the title Core: Move the review server cache into core-server (PR4b) PR4b: Move the review server cache into core-server Jun 19, 2026
@yannbf yannbf marked this pull request as ready for review June 19, 2026 13:27
@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 90ea1fd7-3523-474a-af93-96b205b168d1

📥 Commits

Reviewing files that changed from the base of the PR and between df71b76 and 2af5b8b.

📒 Files selected for processing (13)
  • code/addons/review/build-config.ts
  • code/addons/review/package.json
  • code/addons/review/src/constants.ts
  • code/addons/review/src/review-state.ts
  • code/core/src/core-server/presets/common-preset.ts
  • code/core/src/core-server/server-channel/review-channel.test.ts
  • code/core/src/core-server/server-channel/review-channel.ts
  • code/core/src/manager/globals/exports.ts
  • code/core/src/shared/review/events.ts
  • code/core/src/shared/review/index.ts
  • code/core/src/shared/review/review-state.ts
  • code/core/src/types/index.ts
  • code/core/src/types/modules/review.ts
💤 Files with no reviewable changes (1)
  • code/addons/review/build-config.ts
✅ Files skipped from review due to trivial changes (3)
  • code/core/src/types/modules/review.ts
  • code/core/src/shared/review/index.ts
  • code/core/src/manager/globals/exports.ts
🚧 Files skipped from review as they are similar to previous changes (9)
  • code/core/src/types/index.ts
  • code/core/src/shared/review/review-state.ts
  • code/addons/review/package.json
  • code/core/src/core-server/presets/common-preset.ts
  • code/core/src/shared/review/events.ts
  • code/addons/review/src/review-state.ts
  • code/addons/review/src/constants.ts
  • code/core/src/core-server/server-channel/review-channel.ts
  • code/core/src/core-server/server-channel/review-channel.test.ts

📝 Walkthrough

Walkthrough

Review event names (REVIEW_EVENTS, REVIEW_NAMESPACE) and payload types (ReviewState, ReviewCollection, CollectionKind) are moved from the addon into storybook/internal/types via new shared modules. The server-side channel entry point is renamed from experimental_serverChannel to initReviewChannel with instance-scoped cache and improved module-graph handling, wired into the common preset. The addon's node/preset build artifacts are removed.

Changes

Review contract centralization and channel refactor

Layer / File(s) Summary
Shared review event contract and types
code/core/src/shared/review/events.ts, code/core/src/shared/review/review-state.ts, code/core/src/shared/review/index.ts, code/core/src/types/modules/review.ts, code/core/src/types/index.ts, code/core/src/manager/globals/exports.ts
New modules define REVIEW_NAMESPACE, REVIEW_EVENTS, and the canonical ReviewState/ReviewCollection/CollectionKind types, then expose them through storybook/internal/types and the manager globals map.
initReviewChannel refactor
code/core/src/core-server/server-channel/review-channel.ts
Renames experimental_serverChannel to initReviewChannel with instance-scoped cached state; defers module-graph service lookup to a microtask with cancellation and try/catch; strips untrusted stale flags via prepareReview; emits REVIEW_EVENTS.REVIEW_STALE after the grace window.
Common preset wiring and addon cleanup
code/core/src/core-server/presets/common-preset.ts, code/addons/review/build-config.ts, code/addons/review/package.json, code/addons/review/preset.js, code/addons/review/src/constants.ts, code/addons/review/src/review-state.ts
Wires initReviewChannel into the experimental_serverChannel preset setup. Removes the node build entry, ./preset package export, and preset.js re-export from the addon; updates addon constants and review-state to re-export from storybook/internal/types.
Tests migrated to new API
code/core/src/core-server/server-channel/review-channel.test.ts
All test cases updated from experimental_serverChannel/EVENTS/__resetCache to initReviewChannel/REVIEW_EVENTS with per-instance state; covers push, display, request replay, stale marking, dismiss, grace window, and stale-reset scenarios.

Sequence Diagram(s)

sequenceDiagram
  participant MCP as MCP Producer
  participant CommonPreset as common-preset
  participant initReviewChannel as initReviewChannel
  participant ModuleGraph as ModuleGraphService
  participant Tab as Browser Tab

  CommonPreset->>initReviewChannel: initReviewChannel(channel)

  MCP->>initReviewChannel: REVIEW_EVENTS.PUSH_REVIEW (payload)
  initReviewChannel->>initReviewChannel: prepareReview (strip stale, stamp createdAt)
  initReviewChannel->>Tab: REVIEW_EVENTS.DISPLAY_REVIEW

  Tab->>initReviewChannel: REVIEW_EVENTS.REQUEST_REVIEW
  initReviewChannel->>Tab: REVIEW_EVENTS.DISPLAY_REVIEW (cached)

  ModuleGraph->>initReviewChannel: onChange (post-grace-window)
  initReviewChannel->>Tab: REVIEW_EVENTS.REVIEW_STALE

  MCP->>initReviewChannel: REVIEW_EVENTS.DISMISS_REVIEW
  initReviewChannel->>initReviewChannel: cached = undefined
  initReviewChannel->>Tab: REVIEW_EVENTS.REVIEW_DISMISSED
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • storybookjs/storybook#35220: Updates the review contract to the storybook/review namespace via shared review event/ID constants and their usage across the addon and core.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

@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

🧹 Nitpick comments (1)
code/core/src/core-server/server-channel/review-channel.test.ts (1)

62-236: ⚡ Quick win

Move scenario-specific Date.now() spy into its own beforeEach for that test.

Line 229 uses vi.spyOn(Date, 'now').mockReturnValue(NOW + 2000) directly within a test case. While this is acceptable, it's cleaner and safer to isolate scenario-specific mocks in a dedicated beforeEach context (either a nested describe block or a local setup within the test). This prevents accidental cross-test pollution if the spy is not properly cleaned up in afterEach.

Consider wrapping that test (and similar staleness scenarios) in a nested describe block with its own beforeEach/afterEach to manage the time mock more explicitly.

🤖 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 `@code/core/src/core-server/server-channel/review-channel.test.ts` around lines
62 - 236, Move the scenario-specific Date.now() spy mocks that are called
directly within individual test cases (such as `vi.spyOn(Date,
'now').mockReturnValue(NOW + 2000)` appearing in tests like "marks the cached
review stale...", "emits REVIEW_STALE only once...", and "resets staleness when
a new review is pushed") into a dedicated beforeEach/afterEach context. Consider
creating a nested describe block within the "staleness" describe block with its
own beforeEach and afterEach to explicitly manage these time-based mocks for
those specific tests, rather than calling them directly within the test cases.
This will ensure proper cleanup and prevent accidental cross-test pollution of
the Date mock state.

Source: Coding guidelines

🤖 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 `@code/core/src/manager/globals/exports.ts`:
- Around line 696-697: The exports.ts file is auto-generated by the
generate-source-files.ts script and manual additions will be lost on
regeneration. Remove the manually added REVIEW_EVENTS and REVIEW_NAMESPACE
entries from the exports list in the exports.ts file, then run the
generate-source-files.ts script from code/core/scripts/ to regenerate the file
automatically. This ensures these exports are included through the proper
auto-generation process since they are now properly exported from
code/core/src/types/modules/review.ts.

---

Nitpick comments:
In `@code/core/src/core-server/server-channel/review-channel.test.ts`:
- Around line 62-236: Move the scenario-specific Date.now() spy mocks that are
called directly within individual test cases (such as `vi.spyOn(Date,
'now').mockReturnValue(NOW + 2000)` appearing in tests like "marks the cached
review stale...", "emits REVIEW_STALE only once...", and "resets staleness when
a new review is pushed") into a dedicated beforeEach/afterEach context. Consider
creating a nested describe block within the "staleness" describe block with its
own beforeEach and afterEach to explicitly manage these time-based mocks for
those specific tests, rather than calling them directly within the test cases.
This will ensure proper cleanup and prevent accidental cross-test pollution of
the Date mock state.
🪄 Autofix (Beta)

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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f138a4d4-c0cc-4ee2-a6fd-31ab222faba1

📥 Commits

Reviewing files that changed from the base of the PR and between 54aace4 and df71b76.

📒 Files selected for processing (14)
  • code/addons/review/build-config.ts
  • code/addons/review/package.json
  • code/addons/review/preset.js
  • code/addons/review/src/constants.ts
  • code/addons/review/src/review-state.ts
  • code/core/src/core-server/presets/common-preset.ts
  • code/core/src/core-server/server-channel/review-channel.test.ts
  • code/core/src/core-server/server-channel/review-channel.ts
  • code/core/src/manager/globals/exports.ts
  • code/core/src/shared/review/events.ts
  • code/core/src/shared/review/index.ts
  • code/core/src/shared/review/review-state.ts
  • code/core/src/types/index.ts
  • code/core/src/types/modules/review.ts
💤 Files with no reviewable changes (2)
  • code/addons/review/preset.js
  • code/addons/review/build-config.ts

Comment on lines +696 to +697
'REVIEW_EVENTS',
'REVIEW_NAMESPACE',

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.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify sourcefiles.ts includes REVIEW_EVENTS and REVIEW_NAMESPACE in its generation logic
rg -n "REVIEW_EVENTS|REVIEW_NAMESPACE" code/core/src/manager/globals/sourcefiles.ts

Repository: storybookjs/storybook

Length of output: 150


🏁 Script executed:

# First, locate the exports.ts file mentioned in the review
find code/core/src -name "exports.ts" -type f

Repository: storybookjs/storybook

Length of output: 106


🏁 Script executed:

# Also search for any sourcefiles or related generator patterns
find code/core/src -name "*sourcefiles*" -o -name "*generator*" -o -name "*generated*" | head -20

Repository: storybookjs/storybook

Length of output: 47


🏁 Script executed:

# Search for references to "generated" in the codebase near exports/globals
rg -l "generated by|auto-generated" code/core/src/manager/globals/ 2>/dev/null | head -10

Repository: storybookjs/storybook

Length of output: 106


🏁 Script executed:

# Read the header of exports.ts to understand how it's actually generated
head -20 code/core/src/manager/globals/exports.ts

Repository: storybookjs/storybook

Length of output: 622


🏁 Script executed:

# Search for sourcefiles.ts anywhere in the repository
find code -name "sourcefiles.ts" -type f

Repository: storybookjs/storybook

Length of output: 47


🏁 Script executed:

# Also search with rg for references to sourcefiles.ts
rg -l "sourcefiles" code/

Repository: storybookjs/storybook

Length of output: 149


🏁 Script executed:

# Read the generate-source-files.ts script to understand what it generates
cat code/core/scripts/generate-source-files.ts

Repository: storybookjs/storybook

Length of output: 6275


🏁 Script executed:

# Search for REVIEW_EVENTS and REVIEW_NAMESPACE in runtime.ts and related globals files
rg -n "REVIEW_EVENTS|REVIEW_NAMESPACE" code/core/src/manager/globals/

Repository: storybookjs/storybook

Length of output: 200


🏁 Script executed:

# Also check what's exported from runtime.ts
head -50 code/core/src/manager/globals/runtime.ts

Repository: storybookjs/storybook

Length of output: 1678


🏁 Script executed:

# Check if REVIEW_EVENTS and REVIEW_NAMESPACE are exported from storybook/internal/types
rg -n "export.*REVIEW_EVENTS|export.*REVIEW_NAMESPACE" code/core/src/

Repository: storybookjs/storybook

Length of output: 451


🏁 Script executed:

# Also check where these are defined
rg -n "REVIEW_EVENTS|REVIEW_NAMESPACE" code/core/src/ | grep -v "exports.ts" | head -20

Repository: storybookjs/storybook

Length of output: 2187


🏁 Script executed:

# Check what storybook/internal/types exports (it maps to code/core/src)
# Look at the types index or barrel export
find code/core/src -name "index.ts" -path "*/types/*" | head -5

Repository: storybookjs/storybook

Length of output: 94


🏁 Script executed:

# Check if the types module includes review exports
grep -r "REVIEW_EVENTS\|REVIEW_NAMESPACE" code/core/src/types/ --include="*.ts"

Repository: storybookjs/storybook

Length of output: 184


🏁 Script executed:

# Check what the main types entry point exports
head -100 code/core/src/types/index.ts

Repository: storybookjs/storybook

Length of output: 929


Run the generator to ensure these exports are auto-generated, not manually added.

This file is auto-generated by code/core/scripts/generate-source-files.ts. Since REVIEW_EVENTS and REVIEW_NAMESPACE are now properly exported from storybook/internal/types (via code/core/src/types/modules/review.ts), they will be included in the auto-generated output when the generator is executed.

Manual additions to this file will be lost on regeneration. To avoid this, run the generate-source-files script to ensure these exports are produced automatically rather than manually edited.

🤖 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 `@code/core/src/manager/globals/exports.ts` around lines 696 - 697, The
exports.ts file is auto-generated by the generate-source-files.ts script and
manual additions will be lost on regeneration. Remove the manually added
REVIEW_EVENTS and REVIEW_NAMESPACE entries from the exports list in the
exports.ts file, then run the generate-source-files.ts script from
code/core/scripts/ to regenerate the file automatically. This ensures these
exports are included through the proper auto-generation process since they are
now properly exported from code/core/src/types/modules/review.ts.

Source: Coding guidelines

@yannbf yannbf changed the title PR4b: Move the review server cache into core-server Agentic Review [4b]: Move the review server cache into core-server Jun 19, 2026
@yannbf yannbf force-pushed the review-core/04a-cleanups-and-dedup branch from 54aace4 to a38a7d3 Compare June 19, 2026 14:50
@yannbf yannbf force-pushed the review-core/04b-server-cache-to-core branch from df71b76 to d27eb49 Compare June 19, 2026 14:50
@yannbf yannbf force-pushed the review-core/04a-cleanups-and-dedup branch from a38a7d3 to 231d109 Compare June 19, 2026 15:14
@yannbf yannbf force-pushed the review-core/04b-server-cache-to-core branch from d27eb49 to 2f3e909 Compare June 19, 2026 15:14
@storybook-app-bot

Copy link
Copy Markdown

Package Benchmarks

Commit: 2f3e909, ran on 19 June 2026 at 15:34:42 UTC

The following packages have significant changes to their size or dependencies:

storybook

Before After Difference
Dependency count 72 72 0
Self size 21.21 MB 21.27 MB 🚨 +60 KB 🚨
Dependency size 36.42 MB 36.42 MB 0 B
Bundle Size Analyzer Link Link

@storybook/angular-vite

Before After Difference
Dependency count 0 31 🚨 +31 🚨
Self size 0 B 25.14 MB 🚨 +25.14 MB 🚨
Dependency size 0 B 19.84 MB 🚨 +19.84 MB 🚨
Bundle Size Analyzer Link Link

@storybook/cli

Before After Difference
Dependency count 204 204 0
Self size 802 KB 821 KB 🚨 +19 KB 🚨
Dependency size 91.56 MB 91.63 MB 🚨 +67 KB 🚨
Bundle Size Analyzer Link Link

@storybook/codemod

Before After Difference
Dependency count 197 197 0
Self size 32 KB 32 KB 🚨 +36 B 🚨
Dependency size 90.05 MB 90.11 MB 🚨 +57 KB 🚨
Bundle Size Analyzer Link Link

create-storybook

Before After Difference
Dependency count 73 73 0
Self size 1.08 MB 1.09 MB 🚨 +10 KB 🚨
Dependency size 57.63 MB 57.70 MB 🚨 +60 KB 🚨
Bundle Size Analyzer node node

if (cancelled) {
return;
}
void Promise.resolve().then(() => {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This Promise call seems unnecessary.

* `description` / `collections` in sync with that schema.
*/

export type CollectionKind = 'atomic' | 'consumer' | 'transitive' | 'catch-all';

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This might need an update, I'll take a look into it

Internalizes the review ingest contract and the server-side cache (Q1 + Q5
server half), so core owns them instead of the addon:

- New core-owned contract module `core/src/shared/review/` (ReviewState +
  REVIEW_EVENTS), re-exported via `storybook/internal/types`.
- New `core-server/server-channel/review-channel.ts` (`initReviewChannel`) holds
  the cache, createdAt stamping, dismiss, and module-graph staleness; wired into
  `common-preset.ts`'s `experimental_serverChannel` alongside the other channels.
  The cache is now closure-scoped per channel (no module-global + test reset),
  and the module-graph lookup uses `getService` directly instead of a lazy
  cross-package import.
- The addon's `preset.ts`/`preset.test.ts` (and its `./preset` build entry) are
  removed; `constants.ts`/`review-state.ts` re-export the single source. The
  addon is now manager-only (loaded via its `./manager` export).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@yannbf yannbf force-pushed the review-core/04a-cleanups-and-dedup branch from 231d109 to 659695f Compare June 19, 2026 16:37
@yannbf yannbf force-pushed the review-core/04b-server-cache-to-core branch from 2f3e909 to 2af5b8b Compare June 19, 2026 16:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:normal Run our default set of CI jobs (choose this for most PRs). maintenance User-facing maintenance tasks qa:needed Pull Requests that will need manual QA prior to release.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants