Notify the ASSIGNED steward of a routed decision, via email

FixDaemonService
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.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing