Skip to content

fix: shared virtual module for code-split routes#6659

Merged
schiller-manuel merged 8 commits intomainfrom
auto-code-splitting-shared
Feb 14, 2026
Merged

fix: shared virtual module for code-split routes#6659
schiller-manuel merged 8 commits intomainfrom
auto-code-splitting-shared

Conversation

@schiller-manuel
Copy link
Contributor

@schiller-manuel schiller-manuel commented Feb 14, 2026

When a route file has module-level bindings (variables, functions, classes) referenced by both split and non-split route properties, the bindings are duplicated — initialized independently in the reference file and in each virtual split file. This breaks singletons, causes double side effects, and wastes bundle size.

const collection = { name: 'todos', preload: async () => {} }
export const Route = createFileRoute('/todos')({
  loader: async () => {
    await collection.preload()
  }, // stays in reference
  component: () => <div>{collection.name}</div>, // split to virtual
})

In this example, collection is initialized in both the reference file (because loader references it) and the ?tsr-split=component virtual file (because the component references it). Two separate instances exist at runtime.

To solve this issue, this PR introduces a third virtual module route.tsx?tsr-shared=1 that contains shared bindings. Both the reference and virtual files import from it.

When sharedBindings is empty (the common case — component-only helpers, loader-only code), no shared module exists and the system works exactly as today.

The reference transform runs first and will emit a static import of ?tsr-shared=1 only when needed. Since split chunks are only discovered via the reference file's emitted import('...?tsr-split=...'), the bundler will always process/evaluate the reference module first. Result: the shared module is evaluated once and then reused by any later-loaded split chunk.

Summary by CodeRabbit

  • New Features

    • Support for shared bindings in code-split code-splitting to reduce duplication and coordinate shared module state.
    • Added a new "shared-singleton" route and a navigation link to access it (module-level singleton observable across loads).
  • Tests

    • Added end-to-end test confirming shared module bindings initialize only once.

When a route file has module-level bindings (variables, functions, classes) referenced by **both** split and non-split route properties, the bindings are duplicated — initialized independently in the reference file and in each virtual split file. This breaks singletons, causes double side effects, and wastes bundle size.

```tsx
const collection = { name: 'todos', preload: async () => {} }
export const Route = createFileRoute('/todos')({
  loader: async () => {
    await collection.preload()
  }, // stays in reference
  component: () => <div>{collection.name}</div>, // split to virtual
})
```
In this example, `collection` is initialized in **both** the reference file (because `loader` references it) and the `?tsr-split=component` virtual file (because the component references it). Two separate instances exist at runtime.

To solve this issue, this PR introduces a third virtual module `route.tsx?tsr-shared=1` that contains shared bindings. Both the reference and virtual files import from it.

When `sharedBindings` is empty (the common case — component-only helpers, loader-only code), no shared module exists and the system works exactly as today.

The reference transform runs first and will emit a static import of `?tsr-shared=1` **only when needed**. Since split chunks are only discovered via the reference file's emitted `import('...?tsr-split=...')`, the bundler will always process/evaluate the reference module first. Result: the shared module is evaluated once and then reused by any later-loaded split chunk.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 14, 2026

📝 Walkthrough

Walkthrough

Adds shared-bindings support to the router-plugin code-splitter: static analysis to detect module-level bindings that must be pulled into a shared virtual module, compilation of those shared modules, integration into the existing split/virtual/reference compilation pipeline, E2E test + route for a shared singleton, and extensive snapshot/test updates.

Changes

