Skip to content

Dedupe install across bundled copies; pin the ordering invariant - #8

Open
myabc wants to merge 1 commit into
mainfrom
fix/install-guard
Open

Dedupe install across bundled copies; pin the ordering invariant#8
myabc wants to merge 1 commit into
mainfrom
fix/install-guard

Conversation

@myabc

@myabc myabc commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Ticket

N/A — internal architecture review of this library (candidate 5).

What are you trying to accomplish?

Give installElements() its invariant. The README's hard requirement — install before register()/Application.start() — was unenforced, untested, and fails silently (accessors just undefined). Separately, the double-install guard only worked within one module instance: installed flag and blessings.includes identity check both fail when the package is bundled twice, so each copy pushed its own blessing — a caveat living only in a comment.

What approach did you choose and why?

  • Cross-bundle dedupe (the code change): tag the blessing with Symbol.for("@openproject/stimulus-elements.blessing") and dedupe on the tag. The global symbol registry is shared across module copies, so any copy recognises a blessing installed by another. The comment-caveat becomes behavior.
  • Ordering invariant pinned by test, not warning: investigated the review's "warn on late install" — not implementable. Stimulus snapshots blessings at registration onto a shadow constructor and leaves no observable trace on the user's class or globally; detecting pre-install registrations would require watching Controller.blessings reads from module-eval time, i.e. an import-time side effect, which sideEffects: false forbids. Instead test/install-order.test.ts characterizes the silent failure end-to-end (early controller lacks accessors, install doesn't retro-bless, late controller works) — it regression-guards the failure mode and catches any Stimulus behavior change. README now states the failure is silent.
  • Both new tests live in their own files: vitest browser mode isolates per file, giving each a virgin install-module state that integration.test.ts's beforeEach(installElements) would otherwise destroy.

Patch changeset included. CONTEXT.md decision entry deferred — the file arrives with #1; this PR is independent of that chain.

Stacked on #6 (vitest browser mode) only; independent of the #1#2#4 chain.

Verification: bun run test 35 pass in Chromium, bun run build clean.

Merge checklist

  • Added/updated tests
  • Lookbook docs n/a — npm library; README updated
  • Tested major browsers — suite runs in real Chromium in CI

installElements guarded against double-install only within one module
instance: the installed flag and the blessings.includes identity check
both fail when the package is bundled twice (two dependency graphs),
so each copy pushed its own ElementsBlessing.

Tag the blessing with Symbol.for("@openproject/stimulus-elements.
blessing") and dedupe on the tag: the global symbol registry is
shared across module copies, so any copy recognises a blessing
installed by another.

Also pin the README's ordering invariant with a characterization
test: controllers registered before installElements() silently lack
accessors — Stimulus snapshots blessings at registration onto a
shadow constructor and leaves no observable trace, so a late-install
warning is not implementable without an import-time side effect
(forbidden by sideEffects: false). Documented in README and install.ts.
Copilot AI lite review requested due to automatic review settings August 10, 2026 20:59

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens installElements() by making blessing installation dedupe across multiple bundled copies of the library (so the “double bundle” case becomes safe by behavior, not just by comment), and it pins the Stimulus ordering invariant (“install before register/start”) with focused browser-mode tests and clearer README guidance.

Changes:

  • Tag the blessing with a Symbol.for(...) key and dedupe based on that tag rather than function identity.
  • Add dedicated tests covering (a) silent failure when controllers are registered before install and (b) cross-bundle dedupe behavior.
  • Update documentation and add a patch changeset describing the behavior and invariant.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
test/install-order.test.ts Adds an end-to-end characterization test for the “install before register/start” ordering invariant and its silent failure mode.
test/install-dedupe.test.ts Adds a test ensuring installElements() dedupes a blessing installed by another bundled copy via Symbol.for tagging.
src/install.ts Implements cross-bundle blessing dedupe using a shared symbol tag and documents the ordering invariant.
README.md Documents that late install fails silently and that repeated installs (including bundled duplicates) are safe.
.changeset/calm-installs-dedupe.md Adds a patch changeset for the cross-bundle dedupe + documented silent failure invariant.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +24 to +30
// silent failure: no accessors, no warning, no error
expect(early.thingElement).toBeUndefined()
expect(early.hasThingElement).toBeUndefined()

// installing afterwards does not retro-bless already-registered controllers
installElements()
expect(early.thingElement).toBeUndefined()
@myabc
myabc changed the base branch from code-maintenance/vitest to main August 10, 2026 21:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants