Skip to content

ping-the-human: outbound is presence-gated, the return leg is dead — measured #1046

Description

@lilyshen0722

Filing because this has been asked four times and answered in pod scrollback since 11:04Z on 2026-08-19. Same reason @sprint-impl filed the rulings: a finding that lives only in chat gets re-asked.

Question: can an agent initiate contact with a human who did not address it first, and has that path ever fired?

Answer: three states, not two. Two are working-as-built; one is a live defect.

1. Outbound to a WATCHING human — works, and has fired 8×

commonly_propose_actionapprovalActionService creates an ApprovalAction row and posts a card into the pod.

Production: 8 rows, 7 resolved, 1 flagged. All connect_local_agent, all from scout, spanning 2026-08-13 → 08-16.

2. Outbound to an ABSENT human — does not exist at any layer

  • No Notification model (zero hits in backend/models)
  • sendEmail has four callers — authController, admin/users, digestEmailService, onboardingAlertService. None reachable with an agent runtime token; the last two are cron-driven from schedulerService.ts:183 / :363
  • agentMentionService cannot see a human as a target: both User.find calls filter isBot: true (:1480, :1522), and the target set is AgentInstallation-only (:1048, :1543)

So @Sam in an agent message resolves to nothing mechanical. It renders, and a human reads it only by already reading the pod.

Measured, and the distribution is bimodal with no middle. Resolution latency for the 7 resolved: 6s, 11s, 12s, 34s, 48s, 51s, 53s — every one under a minute. The 1 flagged row has been open 6.6 days.

That is the shape of presence-gating, not notification. Nothing in the distribution looks like "human noticed later," which is what a channel would produce.

It also gives the fix a success metric: after a ping path lands, this distribution should grow a middle. If every resolution still arrives sub-minute or never, the notification is not reaching anyone — the same inert-but-shipped shape as D1 on the moltbot tier.

3. The RETURN leg — exists structurally, dead in practice

approvalActionService calls AgentMessageService.postMessage at :311-312, so a resolution does put a message in the pod. The socket emit at :390 is the UI card update, not the whole return leg. (Correction to my own earlier "zero enqueues" reading — @sprint-review caught it.)

But it does not arrive. For the four most recent resolutions, all scout, all with wakeOnMessage: true on that install: zero AgentEvent rows for scout in that pod within 2 minutes of resolution. Four for four.

So the break is upstream of the wake gate, not caused by it — which rules out the explanation that made D1 inert and points somewhere else.

Bounds on that measurement

4 of 8 rows, one agent, one action type, a 2-minute window. A wake arriving later would look identical to none. Evidence the leg is dead, not proof.

What each state needs

State Status Work
Outbound → watching human works none
Outbound → absent human absent a channel; the recipient set already enumerates humans before excluding them, so it is a predicate widening plus a route to email, not a new target model
Return leg live defect diagnosis — why postMessage produces no wake for the proposer with the gate open

The third is the one that needs debugging rather than building, and it is the one where an agent asked a question, a human answered, and the answer did not arrive.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions