Skip to content

Plugin namespace isolation — detect and warn on method collisions #1977

Closed

Description

@bpamiri

Summary

When two plugins provide the same method name for the same mixin target, the last-loaded plugin silently overwrites the first. There is no warning, no error, and no way for plugin authors or users to know this happened.

Current Behavior

In $processMixins(), methods are collected into a struct keyed by method name. StructAppend with overwrite=true means the last plugin wins silently.

Proposed Behavior

  • During $processMixins(), detect when a method name already exists in the mixin collection for the same target
  • In development mode: log a warning listing the collision (plugin A method X overwritten by plugin B method X)
  • In production mode: log at debug level only
  • Optionally (future): allow plugin.json to declare explicit overrides to suppress the warning

Files

  • vendor/wheels/Plugins.cfc:219-274 — modify $processMixins()

Phase

Phase 1 — Cleanup & Foundation (3.x, no breaking changes)

Activity

  1. bpamiri commented on Mar 16, 2026

    @bpamiri
    CollaboratorAuthor

    Analysis

    Synopsis

    Detect and warn when two plugins provide the same method name for the same mixin target, instead of silently overwriting. Currently, $processMixins() uses StructAppend semantics where the last-loaded plugin wins with no diagnostic output.

    Merit Assessment

    Recommendation: Proceed

    • This is a real pain point for plugin users — silent overwrites cause hard-to-diagnose bugs where a plugin appears loaded but its methods are missing.
    • The fix is purely additive (logging/warning) with no change to runtime behavior — last-loaded still wins, but now you know it happened.
    • Aligns with the broader plugin system improvement goals by making the mixin system observable.

    Implementation Plan

    1. Modify $processMixins() in vendor/wheels/Plugins.cfc:219-274:

      • At line 265, before assigning the method into variables.$class.mixins[target][methodName], check if that key already exists.
      • If it does, record the collision in a new variables.$class.pluginCollisions array of structs: {method, target, overwrittenBy, previousPlugin}.
      • To track which plugin originally provided a method, maintain a parallel struct variables.$class.mixinSources[target][methodName] = pluginName alongside the mixin assignments.
    2. Add collision reporting:

      • Add a getter: getPluginCollisions() returning the collision list.
      • In Global.cfc:$loadPlugins() (line 2767-2786), after plugin loading, check PluginObj.getPluginCollisions().
      • If in development mode and collisions exist, log via $log(type="warning", ...) or store in application.wheels.pluginCollisions for display in the debug panel.
    3. Wire into the debug/info panel:

      • vendor/wheels/public/views/info.cfm already displays plugin settings — add a collision warning section if application.wheels.pluginCollisions is non-empty.
    4. Add tests:

      • Create a test plugin asset directory (e.g., tests/_assets/plugins/collisions/) with two plugins providing the same method name.
      • Verify getPluginCollisions() returns the expected collision data.
      • Verify the method from the alphabetically-last plugin wins (since plugins are sorted by ListSort(StructKeyList(...), "textnocase")).
    5. Estimated complexity: Low-medium — ~20 lines in $processMixins(), ~10 lines for the getter, ~15 lines for reporting.

    Dependencies & Risks

    • Independent of other Phase 1 issues, but benefits from Add plugin.json manifest support alongside box.json #1976 — if plugin.json has an overrides key, collision warnings could be suppressed for intentional overwrites.
    • No breaking changes — existing behavior (last plugin wins) is preserved.
    • Plugin load order is deterministic (alphabetical via ListSort at line 227), so collision results are stable across platforms.

    Automated analysis by @claude — review and adjust as needed.

  2. added this to the v3.1 milestone on Mar 17, 2026
  3. bpamiri commented on Mar 26, 2026

    @bpamiri
    CollaboratorAuthor

    Implemented: $processMixins() tracks method providers per target and records collisions in mixinCollisions array. Warnings logged in development mode.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions