Both are invisible to a fixture and loud on a real database, which is why the
walk is the phase's acceptance rather than a formality.
1. registerEngagementSeeds validated `max_sends_per_hour` and then dropped it
from the normalized rule. The column is NOT NULL, so every one of the 25
module-seeded rules failed to insert at boot. The registry test asserted the
REJECTION of a bad ceiling and never that a good one survives; it now asserts
the normalized rule against `engagementRules.db.insert`'s own column list, so
the next field added is covered the day it is added.
2. The cooldown claim runs inside the engine's per-channel loop and its key was
(rule, user, subject). So the first channel of a rule claimed the cooldown and
every later one was reported as cooled -- and `inapp` is ranked first
deliberately, so a rule naming email + in-app delivered the inbox item and
silently never the mail. Core's own `news.post` rule has that shape. Phase
11b's decision 8 requires the letter and the inbox item to fire together.
`channel` joins the PRIMARY KEY (the org lead's decision 12: a cooldown is per
delivery, not per occasion). Migrated in place behind an information_schema
guard, because MariaDB has no conditional form of a key change and replaying
schema.sql would otherwise fail on every boot after the first.
1551 core tests green; both new tests verified by reverting each fix in turn.
Co-Authored-By: Claude <noreply@anthropic.com>