When multiple plugins register handlers for the same hook and execution order is undefined or depends on object property enumeration, plugin behavior becomes non-deterministic across JavaScript engines and load sequences. An auth plugin that must run before a logging plugin cannot declare that requirement. Debugging a production incident caused by handler ordering requires understanding internal host iteration behavior rather than a declared contract. ISO 25010 maintainability.modularity requires that component interactions be predictable; undefined execution order breaks this at the seam between every plugin pair.
High because undefined hook execution order makes multi-plugin behavior non-deterministic, turning plugin interactions into ordering-dependent bugs that are impossible to reproduce reliably.
Expose an explicit ordering mechanism — either a numeric priority parameter or a dependency-based after declaration — on every hook registration call. Document which strategy the system uses so plugin authors can predict relative execution.
// Priority-based ordering:
registry.on('before:save', handler, { priority: 10 }); // lower = earlier
// Or dependency-based:
registry.on('before:save', handler, { after: ['auth-plugin'] });
ID: plugin-extension-architecture.hook-system.execution-order
Severity: high
What to look for: When multiple plugins register handlers for the same hook, determine how execution order is decided. Look for:
add_action('init', callback, 10) where 10 is priority)Pass criteria: Count all hooks that support ordering. The execution order strategy is explicitly defined (priority, registration order, or dependency-based) AND documented. If multiple strategies are used for different hook types, each is clearly specified. Plugin authors can predict when their handler will run relative to other plugins' handlers. At least 80% of hooks with multiple listeners must have deterministic execution order.
Fail criteria: Execution order is undefined or random. No documentation or API for controlling order. Plugin authors cannot predict or influence when their handler runs. OR the code uses a data structure that doesn't guarantee order (e.g., Object.keys() iteration on an unordered map of handlers).
Skip (N/A) when: The system only supports one plugin at a time (single-plugin architecture) OR each hook allows only one handler (no multi-handler scenarios).
Detail on fail: "Multiple plugins can register handlers for the same hook via on(), but execution order depends on object property enumeration order, which is not guaranteed across JavaScript engines. No priority parameter or ordering documentation exists."
Remediation: Deterministic execution order is essential when plugins interact. Without it, behavior changes unpredictably based on load order, and debugging becomes nearly impossible.
// Priority-based ordering:
registry.on('before:save', handler, { priority: 10 }); // lower = earlier
// Or dependency-based:
registry.on('before:save', handler, { after: ['auth-plugin'] });