Time-Based Triggers: these had never actually fired (2026-08-02)
The page described the design correctly; the code did not match it. A
duplicate sla_format_minutes() fataled the SLA cron on invocation, so
sla.warning and sla.breached had never fired since the feature shipped
on 17 May — with two further wrong-column bugs hidden behind it.
Recorded here because the page is what someone will trust when adding
the next one: a trigger being registered, documented and visible in the
editor proves nothing about whether it fires. Make it fire.
Issue trackers: tracker.* triggers (#958), and why they are not time-based
Engine guide gains 7f: the three triggers, that each carries the ticket,
the aliased columns in the payload query that are silent when wrong, and
the comment loop that terminates only because send_note_to_tracker
records what it pushes.
Time-Based Triggers gains a "a cron is not the same as time-based"
section, because reusing the emissions ledger for these is the obvious
instinct and it is wrong — a fingerprint on current state would swallow
a genuine third transition.
Time-Based Triggers: its own page, a dev recipe, and Pitfalls #9
The #801 write-up was buried mid-page in Workflows, so it never appeared in the
sidebar tree — you could only find it if you already knew it was there.
New page: Time-Based-Triggers.md — the four triggers and their crons, the
fire-once ledger, the fingerprint, the four starter recipes, cron setup, and how
to test it by hand without waiting for a scheduler.
Plus what was missing everywhere: HOW TO ADD A NEW ONE. Register the trigger,
write the detector, choose the entity_key and fingerprint (that choice IS the
job — everything else is boilerplate), register with the cron, ship a recipe.
With the traps nobody would guess: changing the fingerprint formula re-arms every
in-window record AT ONCE, and renaming a trigger silently orphans live workflows
(workflows.trigger_event is a plain string nothing validates — the workflow stays
active, looks healthy, and never fires again).
Pitfalls #9: the fire-once ledger that burned its emission on an audience of
nobody. The cron runs from install; by the time you BUILD a renewal workflow the
ledger already says "already fired" for every contract in-window, so switching it
on leaves it permanently silent for exactly the contracts you built it for — and
nothing is observable. Found by asking what happens on a FRESH INSTALL, which the
happy path never exercises.
Workflows.md keeps a summary + link. Sidebar and See-also updated.