Cohort / File(s) Summary
E2E route + tests
e2e/react-router/basic-file-based-code-splitting/src/routeTree.gen.ts, e2e/react-router/basic-file-based-code-splitting/src/routes/__root.tsx, e2e/react-router/basic-file-based-code-splitting/src/routes/shared-singleton.tsx, e2e/react-router/basic-file-based-code-splitting/tests/shared-bindings.spec.ts
Adds a new /shared-singleton file-route (route tree entries, link in root UI) and an E2E Playwright test verifying shared-module initialization occurs once across split bundles.
Code-split compiler
packages/router-plugin/src/core/code-splitter/compilers.ts
Massive additions: static analyzers (identifier collection, declaration map, dependency graph), shared-binding computation/expansion (destructuring-aware, transitive), helpers to remove or rewire shared declarations, and new public compile function compileCodeSplitSharedRoute. Existing compile paths updated to accept/propagate sharedBindings.
Router plugin integration
packages/router-plugin/src/core/router-code-splitter-plugin.ts
Introduces sharedBindingsMap, computes shared bindings pre-reference compilation, invokes compileCodeSplitSharedRoute for tsr-shared virtual modules, and threads sharedBindings through reference/virtual compilation steps; adjusts transform filters to exclude tsrSplit and tsrShared.
Constants
packages/router-plugin/src/core/constants.ts
Adds exported constant tsrShared = 'tsr-shared' used to mark shared virtual module imports.
Tests & snapshots
packages/router-plugin/tests/code-splitter.test.ts, packages/router-plugin/tests/code-splitter/snapshots/react/**/*
Exports/uses new compiler APIs (computeSharedBindings, compileCodeSplitSharedRoute) in tests; extensive snapshot updates and new shared/@component/@loader/@shared fixtures demonstrating shared extraction patterns, destructuring, transitive deps, side effects, and other scenarios.
Small route tree adjustments
e2e/react-router/basic-file-based-code-splitting/src/routeTree.gen.ts (existing routes)
Adjusts default fullPath values for existing layout routes (from '' to '/') and inserts the new SharedSingletonRoute into root children and FileRoutes mapping structures.

Sequence Diagram(s)

sequenceDiagram
    participant RP as Router Plugin
    participant CS as Code Splitter (compilers)
    participant Shared as Shared Virtual Module
    participant Ref as Reference Route
    participant Virt as Virtual (split) Route

    RP->>CS: computeSharedBindings(code, codeSplitGroupings)
    CS->>CS: buildDeclarationMap(ast)\nbuildDependencyGraph(...)\ncollectIdentifiersFromNode(...)
    CS-->>RP: Set<sharedBindings>

    RP->>CS: compileCodeSplitSharedRoute(filename, sharedBindings)
    CS->>Shared: emit shared virtual module\n(imports/exports only shared bindings)
    CS-->>RP: GeneratorResult(shared module)

    RP->>CS: compileCodeSplitReferenceRoute(code, sharedBindings)
    CS->>Ref: inject imports from shared virtual module\nregister imported specifiers for DCE
    CS-->>RP: GeneratorResult(reference chunk)

    RP->>CS: compileCodeSplitVirtualRoute(splitTargets, sharedBindings)
    CS->>Virt: import + re-export shared bindings\napply DCE cleanup
    CS-->>RP: GeneratorResult(virtual/split chunk)
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Suggested reviewers

  • SeanCassiere
  • nlynzaad

Poem

🐰
"I nibble through modules, tidy and bright,
Pull shared carrots into one cozy bite.
Chunks hop together, bindings held dear,
One init, one beat — the split bundles cheer! 🥕"

🚥 Pre-merge checks | ✅ 3 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.84% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: shared virtual module for code-split routes' clearly summarizes the main change: introducing a shared virtual module mechanism for code-split routes to prevent duplicate bindings.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch auto-code-splitting-shared

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
packages/router-plugin/src/core/router-code-splitter-plugin.ts (2)

148-170: Consider snapshotting sharedBindings before storing/passing.

This keeps the map stable if any downstream compiler step mutates the set.

