Skip to content

fix: ensure implementations resolve correctly in minified builds#12

Merged
brunozoric merged 14 commits into
mainfrom
bruno/test/singleton-multiple-implementations
May 18, 2026
Merged

fix: ensure implementations resolve correctly in minified builds#12
brunozoric merged 14 commits into
mainfrom
bruno/test/singleton-multiple-implementations

Conversation

@brunozoric
Copy link
Copy Markdown
Contributor

@brunozoric brunozoric commented May 18, 2026

Summary

  • Singleton cache key collision bug: When a bundler (rspack/webpack/esbuild) minifies class names, multiple singleton implementations of the same abstraction all resolve to the first one registered. The cache key in Container.resolveRegistration uses class.name, which becomes identical after minification. Documented in bugs/SINGLETON_CACHE_KEY_COLLISION.md with root cause analysis and proposed fix directions.
  • Failing tests that reproduce the bug: A simulated test (classes with identical .name) and a real rspack production-mode bundle test that confirms the collision in a realistic environment.
  • Plugin registry test suite: Tests singleton registry containing multiple singleton plugin implementations — identity, containment, singleton consistency, registration order, and child container sharing.
  • TypeScript config split: tsconfig.json now covers src + __tests__ (IDE and lint), tsconfig.build.json scoped to src only (rslib uses this to keep tests out of dist).
  • Agent onboarding docs: AGENTS.md with architecture, resolution semantics, conventions, and toolchain reference. CLAUDE.md points to it.

Known failing tests (intentional)

4 tests fail — these document the singleton cache key collision bug and are expected to fail until the fix lands:

Test file Failure
simulated.test.ts All implementations resolve to the first when class.name is identical
rspackMinified.test.ts (x3) Same bug reproduced with real rspack minification

Test plan

  • pnpm lint — tsc, oxlint, oxfmt all pass
  • pnpm build — rslib produces dist/index.js + declarations, no test files in dist
  • pnpm test — 54 passing, 4 known failures (singleton cache key collision bug)
  • Verify IDE picks up types for both src/ and __tests__/ from tsconfig.json

🤖 Generated with Claude Code

brunozoric and others added 14 commits May 18, 2026 15:07
Provides codebase architecture, conventions, toolchain, check commands,
and resolution semantics so AI agents can work effectively in this repo.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Verifies singleton registry containing multiple singleton plugin
implementations — identity, containment, singleton consistency across
individual and registry resolution, registration order, and child
container sharing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- tsconfig.json now covers src + __tests__ (IDE + lint)
- tsconfig.build.json scoped to src only (rslib uses this)
- rslib.config.ts points at tsconfig.build.json to keep tests out of dist
- Move registry test into __tests__/registry/ with separate abstractions,
  implementations, and test files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…d class names

When a bundler (rspack/webpack) minifies class names, multiple singleton
implementations of the same abstraction all resolve to the first one
registered. The cache key in Container.resolveRegistration uses
class.name which becomes identical after minification.

Bug documented in __tests__/registry/bugs/SINGLETON_CACHE_KEY_COLLISION.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bundles the plugin registry fixture with rspack in production mode
(minification enabled), executes the bundle, and asserts the output.
Confirms all singleton plugins resolve to the first registered
implementation when class names are mangled.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move bug doc to bugs/ at project root
- Move simulated and rspack minification tests to
  __tests__/singletonCacheKeyCollision/
- Remove bug-related tests from registry test file

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Details the proposed fix using a unique registration ID instead of
class.name for singleton cache keys. Includes before/after resolution
flows, child container behavior, and edge cases.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaces the numeric ID approach with using the Registration object
reference itself as the Map key. No new fields or counters needed —
object identity is guaranteed unique even after bundler minification.
This matches the approach used by inversify and tsyringe.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaces the string-based cache key (abstraction token + class.name)
with the Registration object reference itself as the Map key. Fixes
singleton cache collisions when bundlers minify class names.

Also adds test plan doc for additional hardening tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds coverage analysis (89.88% stmts, 81.7% branches) identifying
untested registerFactory paths and Abstraction.createComposite().
Proposes withFactory.test.ts and withAbstractionCreateComposite.test.ts
to close the gaps.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
tsconfig.json references "node" in types array but @types/node was
only available as a transitive dep locally. CI installs with
--frozen-lockfile and doesn't have it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The rspack minification test imports from @rspack/core which was only
available as a transitive dep from rslib. CI doesn't hoist it
consistently, causing type errors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@brunozoric brunozoric changed the title test: singleton multiple implementations fix: singleton multiple implementations May 18, 2026
@brunozoric brunozoric requested a review from Pavel910 May 18, 2026 18:28
@brunozoric brunozoric self-assigned this May 18, 2026
@brunozoric brunozoric changed the title fix: singleton multiple implementations fix: multiple singleton implementations of the same abstraction now resolve correctly in minified/production builds May 18, 2026
@Pavel910 Pavel910 changed the title fix: multiple singleton implementations of the same abstraction now resolve correctly in minified/production builds fix: ensure implementations resolve correctly in minified/production builds May 18, 2026
@Pavel910 Pavel910 changed the title fix: ensure implementations resolve correctly in minified/production builds fix: ensure implementations resolve correctly in minified builds May 18, 2026
@brunozoric brunozoric merged commit b1cfedb into main May 18, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants