Skip to content

Simulated correspondents: let participants reply to communications, LLM drafts the persona's counter-reply (facilitator-approved) #205

Description

@richardmhope

Summary

Communications are currently one-way and pre-scripted: the scenario (or the facilitator) sends a message from a simulated party — a regulator, a journalist, an attacker — and participants can only read it. In a real incident the pressure comes from the exchange: the regulator asks a follow-up question, the journalist pushes back on a non-answer. Let participants reply to a communication, and have an LLM play the correspondent's persona to draft the counter-reply.

Human in the loop — non-negotiable

Same "pull not push" philosophy as scenario branching: the LLM drafts, the facilitator releases. Nothing generated reaches participants without explicit approval. The SuggestedInject review-queue pattern is the template — a DraftCommunication (or similar) the facilitator can edit, approve, or discard from the console.

Design sketch

  • Personas in the scenario JSON: extend ScenarioDefinition with an optional correspondents block — id, display name, role/voice description, goals, what they know and don't. Communications reference a correspondent id. Validated like everything else in the definition.
  • Reply endpoint: participants POST a reply to a communication (scoped by visible_to_teams / team membership like existing comms reads). Replies are visible to the facilitator and the replying team.
  • LLM pipeline: reuse the existing provider adapters (Clean up lint/security findings; add bandit + vulture config #26) and the run_llm_pipeline background-task pattern (own AsyncSession(engine), honours the outbound proxy Support outbound HTTP proxy for LLM APIs and SIEM egress (adopt iceberg's ProxySettings model) #97). Context: persona definition + the communication thread so far + a scenario summary (same memoised-summary approach as _scenario_summary).
  • Facilitator console: drafts land in a review queue alongside suggested injects; approving one sends it as a normal Communication on the existing WS broadcast path.
  • Threading: comms need a parent/thread reference so the inbox reader can render an exchange rather than a flat list.

Constraints to respect

  • Single-replica: background drafting tasks follow the existing in-process pattern until the Redis/task-queue work happens.
  • LLM disabled (settings without a provider key) must degrade to "replies are recorded and visible to the facilitator, no drafts" — not a 500, and per Explain disabled features to admins instead of silently hiding them #187 the UI should say why.
  • Audit: persona sends and participant replies are exercise events and belong in the audit trail like existing comm sends.

Why it's worth doing

This is the feature that separates a TTX tool from a shared document: scripted comms test whether people read, correspondence tests whether they can respond under pressure. No comparable tool in this space does it with a facilitator-approval loop.

Out of scope (this issue)

  • Autonomous multi-turn exchanges without facilitator approval.
  • Simulated correspondents initiating unscripted first contact.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions