Skip to content

moooon

Motir

Vibe your whole project. Bring an idea — Motir's three AI layers plan it, track it, and ship it, end to end. You're looking at Motir, built in Motir.

  • Vibe Project
  • Open Source
  • AI Agent
  • AI Loop
1
requests
0
upvotes
145
planned
1,361
shipped

Motir · Work items

MOTIR-295Done

5.4.5 Watcher notification job — `work-item/transitioned` event + fan-out on comment/transition (actor excluded, mention-dedupe, idempotent)

Estimate: 30m · Depends on: 5.4.4, 5.1.6

The watcher email pipeline, on the 5.1.6 pattern.

New event: work-item/transitioned (workspaceId, workItemId, actorId, fromStatusKey, toStatusKey, revisionId) — emitted by workItemsService.updateStatus AFTER its transaction commits (today it writes only the revision row — rung-2 fact; the event NEVER fires on rollback, the 5.1.2 rule). Typed in JobEventDataMap.

Job (lib/jobs/definitions/watcherNotify.ts, the 1.6 defineJob harness): consumes work-item/comment.created (5.1.6's event — the SAME emit, a second consumer; no new emit path) and work-item/transitioned. Per event: page through the issue's watchers; exclude the actor (the verified never-self-notify default); exclude the comment's mentioned users (they get the 5.1.6 mention email — one email per person per event, the dedupe rule); re-validate view access at send time; render watcherCommentNotification / watcherTransitionNotification templates (pure, hand-written plain text, deep link — the emailTemplates contract; "<Author> commented on PROD-N" / "<Actor> moved PROD-N to <Status>") and send idempotently per (event × user) via the harness key. Failures → DLQ. Fan-out is PAGED (a 200-watcher issue never builds an unbounded batch).

Acceptance criteria

  • work-item/transitioned is typed + emitted post-commit by updateStatus (rollback emits nothing); existing transition tests stay green.
  • The job mails every watcher EXCEPT the actor and (for comments) the mentioned users; targets failing the send-time view check are skipped; both templates are pure with unredacted deep links.
  • Replay/retry double-sends nothing (idempotency per event × user, @inngest/test coverage); failures land in the DLQ; fan-out pages.
  • Coverage gate ≥90% on the job + templates + the emit seam.

Context refs

  • lib/jobs/definitions/ + 5.1.6 (mentionNotify — the pattern + the shared comment.created event + the mention-recipient list to dedupe against)
  • workItemsService.updateStatus (the post-commit emit point; its revision write at lines ~768)
  • lib/emailTemplates/ contract + workspaceInvite.tsx exemplar
  • The verified notify rules (watchers on comment/transition; never the actor) in the Story 5.4 description; Story 5.7 (the in-app consumer of the same events)