Skip to content

Agentic Setup: Add observability#34510

Merged
Sidnioulz merged 35 commits intoproject/sb-agentic-setupfrom
sidnioulz/agentic-telemetry-ws1
Apr 14, 2026
Merged

Agentic Setup: Add observability#34510
Sidnioulz merged 35 commits intoproject/sb-agentic-setupfrom
sidnioulz/agentic-telemetry-ws1

Conversation

@Sidnioulz
Copy link
Copy Markdown
Member

@Sidnioulz Sidnioulz commented Apr 9, 2026

What I did

  • Added telemetry events for the new sb ai command
  • Added a CLI hook when running as an agent to:
    • detect some changes to the repo / SB config
    • infer the work done by agents since running sb ai setup
    • report back to telemetry so we can confirm if agents ran well
  • Ensured agents running in the cloud have an anonymous user ID so we can link their CLI commands together
  • Added addon MCP to the definition of satellite addons (it had been forgotten)
  • Reworked the trigger logic for ghost stories
    • Decoupled from the story creation modal
    • Runs once per Storybook instance instead of once per instance on the first session only
    • Runs 10 minutes after the app has started up (at this stage the server likely has CPU capacity because everything's booted up)
  • Added tests
  • Added a debug telemetry server to help us work on telemetry and observe its behaviour

What I didn't do

The following is left to do, in this or a follow-up PR:

  • In Vitest, detect if we're part of a ai-prepare run
  • If so, add a new test reporter that sends telemetry to Storybook
  • Customise scoring metrics for ai-prepare-generated stories in the dev run and in the Vitest runs of the self-healing loop, if needed depending on what @kasperpeulen does via the LLM and what he does via afterEach hooks
  • Double check with @yannbf which PR should switch from AI generated titles to ai-generated tags

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

  1. Check this branch out, install and compile
  2. Run node mock-telemetry-receiver.ts to start the telemetry debug server
  3. In a new tab, run export STORYBOOK_TELEMETRY_URL=http://localhost:6007/event-log to point to the debug server
Run sb ai prepare on a freshly installed Storybook instance

In a project without Storybook, run:

export STORYBOOK_TELEMETRY_URL=http://localhost:6007/event-log
npx storybook@0.0.0-pr-34510-sha-c891c832 init

Go through the install, then fire up an agent and prompt it:

set up Storybook by running npx storybook@0.0.0-pr-34510-sha-c891c832 ai prepare
ai-prepare.log

You should see ai-prepare, vitest run, boot:doctor and ai-prepare-evidence in the log. You should see that we capture changes to the preview file.

Next run Storybook, and press "+" to get the ghost stories data.

You should see a new ai-prepare-evidence event fired counting the number of AI written stories.

Caution

Currently this event is not always firing. Must debug further. This is probably because sb ai prepare still creates stories with an AI Generated title but the telemetry looks for an ai-generated tag. I expect @yannbf might have already changed this on another PR so will sync with him.

Next wait 10 minutes until the AI prepare test run triggers.

You should see an ai-prepare-story-scoring event.
dev-after-ai-prepare.log

Init fresh project, open as human and trigger legacy ghost story flow

In a project without Storybook, run:

export STORYBOOK_TELEMETRY_URL=http://localhost:6007/event-log
npx storybook@0.0.0-pr-34510-sha-c891c832 init

Go through the install, then in the UI, click the "+" button in the sidebar. Notice the ghost-stories event in the debugger.

basic-init.log

Documentation

ø

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

🦋 Canary release

This pull request has been released as version 0.0.0-pr-34510-sha-c891c832. Try it out in a new sandbox by running npx storybook@0.0.0-pr-34510-sha-c891c832 sandbox or in an existing project with npx storybook@0.0.0-pr-34510-sha-c891c832 upgrade.

More information
Published version 0.0.0-pr-34510-sha-c891c832
Triggered by @Sidnioulz
Repository storybookjs/storybook
Branch sidnioulz/agentic-telemetry-ws1
Commit c891c832
Datetime Sat Apr 11 14:14:33 UTC 2026 (1775916873)
Workflow run 24284265502

To request a new release of this pull request, mention the @storybookjs/core team.

core team members can create a new canary release here or locally with gh workflow run --repo storybookjs/storybook publish.yml --field pr=34510

Summary by CodeRabbit

  • Telemetry

    • New ai-prepare-evidence event, improved AI-setup tracking, evidence collection (preview-change, AI-authored story counts) and preserved CI metadata for agent-detected runs.
  • UX / Behavior

    • Ghost-stories now trigger from the manager 10 minutes after preview initializes (once-per-project gate) for ai setup sessions.
  • Chores

    • Added mock telemetry receiver and registered @storybook/addon-mcp.

Co-designing telemetry enhancements for tracking human vs agent-driven
Storybook instances and feature adoption metrics.

- docs/superpowers/specs/2026-04-07-telemetry-enhancements-design.md:
  comprehensive design covering 3 sequential streams (metadata enrichment,
  sb ai prepare events, ghost-stories broadening). Section 1 approved,
  sections 2-8 drafted awaiting user review tomorrow.

- scripts/spike-extract-features.ts: throwaway timing spike that proves
  full inline feature extraction is feasible (~640ms for 505 story files,
  ~38ms marginal cost over existing parse work). Will be deleted at end
  of Stream A.
@Sidnioulz Sidnioulz requested a review from Copilot April 9, 2026 08:05
@Sidnioulz Sidnioulz self-assigned this Apr 9, 2026
@Sidnioulz Sidnioulz requested a review from kylegach as a code owner April 9, 2026 08:06
@Sidnioulz Sidnioulz added the build Internal-facing build tooling & test updates label Apr 9, 2026
@Sidnioulz Sidnioulz requested a review from jonniebigodes as a code owner April 9, 2026 08:06
@nx-cloud
Copy link
Copy Markdown

nx-cloud Bot commented Apr 9, 2026

View your CI Pipeline Execution ↗ for commit f51a483

Command Status Duration Result
nx run-many -t compile,check,knip,test,lint,fmt... ✅ Succeeded 7m 36s View ↗

☁️ Nx Cloud last updated this comment at 2026-04-14 13:52:30 UTC

Comment thread code/core/src/core-server/withTelemetry.ts Outdated
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

Adds observability for agent-driven workflows and related telemetry plumbing across CLI + core, including sb ai prepare start telemetry, evidence checkpoints, agent-in-CI metadata retention, and a redesigned ghost-stories trigger/gate. This supports WS1 “agentic telemetry” by enabling correlation across agent sessions and increasing ghost-stories sampling coverage without user interaction.

Changes:

  • Add sb ai prepare trait capture, optional YAML frontmatter output, and cache a baseline “ai-setup pending” record for later evidence collection.
  • Add an ai-setup-evidence telemetry event type and a withTelemetry() hook to emit evidence events for agent runs (plus preserve userSince in CI when an agent is detected).
  • Redesign ghost-stories triggering (10-minute delayed manager trigger) and simplify the server-side “once ever” gate; add local telemetry tooling scripts.

Reviewed changes

Copilot reviewed 23 out of 24 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
scripts/spike-extract-features.ts Adds a feature-extraction timing spike script (planning/tooling).
scripts/mock-telemetry-receiver.ts Adds a local HTTP server to receive/log telemetry events for debugging/testing.
docs/superpowers/specs/2026-04-08-ws1-agentic-telemetry-plan-pm.md PM-facing plan describing WS1 telemetry changes.
docs/superpowers/specs/2026-04-08-ws1-agentic-telemetry-plan-engineer.md Engineering implementation plan for WS1 changes.
docs/superpowers/specs/2026-04-07-telemetry-enhancements-design.md Design doc capturing telemetry decisions and WS1/WS2 split.
code/lib/cli-storybook/src/bin/run.ts Adds --frontmatter flag to sb ai prepare.
code/lib/cli-storybook/src/ai/types.ts Adds AiPrepareTraits and extends options with frontmatter.
code/lib/cli-storybook/src/ai/setup-requirements.ts Adds prompt-adjacent “requirements” helpers (preview snapshot/hash, AI story detection).
code/lib/cli-storybook/src/ai/prompt.ts Threads a traits accumulator through prompt generation output.
code/lib/cli-storybook/src/ai/index.ts Sends ai-prepare telemetry, writes pending-record baseline, supports frontmatter output.
code/core/src/telemetry/types.ts Adds ai-setup-evidence to the EventType union.
code/core/src/telemetry/storybook-metadata.ts Preserves userSince in CI when an agent is detected.
code/core/src/telemetry/storybook-metadata.test.ts Adds coverage for “agent in CI keeps userSince”.
code/core/src/telemetry/index.ts Re-exports getAiSetupPending and SESSION_TIMEOUT for evidence collection.
code/core/src/telemetry/event-cache.ts Adds getAiSetupPending() cache helper for pending setup record.
code/core/src/telemetry/detect-agent.test.ts Hardens tests by clearing/restoring ambient agent env vars.
code/core/src/manager/components/sidebar/useGhostStoriesTrigger.ts Adds 10-minute delayed trigger after PREVIEW_INITIALIZED.
code/core/src/manager/components/sidebar/Sidebar.tsx Calls useGhostStoriesTrigger() from the Sidebar.
code/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx Removes modal-based ghost-stories trigger.
code/core/src/core-server/withTelemetry.ts Adds agent-gated evidence collection hook and preview hash comparison.
code/core/src/core-server/withTelemetry.test.ts Adds detect-agent mocking support for new behavior.
code/core/src/core-server/server-channel/ghost-stories-channel.ts Simplifies ghost-stories gate to a once-ever lastEvents['ghost-stories'] check.
code/core/src/core-server/server-channel/ghost-stories-channel.test.ts Updates tests to match the simplified gate (removes sessionId checks).
code/core/src/common/satellite-addons.ts Adds @storybook/addon-mcp to satellite addons list.
Comments suppressed due to low confidence (1)

code/lib/cli-storybook/src/ai/index.ts:95

  • The renderer/builder gate is using &&, which allows unsupported combinations (e.g. React+Webpack or Vue+Vite) to pass as long as one of the two matches. Since the message says the feature is only available for React renderer with Vite builder, the condition should reject if either differs (use ||).
  if (
    projectInfo.rendererPackage !== '@storybook/react' &&
    projectInfo.builderPackage !== '@storybook/builder-vite'
  ) {
    logger.log(
      'AI-assisted setup is currently only available for projects using the React renderer with Vite builder. Detected renderer: ' +
        projectInfo.rendererPackage +
        ', builder: ' +
        projectInfo.builderPackage

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

Comment thread code/core/src/core-server/withTelemetry.ts Outdated
Comment on lines 294 to +301
if (enableTelemetry) {
telemetry('boot', { eventType }, { stripMetadata: true });
}

if (enableTelemetry) {
// Fire-and-forget: don't await, don't block the command
collectAiSetupEvidence(eventType, options).catch(() => {});
}
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

New evidence collection behavior is introduced here (fire-and-forget call into collectAiSetupEvidence), but withTelemetry.test.ts doesn't cover any of the new gating/payload logic. Please add unit tests that verify: (1) no event when no agent, (2) no event when no pending record, (3) no event when pending is expired, and (4) event payload fields (previewChanged/doctorRanSinceSetup) when all gates pass.

Copilot uses AI. Check for mistakes.
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.

Correct, must be fixed.

Comment thread code/lib/cli-storybook/src/ai/index.ts Outdated
Comment thread scripts/mock-telemetry-receiver.ts Outdated
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 9, 2026

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

Walkthrough

Adds AI-setup telemetry (CLI emits ai-prepare, caches preview snapshot, server collects evidence and emits ai-prepare-evidence when gated), reworks ghost-stories trigger to a manager hook (10-minute delayed GHOST_STORIES_REQUEST), and introduces preview snapshot utilities, CLI frontmatter, tests, scripts, and docs.

Changes

Cohort / File(s) Summary
Telemetry core & server
code/core/src/core-server/withTelemetry.ts, code/core/src/core-server/withTelemetry.test.ts, code/core/src/telemetry/event-cache.ts, code/core/src/telemetry/index.ts, code/core/src/telemetry/types.ts, code/core/src/telemetry/storybook-metadata.ts, code/core/src/telemetry/storybook-metadata.test.ts, code/core/src/telemetry/detect-agent.test.ts, code/core/src/telemetry/ai-prepare-evidence.ts, code/core/src/telemetry/ai-prepare-evidence.test.ts
Adds evidence-collection API (collectAiPrepareEvidence) and getAiSetupPending() export; extends telemetry event types; withTelemetry fire-and-forgets evidence collection; CI agent-detection gating adjusted; new ai-prepare-evidence module and tests implement preview-change/AI-story detection and telemetry emission.
CLI AI flow & helpers
code/lib/cli-storybook/src/ai/index.ts, code/lib/cli-storybook/src/ai/prompt.ts, code/lib/cli-storybook/src/ai/types.ts, code/lib/cli-storybook/src/ai/setup-requirements.ts, code/lib/cli-storybook/src/bin/run.ts
aiPrepare emits ai-prepare telemetry, snapshots preview, writes ai-setup-pending record (session/config/preview hash/traits), optionally prepends YAML frontmatter (--frontmatter), and threads traits through prompt generation. New setup-requirements module provides preview snapshot/hasPreviewChanged helpers and AI-related exports.
Ghost-stories & manager hook
code/core/src/core-server/server-channel/ghost-stories-channel.ts, code/core/src/core-server/server-channel/ghost-stories-channel.test.ts, code/core/src/manager/components/sidebar/useGhostStoriesTrigger.ts, code/core/src/manager/components/sidebar/Sidebar.tsx, code/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx, code/core/src/core-server/presets/common-preset.ts
Server-side ghost-stories gating simplified (removed session-id check; uses lastEvents['ghost-stories']). Manager-side modal trigger removed; new useGhostStoriesTrigger() hook schedules a one-time GHOST_STORIES_REQUEST 10 minutes after PREVIEW_INITIALIZED. Preset wiring passes story-index generator thunk. Tests updated.
Telemetry wiring in server flows
code/core/src/core-server/server-channel/..., code/core/src/core-server/utils/doTelemetry.ts
Non-blocking calls to collectAiPrepareEvidence added where story index is available (e.g., dev flow) to opportunistically collect/emit evidence alongside existing telemetry.
Satellite addons & scripts
code/core/src/common/satellite-addons.ts, scripts/mock-telemetry-receiver.ts, scripts/spike-extract-features.ts
Added @storybook/addon-mcp to satellite addons. Added scripts/mock-telemetry-receiver.ts (HTTP JSONL telemetry receiver) and scripts/spike-extract-features.ts (feature-extraction benchmark).
Tests & test helpers
code/core/src/core-server/ghost-stories-channel.test.ts, code/core/src/core-server/withTelemetry.test.ts, code/core/src/telemetry/detect-agent.test.ts, code/core/src/telemetry/storybook-metadata.test.ts
Tests adjusted: removed reliance on mocked getSessionId; added/updated mocks for collectAiPrepareEvidence and detectAgent; environment-preservation added for detect-agent tests; new ai-prepare evidence tests added.
Docs & specs
docs/superpowers/specs/2026-04-07-telemetry-enhancements-design.md, docs/superpowers/specs/2026-04-08-ws1-agentic-telemetry-plan-engineer.md, docs/superpowers/specs/2026-04-08-ws1-agentic-telemetry-plan-pm.md
New design and planning docs describing agentic telemetry workstream, AI setup evidence flow, ghost-stories redesign, addon sanitization, testing strategy, local telemetry debugging, and rollout considerations.

Sequence Diagram(s)

sequenceDiagram
    participant CLI as CLI (sb ai prepare)
    participant FS as Filesystem (preview file)
    participant Cache as Cache (ai-setup-pending)
    participant Server as Server (withTelemetry / dev)
    participant Telemetry as Telemetry Endpoint

    CLI->>FS: snapshotPreviewFile(configDir) -> compute previewHash
    CLI->>Cache: store ai-setup-pending {sessionId,timestamp,configDir,previewFile,previewHash,traits}
    CLI->>Telemetry: emit "ai-prepare"

    Server->>Cache: getAiSetupPending()
    Server->>FS: snapshotPreviewFile(configDir) -> compute current previewHash
    Server->>Server: compare baseline vs current (hasPreviewChanged)
    Server->>Telemetry: emit "ai-prepare-evidence" {immediate:true, msSinceAiPrepare, previewChanged, traits, aiAuthoredStories?}
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs


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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (4)
scripts/mock-telemetry-receiver.ts (1)

30-35: Add a request-size guard for /event-log bodies.

body is currently unbounded; a large payload can grow memory unexpectedly. A small cap (e.g., 1 MB) makes the debug server much safer.

Suggested hardening patch
 const PORT = Number(process.env.PORT || 6007);
 const LOG_DIR = resolve(process.env.LOG_DIR || '.cache/telemetry-debug');
+const MAX_BODY_BYTES = 1024 * 1024;
 const events: Array<{ receivedAt: string; [key: string]: unknown }> = [];
@@
   if (req.method === 'POST' && req.url === '/event-log') {
     let body = '';
+    let bodySize = 0;
+    let tooLarge = false;
     req.on('data', (chunk: Buffer) => {
+      bodySize += chunk.length;
+      if (bodySize > MAX_BODY_BYTES) {
+        tooLarge = true;
+        res.statusCode = 413;
+        res.end('payload too large');
+        req.destroy();
+        return;
+      }
       body += chunk;
     });
     req.on('end', async () => {
+      if (tooLarge) {
+        return;
+      }
       try {
         const data = JSON.parse(body);

Also applies to: 48-51

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/mock-telemetry-receiver.ts` around lines 30 - 35, The request body
accumulator (variable body) for the /event-log handler is unbounded and needs a
size guard; add a max size constant (e.g. MAX_BODY_BYTES = 1 * 1024 * 1024) and
in the req.on('data', ...) callback check accumulated length, and if it exceeds
the limit immediately stop reading (req.destroy() or req.pause()), send a 413
Payload Too Large response and return; apply the same check to the other
identical data handler instance (the second req.on('data'...) at lines
referenced) so both places enforce the cap and avoid unbounded memory growth.
code/core/src/telemetry/storybook-metadata.test.ts (1)

36-38: Consider using spy: true for consistency with other mocks.

The detectAgent mock doesn't use the spy: true option that other mocks in this file use (e.g., lines 35, 39-47). While the current approach works, using the consistent pattern would align with the project's mocking guidelines.

♻️ Suggested refactor
-vi.mock('./detect-agent.ts', () => ({
-  detectAgent: vi.fn().mockReturnValue(undefined),
-}));
+vi.mock(import('./detect-agent.ts'), { spy: true });

Then set the default behavior in beforeEach:

vi.mocked(detectAgent).mockReturnValue(undefined);

As per coding guidelines: "Use vi.mock() with the spy: true option for all package and file mocks in Vitest tests"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/core/src/telemetry/storybook-metadata.test.ts` around lines 36 - 38,
Replace the direct vi.mock call for detectAgent with the project's spy pattern:
call vi.mock('./detect-agent.ts', { spy: true, ... }) (keeping the module path)
so the mock uses a spy like the others, then move the default return into the
test setup by calling vi.mocked(detectAgent).mockReturnValue(undefined) inside
beforeEach; target the detectAgent import and the vi.mock/vi.mocked usage when
making this change.
code/lib/cli-storybook/src/ai/index.ts (1)

135-151: Inconsistent YAML quoting in frontmatter.

Some string values are quoted (framework, renderer, builder) while others are not (storybook, language). YAML interpreters handle this, but consistent quoting improves readability and avoids edge cases if values contain special characters.

♻️ Suggested fix for consistent quoting
 function buildFrontmatter(projectInfo: ProjectInfo, traits: AiPrepareTraits): string {
   const lines = [
     '---',
-    `storybook: ${projectInfo.storybookVersion || 'unknown'}`,
+    `storybook: '${projectInfo.storybookVersion || 'unknown'}'`,
     `framework: '${projectInfo.framework || 'unknown'}'`,
     `renderer: '${projectInfo.rendererPackage || 'unknown'}'`,
     `builder: '${projectInfo.builderPackage || 'unknown'}'`,
-    `language: ${projectInfo.language}`,
-    `hasCsfFactoryPreview: ${projectInfo.hasCsfFactoryPreview}`,
+    `language: '${projectInfo.language}'`,
+    `hasCsfFactoryPreview: ${String(projectInfo.hasCsfFactoryPreview)}`,
     'traits:',
   ];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/lib/cli-storybook/src/ai/index.ts` around lines 135 - 151, The
frontmatter built by buildFrontmatter currently mixes quoted and unquoted values
(e.g., framework vs storybook/language); update buildFrontmatter so all
string-valued fields are consistently quoted: wrap projectInfo.storybookVersion,
projectInfo.language and any trait values that are strings in quotes while
leaving non-strings (booleans/numbers) unquoted. Locate buildFrontmatter and
adjust the lines array generation and the traits loop to detect typeof value ===
'string' and add quotes (or use a helper to quote safely) for those entries.
code/core/src/core-server/withTelemetry.ts (1)

174-197: Duplicated preview change detection logic.

checkPreviewChanged duplicates logic from setup-requirements.ts:hasPreviewChanged but uses findConfigFile directly instead of calling snapshotPreviewFile. The comment explains this is to avoid cross-package imports, which is reasonable.

Consider whether future changes to preview detection logic might need coordinated updates in both locations. The current duplication is acceptable given the avoidance of circular dependencies.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/core/src/core-server/withTelemetry.ts` around lines 174 - 197,
checkPreviewChanged duplicates preview-detection logic found in
setup-requirements.ts (hasPreviewChanged) but uses findConfigFile directly
instead of snapshotPreviewFile; either refactor checkPreviewChanged to delegate
to the shared snapshotPreviewFile/hasPreviewChanged utility to avoid drift, or
add a clear TODO/comment above checkPreviewChanged noting the duplication and
listing the canonical function names (hasPreviewChanged and snapshotPreviewFile)
so future changes are synchronized; update the function/inline comment
accordingly to reference these symbols.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@code/core/src/core-server/withTelemetry.test.ts`:
- Around line 12-14: Replace the inline-factory mock with a spy-style mock and
move behavior into beforeEach: call vi.mock('../telemetry/detect-agent.ts', {
spy: true }) (leaving detectAgent exported from that module uninitialized here)
and then in the test suite's beforeEach set the behavior using the mocked/spy
reference to detectAgent (e.g.,
vi.mocked(detectAgent).mockReturnValue(undefined) or mockImplementation) so all
behavior is defined in beforeEach rather than in the vi.mock factory; reference
the detectAgent export used in withTelemetry.test.ts and update beforeEach
accordingly.

In `@code/core/src/telemetry/event-cache.ts`:
- Around line 85-93: The AiSetupPendingRecord interface's traits field is
inconsistent with setup-requirements.ts (here: traits: Record<string,string] vs
setup-requirements.ts using AiPrepareTraits), so either import and use
AiPrepareTraits from types.ts in event-cache.ts to make the interface match
exactly (update the AiSetupPendingRecord definition accordingly) or, if the
looser shape is intentional for cache reads, update the comment above
AiSetupPendingRecord to explicitly state it intentionally uses a relaxed type
and why; reference AiSetupPendingRecord, AiPrepareTraits, and
setup-requirements.ts in your change so reviewers can verify the chosen
approach.

In `@docs/superpowers/specs/2026-04-07-telemetry-enhancements-design.md`:
- Line 7: The anchor link "[§ Resume Tomorrow](`#resume-tomorrow`)" has a case
mismatch with the heading "## Resume tomorrow"; update either the heading to "##
Resume Tomorrow" or the link target/text to match the heading's casing so the
anchor slug generated for "## Resume tomorrow" and the link "#resume-tomorrow"
are consistent across parsers; locate the link and the heading in the document
and make their text/casing identical.
- Line 566: The table row "| Tests as in §4.2 |" is malformed because it
contains a single pipe-delimited cell and breaks the table; replace it with
either a properly formatted table row with matching columns or convert it to
plain paragraph text (e.g., remove the surrounding pipes) so it is not treated
as a table; locate the literal string "| Tests as in §4.2 |" in the document and
update it accordingly to match the surrounding table column count or move it
outside the table block.

In `@scripts/spike-extract-features.ts`:
- Around line 29-38: The glob walker currently discovers files then filters
them, causing traversal into ignored directories; update findStoryFiles to pass
an ignore option into the glob call so the walker never descends into
IGNORE_SEGMENTS (e.g., set glob(..., { cwd, ignore: IGNORE_SEGMENTS.map(s =>
`${s}/**`) }) or equivalent), keep the existing ext check using
STORY_EXTENSIONS, and remove or keep the post-filtering by parts — the key
change is adding the ignore option on the glob invocation so node_modules, dist,
build, storybook-static, .cache are excluded up-front.
- Around line 100-118: In objectLiteralKeys(), add handling for quoted string
keys in both branches (where you currently check t.isIdentifier for
ObjectProperty and ObjectMethod) by also checking t.isStringLiteral and pushing
(key as { value: string }).value into the keys array; keep the existing
Identifier handling (pushing .name) and ensure the function still returns the
keys array at the end. Use the existing t.isStringLiteral() pattern consistent
with the codebase and update the branches in objectLiteralKeys to cover both
Identifier and StringLiteral key types.

---

Nitpick comments:
In `@code/core/src/core-server/withTelemetry.ts`:
- Around line 174-197: checkPreviewChanged duplicates preview-detection logic
found in setup-requirements.ts (hasPreviewChanged) but uses findConfigFile
directly instead of snapshotPreviewFile; either refactor checkPreviewChanged to
delegate to the shared snapshotPreviewFile/hasPreviewChanged utility to avoid
drift, or add a clear TODO/comment above checkPreviewChanged noting the
duplication and listing the canonical function names (hasPreviewChanged and
snapshotPreviewFile) so future changes are synchronized; update the
function/inline comment accordingly to reference these symbols.

In `@code/core/src/telemetry/storybook-metadata.test.ts`:
- Around line 36-38: Replace the direct vi.mock call for detectAgent with the
project's spy pattern: call vi.mock('./detect-agent.ts', { spy: true, ... })
(keeping the module path) so the mock uses a spy like the others, then move the
default return into the test setup by calling
vi.mocked(detectAgent).mockReturnValue(undefined) inside beforeEach; target the
detectAgent import and the vi.mock/vi.mocked usage when making this change.

In `@code/lib/cli-storybook/src/ai/index.ts`:
- Around line 135-151: The frontmatter built by buildFrontmatter currently mixes
quoted and unquoted values (e.g., framework vs storybook/language); update
buildFrontmatter so all string-valued fields are consistently quoted: wrap
projectInfo.storybookVersion, projectInfo.language and any trait values that are
strings in quotes while leaving non-strings (booleans/numbers) unquoted. Locate
buildFrontmatter and adjust the lines array generation and the traits loop to
detect typeof value === 'string' and add quotes (or use a helper to quote
safely) for those entries.

In `@scripts/mock-telemetry-receiver.ts`:
- Around line 30-35: The request body accumulator (variable body) for the
/event-log handler is unbounded and needs a size guard; add a max size constant
(e.g. MAX_BODY_BYTES = 1 * 1024 * 1024) and in the req.on('data', ...) callback
check accumulated length, and if it exceeds the limit immediately stop reading
(req.destroy() or req.pause()), send a 413 Payload Too Large response and
return; apply the same check to the other identical data handler instance (the
second req.on('data'...) at lines referenced) so both places enforce the cap and
avoid unbounded memory growth.
🪄 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: c39a8f4f-6042-44ee-8834-bcc55dc310b9

📥 Commits

Reviewing files that changed from the base of the PR and between ae591fc and cc92a8c.

📒 Files selected for processing (24)
  • code/core/src/common/satellite-addons.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.test.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.ts
  • code/core/src/core-server/withTelemetry.test.ts
  • code/core/src/core-server/withTelemetry.ts
  • code/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx
  • code/core/src/manager/components/sidebar/Sidebar.tsx
  • code/core/src/manager/components/sidebar/useGhostStoriesTrigger.ts
  • code/core/src/telemetry/detect-agent.test.ts
  • code/core/src/telemetry/event-cache.ts
  • code/core/src/telemetry/index.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
  • code/core/src/telemetry/storybook-metadata.ts
  • code/core/src/telemetry/types.ts
  • code/lib/cli-storybook/src/ai/index.ts
  • code/lib/cli-storybook/src/ai/prompt.ts
  • code/lib/cli-storybook/src/ai/setup-requirements.ts
  • code/lib/cli-storybook/src/ai/types.ts
  • code/lib/cli-storybook/src/bin/run.ts
  • docs/superpowers/specs/2026-04-07-telemetry-enhancements-design.md
  • docs/superpowers/specs/2026-04-08-ws1-agentic-telemetry-plan-engineer.md
  • docs/superpowers/specs/2026-04-08-ws1-agentic-telemetry-plan-pm.md
  • scripts/mock-telemetry-receiver.ts
  • scripts/spike-extract-features.ts
💤 Files with no reviewable changes (1)
  • code/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx

Comment thread code/core/src/core-server/withTelemetry.test.ts Outdated
Comment thread code/core/src/telemetry/event-cache.ts Outdated
Comment thread docs/superpowers/specs/2026-04-07-telemetry-enhancements-design.md Outdated
Comment thread docs/superpowers/specs/2026-04-07-telemetry-enhancements-design.md Outdated
Comment thread scripts/spike-extract-features.ts Outdated
Comment thread scripts/spike-extract-features.ts Outdated
Comment thread code/core/src/core-server/withTelemetry.ts Outdated
Comment thread code/core/src/core-server/withTelemetry.ts Outdated
Comment thread code/core/src/core-server/withTelemetry.ts Outdated
Comment thread code/core/src/core-server/withTelemetry.ts Outdated
Comment thread code/core/src/core-server/withTelemetry.ts Outdated
Comment thread code/core/src/core-server/withTelemetry.ts Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@code/core/src/core-server/withTelemetry.ts`:
- Around line 215-225: The pending ai-setup record returned by
getAiSetupPending() is only checked for age, so add validation that the record
belongs to the current run: after fetching pending and before computing
msSinceAiPrepare, verify pending.sessionId and pending.configDir match the
current run's session identifiers (e.g., the local sessionId and configDir
values available in this module) and return early if they differ; keep the
existing timestamp/SESSION_TIMEOUT check (use pending.timestamp as before).
Ensure you reference getAiSetupPending(), pending.timestamp, SESSION_TIMEOUT,
pending.sessionId and pending.configDir when making the comparison.
- Around line 241-244: The telemetry check for doctorRanSinceSetup only reads
lastEvents.doctor but ignores the current in-flight boot event; change the logic
that computes doctorBoot/doctorRanSinceSetup to treat the current pending boot
as evidence by comparing lastEvents.doctor with the current pending event (use
pending.timestamp and pending.type or whatever flag denotes the current "doctor"
boot) and take the later timestamp—e.g., set doctorBoot = the more recent of
lastEvents.doctor and pending (if pending indicates a doctor boot) and then
compute doctorRanSinceSetup = Boolean(doctorBoot && doctorBoot.timestamp >
pending.timestamp) so the just-fired doctor boot counts as evidence.
🪄 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: 42185871-24fe-4681-8d20-b0e8b17f0191

📥 Commits

Reviewing files that changed from the base of the PR and between cc92a8c and a6f4f1f.

📒 Files selected for processing (1)
  • code/core/src/core-server/withTelemetry.ts

Comment thread code/core/src/core-server/withTelemetry.ts Outdated
Comment thread code/core/src/core-server/withTelemetry.ts Outdated
@storybook-app-bot
Copy link
Copy Markdown

storybook-app-bot Bot commented Apr 10, 2026

Package Benchmarks

Commit: f51a483, ran on 14 April 2026 at 13:55:04 UTC

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

storybook

Before After Difference
Dependency count 50 50 0
Self size 20.53 MB 20.54 MB 🚨 +14 KB 🚨
Dependency size 16.56 MB 16.56 MB 0 B
Bundle Size Analyzer Link Link

@storybook/cli

Before After Difference
Dependency count 184 184 0
Self size 818 KB 819 KB 🚨 +1 KB 🚨
Dependency size 68.18 MB 68.19 MB 🚨 +14 KB 🚨
Bundle Size Analyzer Link Link

@storybook/codemod

Before After Difference
Dependency count 177 177 0
Self size 32 KB 32 KB 0 B
Dependency size 66.69 MB 66.71 MB 🚨 +14 KB 🚨
Bundle Size Analyzer Link Link

create-storybook

Before After Difference
Dependency count 51 51 0
Self size 1.05 MB 1.05 MB 0 B
Dependency size 37.09 MB 37.10 MB 🚨 +14 KB 🚨
Bundle Size Analyzer node node

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
code/core/src/core-server/server-channel/ghost-stories-channel.ts (1)

61-70: ⚠️ Potential issue | 🟠 Major

Scope the one-shot ghost-stories guard to the current run.

getLastEvents() reads a global lastEvents cache keyed only by event type, so checking only for the existence of lastEvents['ghost-stories'] makes this a cross-run/global one-shot. After the first recorded ghost-stories event, later Storybook instances can skip immediately even though they never ran it. Compare against the current init/session instead of treating any cached event as a match.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/core/src/core-server/server-channel/ghost-stories-channel.ts` around
lines 61 - 70, The current guard treats any prior 'ghost-stories' entry in the
global lastEvents cache as a permanent one-shot; change it to scope to the
current init/session by comparing the stored ghost-stories event against the
current init value. Specifically, inside the block that calls getLastEvents()
use lastEvents?.init (lastInit) as the current run identifier and replace the
unconditional truthy check of lastEvents['ghost-stories'] with a comparison that
ensures lastEvents['ghost-stories'] corresponds to lastInit (e.g., only skip
when lastEvents['ghost-stories'] === lastInit or has the same run/session id),
leaving other behavior (return when !lastEvents || !lastInit) unchanged.
♻️ Duplicate comments (1)
code/core/src/telemetry/ai-prepare-evidence.ts (1)

110-143: ⚠️ Potential issue | 🟠 Major

Don't let an undefined configDir reuse a stale pending record.

If callers pass undefined here, Gate 4 is skipped and we still hash pending.configDir + emit ai-prepare-evidence for whatever repo last wrote ai-setup-pending. That can attach stale evidence to the wrong project. Bail out unless the current run can prove it is in the same config dir, and send telemetry with the matched dir.

Suggested fix
-    if (configDir && pending.configDir !== configDir) {
+    if (!configDir || pending.configDir !== configDir) {
       return;
     }
@@
       {
         immediate: true,
-        configDir,
+        configDir: pending.configDir,
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/core/src/telemetry/ai-prepare-evidence.ts` around lines 110 - 143, The
current Gate 4 allows a missing configDir to skip the cross-project guard and
reuse a stale pending record; change the guard to bail unless there is a current
configDir that matches the pending record (replace if (configDir &&
pending.configDir !== configDir) return; with a check like if (!configDir ||
pending.configDir !== configDir) return;), use the current configDir (not
pending.configDir) when calling checkPreviewChanged, and include the matched
config dir in the telemetry payload (e.g. add matchedConfigDir: configDir) when
emitting 'ai-prepare-evidence' so evidence is tied to the verified project.
🧹 Nitpick comments (1)
code/core/src/core-server/server-channel/ghost-stories-channel.ts (1)

22-31: Don't treat every test-provider failure as “idle.”

This catch turns any fullTestProviderStore.getFullState() failure into true, so a broken store looks the same as “no tests are running” and we can launch another Vitest run on top of active work. Keep the uninitialized-store fallback if needed, but fail closed for unexpected exceptions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/core/src/core-server/server-channel/ghost-stories-channel.ts` around
lines 22 - 31, The catch currently treats any exception from
fullTestProviderStore.getFullState() as "idle", which hides real failures;
update the error handling in the block that calls
fullTestProviderStore.getFullState() and computes isRunning so only the known
"store not initialized" condition is treated as idle (return true); for any
other unexpected exception either rethrow or return false (fail closed) and log
the error. Specifically, modify the try/catch around
fullTestProviderStore.getFullState() / isRunning so the catch inspects the
thrown error (e.g., by error type or message) and only returns true for the
explicit uninitialized-store case, otherwise propagate or handle as a real
failure.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@code/core/src/core-server/withTelemetry.ts`:
- Around line 189-193: Currently collectAiPrepareEvidence is invoked before the
command's run(), causing short-lived mutating commands to record pre-command
state; move the collectAiPrepareEvidence(options.cliOptions.configDir ||
options.presetOptions?.configDir) call to execute after command.run() for
non-dev and non-build commands (i.e., when the command is short-lived), leaving
the existing dev/build telemetry flow (doTelemetry) unchanged; update the
conditional around enableTelemetry to call collectAiPrepareEvidence post-run
(but skip for dev/build/long-running paths) so evidence reflects post-command
filesystem changes.

---

Outside diff comments:
In `@code/core/src/core-server/server-channel/ghost-stories-channel.ts`:
- Around line 61-70: The current guard treats any prior 'ghost-stories' entry in
the global lastEvents cache as a permanent one-shot; change it to scope to the
current init/session by comparing the stored ghost-stories event against the
current init value. Specifically, inside the block that calls getLastEvents()
use lastEvents?.init (lastInit) as the current run identifier and replace the
unconditional truthy check of lastEvents['ghost-stories'] with a comparison that
ensures lastEvents['ghost-stories'] corresponds to lastInit (e.g., only skip
when lastEvents['ghost-stories'] === lastInit or has the same run/session id),
leaving other behavior (return when !lastEvents || !lastInit) unchanged.

---

Duplicate comments:
In `@code/core/src/telemetry/ai-prepare-evidence.ts`:
- Around line 110-143: The current Gate 4 allows a missing configDir to skip the
cross-project guard and reuse a stale pending record; change the guard to bail
unless there is a current configDir that matches the pending record (replace if
(configDir && pending.configDir !== configDir) return; with a check like if
(!configDir || pending.configDir !== configDir) return;), use the current
configDir (not pending.configDir) when calling checkPreviewChanged, and include
the matched config dir in the telemetry payload (e.g. add matchedConfigDir:
configDir) when emitting 'ai-prepare-evidence' so evidence is tied to the
verified project.

---

Nitpick comments:
In `@code/core/src/core-server/server-channel/ghost-stories-channel.ts`:
- Around line 22-31: The catch currently treats any exception from
fullTestProviderStore.getFullState() as "idle", which hides real failures;
update the error handling in the block that calls
fullTestProviderStore.getFullState() and computes isRunning so only the known
"store not initialized" condition is treated as idle (return true); for any
other unexpected exception either rethrow or return false (fail closed) and log
the error. Specifically, modify the try/catch around
fullTestProviderStore.getFullState() / isRunning so the catch inspects the
thrown error (e.g., by error type or message) and only returns true for the
explicit uninitialized-store case, otherwise propagate or handle as a real
failure.
🪄 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: c1fa84a1-50e4-4232-a2ae-d3309d462eec

📥 Commits

Reviewing files that changed from the base of the PR and between b571cf5 and 82f7bcd.

📒 Files selected for processing (12)
  • code/core/src/core-server/presets/common-preset.ts
  • code/core/src/core-server/server-channel/ghost-stories-channel.ts
  • code/core/src/core-server/utils/doTelemetry.ts
  • code/core/src/core-server/withTelemetry.test.ts
  • code/core/src/core-server/withTelemetry.ts
  • code/core/src/telemetry/ai-prepare-evidence.test.ts
  • code/core/src/telemetry/ai-prepare-evidence.ts
  • code/core/src/telemetry/event-cache.ts
  • code/core/src/telemetry/index.ts
  • code/core/src/telemetry/storybook-metadata.test.ts
  • code/core/src/telemetry/types.ts
  • code/lib/cli-storybook/src/ai/setup-requirements.ts
✅ Files skipped from review due to trivial changes (3)
  • code/core/src/core-server/withTelemetry.test.ts
  • code/core/src/telemetry/ai-prepare-evidence.test.ts
  • code/core/src/telemetry/event-cache.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • code/core/src/telemetry/index.ts
  • code/core/src/telemetry/types.ts
  • code/core/src/telemetry/storybook-metadata.test.ts

Comment thread code/core/src/core-server/withTelemetry.ts
'@storybook/addon-coverage',
'@storybook/addon-webpack5-compiler-babel',
'@storybook/addon-webpack5-compiler-swc',
'@storybook/addon-mcp',
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 was caught up during my review of the existing telemetry, we're not putting this addon in our own satellites bucket.

Copy link
Copy Markdown
Member Author

@Sidnioulz Sidnioulz left a comment

Choose a reason for hiding this comment

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

Leftovers

Comment thread code/core/src/telemetry/ai-prepare-utils.ts Outdated
Comment thread code/core/src/telemetry/ai-prepare-utils.ts
Comment thread code/core/src/telemetry/detect-agent.test.ts
Comment thread scripts/mock-telemetry-receiver.ts Outdated
Copy link
Copy Markdown
Member

@yannbf yannbf left a comment

Choose a reason for hiding this comment

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

My tests were pretty promising, and from a quick glance what I'd comment on already has comments and you are already planning on fixing them. I will take a deeper pass but so far LGTM

Comment thread code/lib/cli-storybook/src/bin/run.ts Outdated
Comment thread code/lib/cli-storybook/src/ai/types.ts Outdated
@Sidnioulz Sidnioulz merged commit 920b29d into project/sb-agentic-setup Apr 14, 2026
124 checks passed
@Sidnioulz Sidnioulz deleted the sidnioulz/agentic-telemetry-ws1 branch April 14, 2026 14:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build Internal-facing build tooling & test updates ci:normal

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants