Channel conditions — what a status can honestly say

Not "what the Home payload returns" — what the system actually knows. Every line below is read out of channel-gates.ts, silence.ts, home.service.ts and Home.tsx. Where I previously told you something different, it is marked and corrected.

Four things I had wrong, found by reading the source

1 · Receiving is never gated. Only acting is. channel-gates.ts on instagram:dms: "off = the agent does not even decide (inbound DMs are still stored — receive is ungated)". So a Messages tile showing 0 because DMs are off — which is what I drew — is false. Messages arrive and are stored whatever the gate says. The gate decides whether the bot answers, not whether the count exists.
2 · There are nine gates, not two. The payload exposes whatsapp.agent, instagram.comments and instagram.moderation. The registry defines nine surfaces across three channels, each independently flippable.
3 · "Silent" is a threshold over a configurable clock, not "nothing lately". evaluateSilence counts hours in one of two modes — always (24/7) or business-hours (configurable days and window) — and sets silent = countedHours >= thresholdHours. In business-hours mode a channel quiet all weekend has hoursSince: 0 and is not silent, by design. A status that says "gone quiet" is making a claim about the operator's own configured working week.
4 · Facebook Messenger has no pipeline at all. Not "off" — absent. facebook:dms: "no webhook ingestion, no normalized inbound adapter, no sender. The gate + the channel profile exist so the PLAYGROUND can simulate a FB DM turn." A Facebook Messages tile can only ever read zero, and the reason is structural, not a setting.

1 · Every dimension the status can read

Nine independent inputs. A status line is a function of some subset; nothing else exists to read.

DimensionValuesSource of truthWhat it actually means
Configuredtrue / falseconnections row existsA connection record for this provider exists at all. False = never set up.
Activetrue / falseconnections.isActiveThe operator switched this connection off here. Nothing to do with Meta.
Last webhook eventdate / nullwebhook event logThe last time Meta delivered anything on this channel. Null = never, in the whole history.
Silencesilent: true / false / null
hoursSince: number / null
silence.ts evaluateSilencenull means never heard from — unknowable, not healthy. Otherwise counted hours ≥ threshold, counted 24/7 or business-hours-only per config.
Mutedstring / nullalerts.configThe operator declared this channel knowingly dead, in their own words. Defaults to the bare word "Muted" when no text was given. Independent of the live silence reading, on purpose.
Gatesoff / shadow / live
(WhatsApp: off / canary / live)
channelGates settingWhether the agent acts on this surface. Never whether messages arrive.
Errors 24hwebhookErrors + failsafeshome.service errors()Delivery failures and times the agent stood down. Two different things, currently summed.
Last inbound / outbounddate / nullmessage tablesReal traffic, as distinct from webhook chatter. A channel can get webhooks and no messages.
Quality & quotarating · tier · used/limitMeta, WhatsApp onlyExists for WhatsApp alone. No equivalent on Instagram or Facebook.

2 · Which surfaces each channel actually has

The gate registry is not symmetrical. A status that offers the same four facts per channel is inventing three of them.

SurfaceWhatsAppInstagramWeb chat
Reply to messagesoff · canary · live
canary = an allowlist of numbers
off · shadow · live
send arm built dark
no pipeline at all
playground simulation only
does not exist
Reply to commentsno commentsoff · shadow · liveoff · shadow · livedoes not exist
Moderate commentsno commentsoff · shadow · live
defaults to shadow
off · shadow · live
defaults to shadow
does not exist
Comment → open a DMno commentsoff · shadow · liveoff, built dark
token has no messaging scope
does not exist
Quality & sending limitrating + daily quotanonenonenone
Receivingalways on, on every connected channel — no gate governs itnot connected

3 · What a status line can honestly say, and when

Ordered by precedence. Every row states the condition, what may be claimed, and what it must not claim — the second column is the one that keeps a status honest.

ConditionCan honestly sayMust NOT sayWhy
Not configuredNot set up · Not connectedanything about traffic or gatesThere is no connection to describe. Gate values may still be stored and are meaningless.
MutedThe operator's own words · and the real traffic figures"silent" as a diagnosisThe ruling is that Home says WHY, not just silent. Muted survives a healthy blip on purpose.
Not activeSwitched off by you"Meta disabled this"This flag is local. Conflating it with a Meta action misdirects the fix.
silent === nullNothing has ever arrivedhealthy, or "gone quiet"Unknowable, not OK. Never-heard-from is a different fact from stopped-hearing.
silent === trueNothing for N counted hours"broken", or a bare hour countN is counted under the operator's own business-hours config. The number is meaningless without the window.
All gates offReceiving, answering nothing"not working" or "off"Receiving is ungated. Messages are still arriving and being stored.
Any gate shadowWriting, holding it for you"answering"Shadow means propose-and-approve. Nothing reaches a customer.
WhatsApp canaryAnswering a named few"live" or "answering"Canary is an allowlist. Everyone not on it gets nothing.
Any gate liveAnswering, and on which surfacea blanket "answering"Comments live with DMs off is not the same product as both live. One word cannot hold it.

4 · The thing the audit really exposed

One line cannot hold this, and that is the finding. A channel has up to four independently gated surfaces, plus a connection state, plus a silence state that can be null, plus an operator mute. My seven-step ladder picked one and threw the rest away — which is why "Answering on its own" felt wrong to you: it was true of comments and silently false about DMs.

The shipped screen is more honest than my mockups: it renders connection and webhook as two separate pills and lists every gate. It is ugly, but it does not lie.

So the real design question is not which words to use. It is: does the channel box carry one verdict, or one line per surface? That is the fork worth ruling — and it is yours, not mine.

5 · Exposed today vs knowable

FactOn the Home payloadTo get it
Connection, silence, mute, errors, last in/outyesnothing
whatsapp, instagram:comments, :moderationyesnothing
instagram:dms, instagram:comment_to_dmnoread from the same resolved gates object already in scope
Facebook, entirelynoa third member on the channel union + its four gates
Per-channel message counts todayonly WhatsApp + InstagramHomeToday.messages needs a Facebook key
Comments vs messages, counted apartnothe tiles you picked need this split; today it is one number
A 14-point daily series per channelnonew aggregation — this is what treatment C's sparkline needs
Quality & quotaseparate endpointsalready fetched by the old Home, WhatsApp only