0146 — Team notices and staff replies live on the source conversation

Context

On 2026-10-18 Clara emailed Western Slope's leasing inbox about a leak call. The email went out, and its body even linked to the conversation. But nobody could show from our side that the team had been told: the conversation page showed only the call. For companies on the team-notification engine (Western Slope and JPCO), the engine records the send as a TeamNotice row in its own partition (src/lib/team-notify/live-deps.ts:48, noConversationRecord), and the page never reads that partition. #19577 added the thread write only on the pre-engine send path, which those companies no longer use.

The team's replies were lost as well. The copy that matched our notice only closed it (team-notify/ingest.ts:74-77), and the reply text was written nowhere. A header-less sent copy was matched by sender address to an unrelated placeholder renter. Clara answered it as that renter, and a team note went out saying "no leak report appears in this conversation thread", which was false. #20949 stops staff mail being treated as customer mail and is live in production. The placeholder's claim on the leasing inbox was retired, and its stale open question closed, on 2026-10-19.

About 40 staff-notice paths exist, and most leave no row on any conversation.

Decision

  1. Every team notice is a row on its source conversation. Any channel (email, SMS, call, Slack), written through the ADR-0119 door as kind: team_notice with the recipient, channel and provider id, and only when delivered. A notice whose conversation id does not name a real conversation (a PMS id, a tour id) writes nothing and alerts. A conversation is never created for a notice.
  2. Every staff reply is a row on the same conversation. It is a new team_notice_reply kind, matched through the one staff-reply door (ADR-0141), with an idempotency key on the reply's Message-ID or SID, so duplicate copies make one row. A staff reply is never matched to a person by sender address alone.
  3. Every team notice carries the conversation link, built by one helper and always opening the right thread.
  4. Whether Clara answers a staff reply follows Fede's shared-inbox reply gating design (Fede, 2026-10-19), and it runs in Supervised first. The gate has three layers: is the message for Clara at all (if not, she stays quiet); can she actually help (no "I'll check with the team" replies); and does she reply only when about 95% confident nobody else has handled it. This ADR decides only that a staff reply, and any answer Clara sends, is recorded on the source conversation. The #20949 guards stay: staff mail is never a customer turn.
  5. One team-notice door. The pre-engine send path folds into the one team-notice door (sendOrHoldTeamNotice) in the workstream-C PRs, so the thread row is written in one place. No second send path stays alive alongside it.
  6. Every email sent to staff carries a reply tag, including the forward-to-property-manager email (handle-forward-to-property-manager.ts:1700, which has none today).

Consequences

Alternatives considered