stnd.buildSTANDARD MANUAL2026-08-23
STD-5-2-HOOK

5.2 Hook Kind Mismatch

Hook Kind Mismatch

Error: Hook "X" is registered as both a logic hook and a UI/action zone contribution.

The Problem

Two different modules (or two entries in the same manifest) register the same hook name, but the entries classify into two different kinds:

  • logic hook — a .js/.ts entry whose name doesn’t start with launcher: and doesn’t end with :action. Compiled into virtual:stnd/hooks, called via runHook()/runPipeline().
  • UI/action zone contribution — everything else (.astro/.svelte components, or any launcher:-prefixed / :action-suffixed entry regardless of file type). Compiled into virtual:stnd/components, rendered via <Hook zone="..."> or read directly as extensions[zone].

The Why

These are two disconnected virtual modules with different consumers. A hook name silently meaning two different things depending on which module registered it first means half the registrations are invisible to whichever consumer asked for the other kind — a runPipeline("X", ...) call would never see the UI-classified entries, and a <Hook zone="X"> would never see the logic-classified ones. No error, no warning — just a feature that silently doesn’t work for some of its contributors.

This mirrors launcher-trigger-collision and module-duplicate-id: the framework prefers a loud build-time failure over unpredictable, silently-partial behavior.

The Solution

  1. Rename one of the hooks. If the two features are genuinely distinct, give them different names.
  2. Match entry types. If they’re meant to be the same hook, make sure every registration classifies the same way — e.g. don’t mix a .astro UI entry and a .ts action entry under one name unless the name is launcher:-prefixed or :action-suffixed (which always forces UI/action classification).
  3. Avoid launcher:/:action naming for logic hooks. If you want runHook/runPipeline semantics, don’t name the hook launcher:* or *:action — those patterns always route to the UI/action pool regardless of entry type. See also hook-server-flag-ignored, the related trap this naming pattern creates.
  • modules: How the Standard module system works, including the full hooks: contract.
  • launcher-trigger-collision: The same “fail loud on ambiguity” principle applied to launcher triggers.