♻️ Suggested tweak
-    const sharedBindings = computeSharedBindings({
+    const sharedBindings = computeSharedBindings({
       code,
       codeSplitGroupings: splitGroupings,
     })
-    if (sharedBindings.size > 0) {
-      sharedBindingsMap.set(id, sharedBindings)
+    const sharedBindingsSnapshot = new Set(sharedBindings)
+    if (sharedBindingsSnapshot.size > 0) {
+      sharedBindingsMap.set(id, sharedBindingsSnapshot)
     } else {
       sharedBindingsMap.delete(id)
     }
@@
-      sharedBindings: sharedBindings.size > 0 ? sharedBindings : undefined,
+      sharedBindings:
+        sharedBindingsSnapshot.size > 0 ? sharedBindingsSnapshot : undefined,

211-219: Avoid the non-null assertion on baseId.

Use an explicit guard (or throw) to keep strict type safety and avoid accidental undefined keys.

♻️ Suggested tweak
-    const baseId = id.split('?')[0]!
-    const resolvedSharedBindings = sharedBindingsMap.get(baseId)
+    const baseId = id.split('?')[0]
+    if (!baseId) {
+      throw new Error(
+        `The base id for the virtual route "${id}" was not found.`,
+      )
+    }
+    const resolvedSharedBindings = sharedBindingsMap.get(baseId)
As per coding guidelines: `**/*.{ts,tsx}`: Use TypeScript strict mode with extensive type safety for all code.

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

@nx-cloud
Copy link

nx-cloud bot commented Feb 14, 2026

View your CI Pipeline Execution ↗ for commit a0323f2

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ✅ Succeeded 11m 29s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 29s View ↗

☁️ Nx Cloud last updated this comment at 2026-02-14 11:40:44 UTC

@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 14, 2026

More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@6659

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@6659

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@6659

@tanstack/nitro-v2-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/nitro-v2-vite-plugin@6659

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@6659

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@6659

@tanstack/react-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-ssr-query@6659

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@6659

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@6659

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@6659

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@6659

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@6659

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@6659

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@6659

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@6659

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@6659

@tanstack/router-ssr-query-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-ssr-query-core@6659

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@6659

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@6659

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@6659

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@6659

@tanstack/solid-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-ssr-query@6659

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@6659

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@6659

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@6659

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@6659

@tanstack/start-fn-stubs

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-fn-stubs@6659

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@6659

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@6659

@tanstack/start-static-server-functions

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-static-server-functions@6659

@tanstack/start-storage-context

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-storage-context@6659

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@6659

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@6659

@tanstack/vue-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-router@6659

@tanstack/vue-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-router-devtools@6659

@tanstack/vue-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-router-ssr-query@6659

@tanstack/vue-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start@6659

@tanstack/vue-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start-client@6659

@tanstack/vue-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start-server@6659

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@6659

commit: a0323f2

Copy link
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

🤖 Fix all issues with AI agents
In `@packages/router-plugin/src/core/code-splitter/compilers.ts`:
- Around line 1395-1406: expandTransitively can pull the singleton symbol Route
into keepBindings (initialized from opts.sharedBindings), violating the
invariant that Route must never be extracted; after building depGraph (and
before calling expandTransitively) detect any binding that transitively depends
on the symbol "Route" (e.g., walk depGraph from each candidate in
opts.sharedBindings or compute a reverse-dependency reachability to "Route") and
either remove those bindings from keepBindings or throw a clear error indicating
the offending binding(s). Update references to
expandTransitively/keepBindings/depGraph/buildDependencyGraph/opts.sharedBindings
accordingly so the shared-set expansion will not include any binding that
depends on "Route".
- Around line 1358-1371: The current filter in the AST transformer removes
top-level ExpressionStatements even when they are directive prologues (e.g.,
'use client' / 'use server'); update the filter inside the ast.program.body
reassignment so that any ExpressionStatement with a .directive property (i.e., a
directive prologue) is always preserved before applying the existing
local-binding check; locate the filter that uses
collectLocalBindingsFromStatement and collectIdentifiersFromNode and add an
explicit early-return true for statements where t.isExpressionStatement(stmt) &&
stmt.directive to retain runtime semantics.
🧹 Nitpick comments (2)
packages/router-plugin/tests/code-splitter/test-files/react/shared-function.tsx (1)

3-6: Consider adding type parameters for stricter typing.

The Map lacks type parameters and getCached returns an implicit any. For TypeScript strict mode compliance, explicit types would be preferable.

💡 Suggested improvement
-const cache = new Map()
-function getCached(key: string) {
+const cache = new Map<string, unknown>()
+function getCached(key: string): unknown {
   return cache.get(key)
 }

That said, this is a test fixture focused on demonstrating shared bindings for code-splitting, so the simpler form may be intentional to keep the test focused.

e2e/react-router/basic-file-based-code-splitting/src/routes/shared-singleton.tsx (1)

5-14: Avoid any for the shared singleton global.

Casting globalThis to any weakens strict typing; a typed global keeps the test strict-mode friendly.

♻️ Suggested typing improvement
 import * as React from 'react'

+declare global {
+  var __tsrSharedSingleton: { initCount: number } | undefined
+}
+
 // All shared state lives in declarations — no bare expression statements.
 // The singleton tracks how many times this module scope executes.
 const singleton = (() => {
-  const g = globalThis as any
-  g.__tsrSharedSingleton ??= { initCount: 0 }
-  g.__tsrSharedSingleton.initCount++
-  return { initCountAtCreate: g.__tsrSharedSingleton.initCount as number }
+  globalThis.__tsrSharedSingleton ??= { initCount: 0 }
+  globalThis.__tsrSharedSingleton.initCount++
+  return { initCountAtCreate: globalThis.__tsrSharedSingleton.initCount }
 })()

 function getInitCount() {
-  return (globalThis as any).__tsrSharedSingleton?.initCount as number
+  return globalThis.__tsrSharedSingleton?.initCount ?? 0
 }
As per coding guidelines, "**/*.{ts,tsx}**: Use TypeScript strict mode with extensive type safety for all code".

…dBindings

Skip the expensive babel.traverse for route files that have no local
module-level bindings (aside from Route). Most route files only contain
imports + the Route export, so this early bailout avoids the traversal
in the common case.
Copy link
Member

@SeanCassiere SeanCassiere left a comment

Choose a reason for hiding this comment

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

The tests make sense! which is always a good thing 🙌🏼


This is probably something that should've been done during the implementation of the code-splitting groups, but I think its time we probably have some internal documentation for devs touching the code-splitter.

Mostly since there's a decent bit of complexity whenever the code-splitter gets touched. Plus, changes here often times mean that 50+ snapshots see changes making it easier for unintended things slipping through. A mermaid diagram or something would help I'd think, at-least in the understanding of the conditions and actions of running the code-splitter.

Long term, we likely break apart the tests into a very different structure, but we're probably not there just yet.

@schiller-manuel schiller-manuel merged commit 523972e into main Feb 14, 2026
6 checks passed
@schiller-manuel schiller-manuel deleted the auto-code-splitting-shared branch February 14, 2026 12:10
KyleAMathews added a commit to KyleAMathews/router that referenced this pull request Feb 14, 2026
… shared bindings

Add 76 new tests across three layers for the shared virtual module
code-splitting logic introduced in TanStack#6659:

Layer 1 - Algebraic property tests on helper functions:
- expandTransitively: idempotence, monotonicity, cycle handling
- buildDependencyGraph: subset invariants
- removeBindingsDependingOnRoute: direct/transitive removal
- expandDestructuredDeclarations: idempotence, sibling expansion
- collectLocalBindingsFromStatement: all declaration types

Layer 2 - Invariant tests on computeSharedBindings:
- Route is never in the shared set
- Results are always real local bindings (never imports)
- Destructured siblings cohesion
- Transitive dependency inclusion
- Route-dependent binding exclusion
- Determinism across repeated calls

Layer 3 - Small-scope exhaustive tests:
- Single binding × 3 declaration kinds × 4 property patterns × 2 groupings
- Two bindings × 4 cross-group reference patterns × 2 groupings
- Transitive dependency chains (linear, 3-deep, diamond)
- Meta-invariant conformance across all shared-* fixture files

Testing approach inspired by:
https://gist.github.com/KyleAMathews/64bcea53a57f600cc3b73bc366d9ac4d

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
schiller-manuel pushed a commit that referenced this pull request Feb 14, 2026
…ngs (#6662)

* test: add invariant, property, and exhaustive tests for code-splitter shared bindings

Add 76 new tests across three layers for the shared virtual module
code-splitting logic introduced in #6659:

Layer 1 - Algebraic property tests on helper functions:
- expandTransitively: idempotence, monotonicity, cycle handling
- buildDependencyGraph: subset invariants
- removeBindingsDependingOnRoute: direct/transitive removal
- expandDestructuredDeclarations: idempotence, sibling expansion
- collectLocalBindingsFromStatement: all declaration types

Layer 2 - Invariant tests on computeSharedBindings:
- Route is never in the shared set
- Results are always real local bindings (never imports)
- Destructured siblings cohesion
- Transitive dependency inclusion
- Route-dependent binding exclusion
- Determinism across repeated calls

Layer 3 - Small-scope exhaustive tests:
- Single binding × 3 declaration kinds × 4 property patterns × 2 groupings
- Two bindings × 4 cross-group reference patterns × 2 groupings
- Transitive dependency chains (linear, 3-deep, diamond)
- Meta-invariant conformance across all shared-* fixture files

Testing approach inspired by:
https://gist.github.com/KyleAMathews/64bcea53a57f600cc3b73bc366d9ac4d

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* ci: apply automated fixes

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Sheraff pushed a commit that referenced this pull request Feb 15, 2026
* fix: shared virtual module for code-split routes

When a route file has module-level bindings (variables, functions, classes) referenced by **both** split and non-split route properties, the bindings are duplicated — initialized independently in the reference file and in each virtual split file. This breaks singletons, causes double side effects, and wastes bundle size.

```tsx
const collection = { name: 'todos', preload: async () => {} }
export const Route = createFileRoute('/todos')({
  loader: async () => {
    await collection.preload()
  }, // stays in reference
  component: () => <div>{collection.name}</div>, // split to virtual
})
```
In this example, `collection` is initialized in **both** the reference file (because `loader` references it) and the `?tsr-split=component` virtual file (because the component references it). Two separate instances exist at runtime.

To solve this issue, this PR introduces a third virtual module `route.tsx?tsr-shared=1` that contains shared bindings. Both the reference and virtual files import from it.

When `sharedBindings` is empty (the common case — component-only helpers, loader-only code), no shared module exists and the system works exactly as today.

The reference transform runs first and will emit a static import of `?tsr-shared=1` **only when needed**. Since split chunks are only discovered via the reference file's emitted `import('...?tsr-split=...')`, the bundler will always process/evaluate the reference module first. Result: the shared module is evaluated once and then reused by any later-loaded split chunk.
Sheraff pushed a commit that referenced this pull request Feb 15, 2026
…ngs (#6662)

* test: add invariant, property, and exhaustive tests for code-splitter shared bindings

Add 76 new tests across three layers for the shared virtual module
code-splitting logic introduced in #6659:

Layer 1 - Algebraic property tests on helper functions:
- expandTransitively: idempotence, monotonicity, cycle handling
- buildDependencyGraph: subset invariants
- removeBindingsDependingOnRoute: direct/transitive removal
- expandDestructuredDeclarations: idempotence, sibling expansion
- collectLocalBindingsFromStatement: all declaration types

Layer 2 - Invariant tests on computeSharedBindings:
- Route is never in the shared set
- Results are always real local bindings (never imports)
- Destructured siblings cohesion
- Transitive dependency inclusion
- Route-dependent binding exclusion
- Determinism across repeated calls

Layer 3 - Small-scope exhaustive tests:
- Single binding × 3 declaration kinds × 4 property patterns × 2 groupings
- Two bindings × 4 cross-group reference patterns × 2 groupings
- Transitive dependency chains (linear, 3-deep, diamond)
- Meta-invariant conformance across all shared-* fixture files

Testing approach inspired by:
https://gist.github.com/KyleAMathews/64bcea53a57f600cc3b73bc366d9ac4d

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* ci: apply automated fixes

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants