Skip to content

Skills M4 (1/9): shared toolset contract, with changed-stories migrated end to end - #35727

Closed
valentinpalkovic wants to merge 1 commit into
nextfrom
valentin/m4-01-tracer-changed-stories
Closed

valentinpalkovic wants to merge 1 commit into
nextfrom
valentin/m4-01-tracer-changed-stories

Conversation

@valentinpalkovic

Copy link
Copy Markdown
Contributor

Closes #

Part 1 of 9 of the Skills M4 migration. Targets next, replaces #35677.

What I did

Storybook exposes agent tools through two different MCP servers today: the one the dev server serves via the MCP addon, and the hosted @storybook/mcp package. Each of them carries its own hand-written implementation of those tools, which is why the same tool can drift in two places. This stack replaces both with one shared set of toolsets owned by Storybook's core, and this first PR lands the contract those toolsets are written against, together with a single tool migrated all the way through, so the whole path is reviewable on something real rather than on an abstraction.

Two things about the contract are worth understanding before reading the rest of the stack. A tool handler now produces its structured data, its human-readable text and its telemetry in a single run, instead of being invoked once per output format with telemetry reported somewhere else entirely. And failure is deliberately split in two: a method that cannot do its job at all throws, while a method that did its job and simply has bad news returns a failure outcome that the agent is meant to read.

The migrated tool is the changed-stories tool, which reports which stories a working-tree diff affects. It is now served from core and the hand-written copy is deleted. The other three toolsets are converted in the same commit, but mechanically: removing the per-call output-format flag is source-breaking for every toolset definition at once, so they all have to move together. That mechanical conversion is the bulk of the diff, and a compatibility shim would only have to be built and then torn down again.

One unrelated fix rides along, because the stack is red in CI without it: two stale package proxy entries in the local test registry break the Linux build on every branch since those packages were first published, and they are removed here.

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

Caution

