- Shipped
- July 27, 2026 at 7:15 PM UTC
- Author
- Kamo
- Commit
- 72abd22
DECISION_ROUTED's steward notification was a record-only no-op: StewardNotifier fanned out over SMS to a static CSV **************** that is empty by default, and it ignored StewardTask.assignedMemberId entirely — the very field the spine's StewardAssigner already stamps (license-aware, least-loaded). StewardRecipientResolver loads the task by the event's taskId, reads assignedMemberId, and resolves that member's email (falling back to the org owners only when the task is unassigned; an assigned-but-unreachable steward is an honest no-op, never an owner escalation). Mirrors the proven **************** Delivery is now the existing canonical email-template system (STEWARD_TASK_ROUTED) as the primary path; the SMS option is retained. When neither resolves it stays a logged no-op — never a silent success. The email client binds mlos.internal-auth-secret — NOT the daemon's internal.auth.secret, which resolves to the public-chat value; EmailService validates templates/send against the mlos-internal-auth secret, so a naive mirror of the SecurityService client would 403. DaemonServiceApplication now scans com.kamo.z.shared.mlos.steward for StewardTaskRepository. 40 tests green (7 new resolver cases: assigned->contact, unassigned->owner fallback, assigned-but-no-email->no-op, task-not-found, null taskId). KNOWN CAVEAT (not fixed here): the DECISION_ROUTED emitter is dormant in-cluster — mlos.spine.enabled is set true in no checked-in config, so DecisionSpine emits nothing until a service enables the decision spine. This fix is correct and ready but will not fire until then; enabling the spine is a separate, broader decision.