Symptom

A partially-implemented KrillApp.Trigger.Timer node never started its countdown. Dropping a Timer under a source and firing the source did nothing — no countdown, no observers fired — and the node had no editor (the editor when silently fell through to the empty else).

Root cause

Two wiring gaps in the half-finished feature:

  1. KrillApp.Trigger.Timer was missing from KrillAppEmit.processor(), so it hit the else -> null arm. ServerNodeManager.invoke() dispatches via target.type.processor()?.onInvoke(...); a null processor means the server-side onInvoke was never reached, so TimerBoss never ran.
  2. ServerTimerProcessor.onInvoke routed both EXECUTE and RESET to timerBoss.stop() — so even if dispatch had worked, EXECUTE would have stopped (a no-op) instead of starting the countdown. KrillAppMeta.meta() also handed the node a generic TriggerMetaData (no delay field) instead of TimerMetaData, and TimerProcessor was absent from ClientProcessModule’s binds.

Fix

Added the KrillApp.Trigger.Timer -> TimerProcessor arm to KrillAppEmit.processor(), the TimerProcessor::class binding to ClientProcessModule, and pointed KrillAppMeta.meta() at TimerMetaData. Corrected ServerTimerProcessor.onInvoke to EXECUTE -> start, RESET -> stop. Rebuilt TimerBoss around a single cancellable delay(meta.delay) (no wall-clock busy loop), persisting PROCESSING on start, firing executeSources + clearing state on completion, and force-broadcasting STATE_CHANGE(RESET) on stop so clients drop the countdown pie. The client draws the pie purely from timerProgress(now, startTimestamp, delay), and the generic 1500ms activity-pulse reset is skipped for Timer nodes so a long countdown isn’t truncated.

Prevention

The “add a node type” checklist must include the dispatch entry point (KrillAppEmit.processor()), not just the handler body — a missing arm there is a silent no-op, not a crash. TimerWiringTest now guards that KrillApp.Trigger.Timer.meta() returns TimerMetaData, and ServerTimerProcessorTest pins EXECUTE -> start / RESET -> stop so the verb-swap regression can’t return. When a refactor changes how a unit is invoked, verify the dispatch path resolves to a processor, not only that the processor’s logic is correct.