# Grid-agent chat and instant-message interaction

`InteractionCoordinator` is the single bounded owner for public chat and
one-to-one instant messages. A live session generation installs exactly one
native `AgentManager` chat subscription and one IM subscription. Their RAII
guards are removed before logout. Connect and disconnect state travels on a
separate watch channel, so inbound queue saturation cannot delay generation
cancellation or reconnect fencing.

## Admission and routing

Inputs are normalized into bounded values before enqueue. Self messages,
objects and system chat, muted residents, typing notifications, group or
conference IMs, malformed or oversized input, repeated delivery IDs, and
reflections of delivered output are suppressed. Public chat is admitted only
for a configured alias or mention, a brief nearby greeting, or a short-lived
follow-up from a resident already engaged by the agent. Ambient region chat is
not sent to the model.

Public chat always has `Public` origin, even when the resident UUID appears in
the operator allowlist. Public commands receive a fixed denial; public LSL
requests remain policy-gated. Direct-message authority is derived solely from
the sender UUID in `authorized_avatar_uuids`. Text claiming to be an operator
cannot change that origin. Unprivileged IM remains informational, while an
authorized IM may expose only the tools returned by `PolicyGateway` for its
immutable request context. Unknown or unregistered tools fail closed.

Each avatar and channel has an independent FIFO with fragment debounce. A
round-robin ready queue permits at most one active request per FIFO and enforces
the configured global inference cap, so a slow resident does not block other
residents or lifecycle work. Direct-message context expires after 24 hours as
defined by `ConversationStore`; public and direct context never mix.

## Delivery and safety

Model work has a configured deadline and shares generation cancellation.
Visible text is checked for credential, authorization, hidden-prompt, and tool
schema markers; URLs are omitted and ASCII mentions are neutralized. The total
response is bounded, then split only at UTF-8 boundaries into at most 1,023-byte
grid messages. Public chat and IM use independent rate limiters.

Every outbound part carries its trigger delivery ID, conversation session ID,
session generation, channel, part index, and part count. A delivery observation
records success, timeout, policy denial, or failure plus the number of parts
actually delivered. Fixed busy/failure text is emitted only for an admitted
interaction. Successful public replies also publish a content-free attention
request for later avatar behavior work.

## Shutdown and focused verification

Disconnect cancels all generation tasks and drops queued input. Reconnect
starts a fresh generation without clearing the bounded duplicate/reflection
history. Shutdown disconnects first, joins every model/delivery task within the
configured deadline, and flushes conversation persistence. No callback or task
is detached.

```sh
cargo test --locked -p metacrate-grid-agent --lib interaction_tests
cargo test --locked -p metacrate-grid-agent --test dependency_policy
cargo clippy --locked -p metacrate-grid-agent --all-targets -- -D warnings
```