This section is mandatory for all contributions. If you believe no manual test is necessary, please state so explicitly. Thanks!

  1. Build the monorepo packages with yarn nx run-many -t compile.
  2. In test-storybooks/mcp, run yarn install and then yarn storybook. The MCP endpoint comes up at http://localhost:6006/mcp.
  3. Point an MCP client at that endpoint (or POST a tools/list JSON-RPC request to it) and confirm the tool list still contains get-changed-stories with an unchanged name, title, description and input schema.
  4. Change any story file in that Storybook, then call get-changed-stories. The result should read exactly as it did before this PR, including the coverage-gap banner and the New/Modified/Related grouping.
  5. Run the same call in a directory where git cannot answer (for example with the repository's git metadata temporarily unavailable) and confirm the tool reports the failure to you instead of claiming that nothing changed.

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

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

  • Declare whether manual QA will be needed for this PR during the next release, through qa:needed or qa:skip

  • 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 PR does not have a canary release associated. You can request a canary release of this pull request by mentioning the @storybookjs/core team here.

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

Toolset methods now return a single tagged outcome carrying both the structured
data and the rendered Markdown, instead of branching on a `format` flag and
returning one or the other. Every toolset also declares the telemetry group it
reports under, so the grouping cannot drift between surfaces.

A new adapter in addon-mcp turns a toolset method into an MCP tool: name, title,
description, schemas, behaviour and telemetry all come from the method, while
the addon contributes only the MCP grouping and the availability gate. The
shipped get-changed-stories tool is the first to run on it and its hand-written
implementation is deleted. If a row's backing toolset is ever missing, that one
tool is dropped with an error log instead of taking the whole server down.

Also drops the @storybook/mcp and @storybook/addon-mcp proxy entries from the
Verdaccio config, which have been failing the Linux build since those packages
were first published.
@valentinpalkovic
valentinpalkovic requested a review from a team August 3, 2026 21:51
@valentinpalkovic valentinpalkovic added maintenance User-facing maintenance tasks ci:normal Run our default set of CI jobs (choose this for most PRs). labels Aug 3, 2026
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor
Fails
🚫

PR is not labeled with one of: ["qa:needed","qa:skip","qa:success"]

🚫 PR title must be in the format of "Area: Summary", With both Area and Summary starting with a capital letter Good examples: - "Docs: Describe Canvas Doc Block" - "Svelte: Support Svelte v4" Bad examples: - "add new api docs" - "fix: Svelte 4 support" - "Vue: improve docs"
🚫 This PR needs an approving review from a Storybook Core or Developer Experience team member before it can be merged.

Generated by 🚫 dangerJS against 1e46be4

@storybook-app-bot

storybook-app-bot Bot commented Aug 3, 2026 •

Copy link
Copy Markdown
Contributor

Package Benchmarks

Commit: 1e46be4, ran on 4 August 2026 at 11:04:23 UTC

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

storybook

Before After Difference
Dependency count 73 73 0
Self size 21.42 MB 21.52 MB 🚨 +95 KB 🚨
Dependency size 31.21 MB 31.21 MB 0 B
Bundle Size Analyzer Link Link

@storybook/cli

Before After Difference
Dependency count 205 205 0
Self size 829 KB 829 KB 0 B
Dependency size 86.10 MB 86.20 MB 🚨 +95 KB 🚨
Bundle Size Analyzer Link Link

@storybook/codemod

Before After Difference
Dependency count 198 198 0
Self size 32 KB 32 KB 🚨 +36 B 🚨
Dependency size 84.58 MB 84.68 MB 🚨 +95 KB 🚨
Bundle Size Analyzer Link Link

create-storybook

Before After Difference
Dependency count 74 74 0
Self size 1.09 MB 1.09 MB 🎉 -66 B 🎉
Dependency size 52.63 MB 52.73 MB 🚨 +95 KB 🚨
Bundle Size Analyzer node node

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The PR migrates MCP tools to shared Open Service toolsets. It adds typed outcomes, registry APIs, core stories registration, MCP adapters, UI-root resolution, review gating, resilient missing-toolset handling, and updated unit and end-to-end tests.

Changes

Shared toolset contracts and registry

Layer / File(s) Summary
Toolset contracts and registry
code/core/src/shared/open-service/*, code/core/src/server-errors.ts, code/core/src/storybook-error.ts
Toolsets now use typed { ok, data, markdown } outcomes, telemetry groups, output schemas, dynamic descriptions, canonical names, and explicit registry errors.
Core toolset outcomes
code/core/src/shared/open-service/toolsets/*
Docs, review, stories, and test toolsets return structured outcomes. Stories handling includes unreachable-file detection, status enrichment, telemetry, and review guidance.
Core registration and review gating
code/core/src/core-server/*, code/core/src/shared/review/*
The services preset registers the stories toolset with Storybook services, Git, change status, story index, and explicit review gating.

MCP integration

Layer / File(s) Summary
MCP toolset adapter
code/addons/mcp/src/tools/*, code/addons/mcp/scripts/generate-tools-api-doc.ts
MCP tools resolve shared toolsets, validate outputs, forward telemetry, handle agent-facing errors, derive UI roots, and use registered toolsets for metadata and CLI documentation. The legacy changed-stories implementation is removed.
Registration and integration validation
code/addons/mcp/src/*test.ts, code/addons/mcp/src/test-support/*, test-storybooks/mcp/tests/*
Tests register core toolsets, verify adapter and missing-toolset behavior, and cover MCP requests when Git is unusable.

Possibly related issues

Possibly related PRs

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

@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 (5)
code/core/src/server-errors.ts (1)

381-397: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider identifying the failing toolset/method in the mismatch error.

OpenServiceToolsetOutputMismatchError stores only issues. When this error surfaces in logs, nothing on the error identifies which toolset or method produced the invalid output, so diagnosing the bug requires cross-referencing the issues payload against every method with an outputSchema. Add a toolsetId and/or methodId field so the error is self-describing.

♻️ Proposed addition of identifying context
 export class OpenServiceToolsetOutputMismatchError extends StorybookError {
-  constructor(public data: { issues: readonly unknown[] }) {
+  constructor(public data: { toolsetId: string; methodId: string; issues: readonly unknown[] }) {
     super({
       name: 'OpenServiceToolsetOutputMismatchError',
       category: Category.CORE_COMMON,
       code: 26,
-      message: `Toolset output did not match its published output schema: ${JSON.stringify(data.issues)}`,
+      message: `Toolset "${data.toolsetId}" method "${data.methodId}" output did not match its published output schema: ${JSON.stringify(data.issues)}`,
     });
   }
 }
🤖 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/server-errors.ts` around lines 381 - 397, Update
OpenServiceToolsetOutputMismatchError to accept and store identifying context
for the failing toolset and/or method, such as toolsetId and methodId, and
include that context in the constructed error message so surfaced errors are
self-describing. Preserve the existing issues payload and validation-mismatch
behavior.
test-storybooks/mcp/tests/mcp-git-unusable.e2e.test.ts (1)

3-3: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add the explicit .ts extension to the relative import.

♻️ Proposed change
-import { mcpRequest, waitForMcpEndpoint, killPort, startStorybook, stopStorybook } from './helpers';
+import { mcpRequest, waitForMcpEndpoint, killPort, startStorybook, stopStorybook } from './helpers.ts';

As per coding guidelines: "For relative TypeScript imports and exports targeting repository TS/JS modules, prefer explicit extensions such as ./foo.ts or ./bar.tsx."

🤖 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 `@test-storybooks/mcp/tests/mcp-git-unusable.e2e.test.ts` at line 3, Update the
relative import from `./helpers` in the test file to include the explicit `.ts`
extension, while preserving the existing imported symbols.

Source: Coding guidelines

code/addons/mcp/src/tools/toolset-tools.ts (2)

45-51: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Add a boundary assertion for an unresolved method.

resolveMethod returns toolset.methods[methodName] without checking that the key exists. If ToolsetMethodRef and the registered toolset's methods map ever drift (a typo, a renamed method, a partially-registered stub toolset in tests), this returns undefined typed as a valid ToolsetMethod. The failure then surfaces later as an opaque TypeError inside method.handler(...), instead of a clear error at the resolution boundary.

Add a runtime check next to the existing getToolset boundary check, so a missing method fails as loudly and specifically as a missing toolset.

As per coding guidelines, "Use static TypeScript types and existing lint rules to encode invariants whenever practical; otherwise add a cheap runtime assertion near the boundary."

🛡️ Proposed boundary assertion
 function resolveMethod(
   toolset: AnyToolsetDefinition,
   options: ToolsetToolOptions
 ): ToolsetMethod<any, AnyToolsetOutcome> {
   const [, methodName] = options.method.split('.');
-  return toolset.methods[methodName];
+  const method = toolset.methods[methodName];
+  if (!method) {
+    throw new Error(
+      `Toolset "${toolset.id}" has no method "${methodName}" (requested via "${options.method}").`
+    );
+  }
+  return method;
 }
🤖 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/addons/mcp/src/tools/toolset-tools.ts` around lines 45 - 51, Update
resolveMethod to validate that toolset.methods[methodName] exists before
returning it, using the same runtime assertion style as the existing getToolset
boundary check. Preserve the current method-name extraction and return the
resolved ToolsetMethod when present; otherwise fail immediately with a clear
missing-method error.

Source: Coding guidelines


138-156: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Avoid relying on .entries for zero-input detection.

ToolsetMethod.schema accepts any StandardSchemaV1. Valibot object schemas expose .entries, but piped schemas and other Standard Schema implementations do not. Store explicit input metadata in the method definition, or restrict and enforce object schemas in the core contract.

🤖 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/addons/mcp/src/tools/toolset-tools.ts` around lines 138 - 156, Update
getToolsetToolMetadata and the ToolsetMethod definition to determine zero-input
methods through explicit input metadata rather than inspecting
method.schema.entries. Ensure every method definition supplies that metadata,
including piped and non-Valibot StandardSchemaV1 schemas, and preserve omission
of schema only for methods explicitly marked as having no inputs.
code/addons/mcp/src/tools/toolset-tools.test.ts (1)

1-12: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

vi.mock() calls omit the required spy: true option. Both test files replace modules with vi.mock() factories but none pass { spy: true }, and the coding guidelines require it for every package and file mock in Vitest tests. Note spy: true is documented to preserve the original export behavior while automocking, which conflicts with these tests' intent to fully replace collectTelemetry, getService, and logger — confirm the intended pattern per .cursor/rules/spy-mocking.mdc before applying a mechanical fix.

  • code/addons/mcp/src/tools/toolset-tools.test.ts#L1-L12: add spy: true (or confirm the repo's documented alternative pattern) to the vi.mock('storybook/internal/core-server', ...) and vi.mock('../telemetry.ts', ...) calls.
  • code/addons/mcp/src/tools/tool-registry.test.ts#L14-L20: add spy: true (or confirm the repo's documented alternative pattern) to the vi.mock('../telemetry.ts', ...) and vi.mock('storybook/internal/node-logger', ...) calls.

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

🤖 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/addons/mcp/src/tools/toolset-tools.test.ts` around lines 1 - 12, Update
the vi.mock calls in code/addons/mcp/src/tools/toolset-tools.test.ts:1-12 and
code/addons/mcp/src/tools/tool-registry.test.ts:14-20 to follow the documented
spy-mocking pattern, adding spy: true where appropriate while preserving the
tests’ intended replacement behavior for getService, collectTelemetry, and
logger; if the repository guidance specifies an alternative for full factory
replacements, apply that documented pattern instead.

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/shared/open-service/toolsets/stories/format.ts`:
- Around line 37-46: Update formatPartialCoverageBanner and its caller to
receive the true unreachable-file total separately from the capped file list, so
the banner reports the full count while still previewing only available entries.
Use neutral “changed” wording (or otherwise avoid labeling new files as
modified), preserve the existing +N preview behavior, and update the
corresponding expectation in the definition test.

---

Nitpick comments:
In `@code/addons/mcp/src/tools/toolset-tools.test.ts`:
- Around line 1-12: Update the vi.mock calls in
code/addons/mcp/src/tools/toolset-tools.test.ts:1-12 and
code/addons/mcp/src/tools/tool-registry.test.ts:14-20 to follow the documented
spy-mocking pattern, adding spy: true where appropriate while preserving the
tests’ intended replacement behavior for getService, collectTelemetry, and
logger; if the repository guidance specifies an alternative for full factory
replacements, apply that documented pattern instead.

In `@code/addons/mcp/src/tools/toolset-tools.ts`:
- Around line 45-51: Update resolveMethod to validate that
toolset.methods[methodName] exists before returning it, using the same runtime
assertion style as the existing getToolset boundary check. Preserve the current
method-name extraction and return the resolved ToolsetMethod when present;
otherwise fail immediately with a clear missing-method error.
- Around line 138-156: Update getToolsetToolMetadata and the ToolsetMethod
definition to determine zero-input methods through explicit input metadata
rather than inspecting method.schema.entries. Ensure every method definition
supplies that metadata, including piped and non-Valibot StandardSchemaV1
schemas, and preserve omission of schema only for methods explicitly marked as
having no inputs.

In `@code/core/src/server-errors.ts`:
- Around line 381-397: Update OpenServiceToolsetOutputMismatchError to accept
and store identifying context for the failing toolset and/or method, such as
toolsetId and methodId, and include that context in the constructed error
message so surfaced errors are self-describing. Preserve the existing issues
payload and validation-mismatch behavior.

In `@test-storybooks/mcp/tests/mcp-git-unusable.e2e.test.ts`:
- Line 3: Update the relative import from `./helpers` in the test file to
include the explicit `.ts` extension, while preserving the existing imported
symbols.
🪄 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: e9842f99-8ca3-4d60-92d6-d7143afcb4ec

📥 Commits

Reviewing files that changed from the base of the PR and between bb5ab56 and 1e46be4.

📒 Files selected for processing (41)
  • code/addons/mcp/scripts/generate-tools-api-doc.ts
  • code/addons/mcp/src/mcp-handler.test.ts
  • code/addons/mcp/src/preset.test.ts
  • code/addons/mcp/src/storybook-ai-metadata.test.ts
  • code/addons/mcp/src/test-support/register-core-toolsets.ts
  • code/addons/mcp/src/tools/get-changed-stories.test.ts
  • code/addons/mcp/src/tools/get-changed-stories.ts
  • code/addons/mcp/src/tools/tool-names.ts
  • code/addons/mcp/src/tools/tool-registry.test.ts
  • code/addons/mcp/src/tools/tool-registry.ts
  • code/addons/mcp/src/tools/toolset-tools.test.ts
  • code/addons/mcp/src/tools/toolset-tools.ts
  • code/addons/mcp/src/tools/ui-root.ts
  • code/addons/mcp/src/utils/detect-unreachable-changes.test.ts
  • code/addons/mcp/src/utils/detect-unreachable-changes.ts
  • code/core/src/core-server/index.ts
  • code/core/src/core-server/presets/common-preset.ts
  • code/core/src/server-errors.ts
  • code/core/src/shared/open-service/index.ts
  • code/core/src/shared/open-service/toolset-definition.test-d.ts
  • code/core/src/shared/open-service/toolset-definition.ts
  • code/core/src/shared/open-service/toolset-names.ts
  • code/core/src/shared/open-service/toolset-registry.test.ts
  • code/core/src/shared/open-service/toolset-registry.ts
  • code/core/src/shared/open-service/toolset-types.ts
  • code/core/src/shared/open-service/toolsets/docs/definition.test.ts
  • code/core/src/shared/open-service/toolsets/docs/definition.ts
  • code/core/src/shared/open-service/toolsets/review/definition.test.ts
  • code/core/src/shared/open-service/toolsets/review/definition.ts
  • code/core/src/shared/open-service/toolsets/stories/definition.test.ts
  • code/core/src/shared/open-service/toolsets/stories/definition.ts
  • code/core/src/shared/open-service/toolsets/stories/format.ts
  • code/core/src/shared/open-service/toolsets/stories/unreachable-files.ts
  • code/core/src/shared/open-service/toolsets/test/definition.test.ts
  • code/core/src/shared/open-service/toolsets/test/definition.ts
  • code/core/src/shared/review/features.test.ts
  • code/core/src/shared/review/features.ts
  • code/core/src/storybook-error.ts
  • scripts/verdaccio.yaml
  • test-storybooks/mcp/tests/helpers.ts
  • test-storybooks/mcp/tests/mcp-git-unusable.e2e.test.ts
💤 Files with no reviewable changes (5)
  • scripts/verdaccio.yaml
  • code/addons/mcp/src/utils/detect-unreachable-changes.ts
  • code/addons/mcp/src/utils/detect-unreachable-changes.test.ts
  • code/addons/mcp/src/tools/get-changed-stories.test.ts
  • code/addons/mcp/src/tools/get-changed-stories.ts

Comment on lines +37 to +46
function formatPartialCoverageBanner(unreachable: string[]): string {
if (unreachable.length === 0) {
return '';
}
const fileList =
unreachable.length <= BANNER_INLINE_LIMIT
? unreachable.join(', ')
: `${unreachable.slice(0, BANNER_INLINE_LIMIT).join(', ')}, +${unreachable.length - BANNER_INLINE_LIMIT} more`;
return `⚠ Coverage gap: ${unreachable.length} modified ${pluralize(unreachable.length, 'file')} unreachable from any story (${fileList}) — full sanity-check note at end of this response.\n\n`;
}

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

The banner count can understate the coverage gap, and the label can be wrong for new files.

detectUnreachableFiles caps its result at DEFAULT_MAX_FILES (10) in unreachable-files.ts, and it includes entries from changedFiles.new. As a result the banner reports at most 10 files as the whole gap, and it calls untracked new files "modified". Pass the true total to the formatter, or use a neutral wording such as "changed" plus a "+N more" total marker.

♻️ Proposed change
-function formatPartialCoverageBanner(unreachable: string[]): string {
+function formatPartialCoverageBanner(unreachable: string[], total = unreachable.length): string {
   if (unreachable.length === 0) {
     return '';
   }
   const fileList =
     unreachable.length <= BANNER_INLINE_LIMIT
       ? unreachable.join(', ')
       : `${unreachable.slice(0, BANNER_INLINE_LIMIT).join(', ')}, +${unreachable.length - BANNER_INLINE_LIMIT} more`;
-  return `⚠ Coverage gap: ${unreachable.length} modified ${pluralize(unreachable.length, 'file')} unreachable from any story (${fileList}) — full sanity-check note at end of this response.\n\n`;
+  return `⚠ Coverage gap: ${total}${total > unreachable.length ? '+' : ''} changed ${pluralize(total, 'file')} unreachable from any story (${fileList}) — full sanity-check note at end of this response.\n\n`;
 }

This change also requires updating the banner expectation in code/core/src/shared/open-service/toolsets/stories/definition.test.ts.

🤖 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/shared/open-service/toolsets/stories/format.ts` around lines 37
- 46, Update formatPartialCoverageBanner and its caller to receive the true
unreachable-file total separately from the capped file list, so the banner
reports the full count while still previewing only available entries. Use
neutral “changed” wording (or otherwise avoid labeling new files as modified),
preserve the existing +N preview behavior, and update the corresponding
expectation in the definition test.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant