Skip to content

event_tone() gives failed sends (send_error / create_group_error) a non-error tone, so failed operations render identically to successful traffic on the timeline #294

Description

@erskingardner

Summary

event_tone has an explicit "error" branch for publish_failure, but no branch for the sibling failure event types send_error and create_group_error. Both are real, ingested event types, and both fall through to the generic startswith("send_") catch-all — so a failed send is painted with the neutral/positive "send" tone (visually identical to a successful send_entry/send_outcome) and a failed group creation is painted "receive". Neither failure is highlighted, even though the analogous publish_failure is.

Code

forensics/analysis.py:860-882:

def event_tone(event: AuditEvent) -> str:
    if event.event_type == "human_action":
        return "send" if event.human_action_origin == "local_user" else "receive"
    if event.event_type == "publish_failure":
        return "error"
    if event.event_type == "publish_outcome" and event.failed_relays:
        return "error" if not event.met_required_acks else "send"
    tone = "send" if event.event_type.startswith("send_") else "receive"   # catch-all
    ...
    return tone

send_error and create_group_error are ingested event types (forensics/ingest.py:661 case "send_error":, :670 case "create_group_error":, which populate outcome_kind/detail):

  • send_errorstartswith("send_") is True → tone "send"
  • create_group_error → tone "receive"

Concrete failure scenario

An audit log contains a send_error (a send that failed — relay rejected, encryption error, etc.). On the timeline (timeline_item_for_eventevent_tone, analysis.py:1465) it is rendered with the "send" tone, indistinguishable from a successful send. The analyst gets no error indication for a failed operation. Failed sends and failed group-creations silently blend into successful traffic — a correctness gap for a forensic triage surface.

Related supporting defect (same root cause)

event_summary (analysis.py:823-857) likewise has no send_error/create_group_error case, so it returns the bare event.event_type (line 857) and never surfaces the ingested outcome_kind/detail — whereas publish_failure summaries include the reason (line 835-836). The failure reason is dropped from the summary line.

Why not a duplicate

The two existing event_tone issues are #191 (successful/attempted publish events classified inbound "receive") and #258 (create_group_outcome classified "receive"). Neither concerns the *_error event types being denied an "error" tone. This is a distinct misclassification of failure events.

Suggested fix

Add explicit "error" branches for send_error and create_group_error in event_tone, and matching cases in event_summary that surface outcome_kind/detail, mirroring the existing publish_failure handling.

Severity: MEDIUM — consistent with #191/#258; a failed forensic operation is not visually distinguishable from a successful one.

Metadata

Metadata

Assignees

No one assigned

    Labels

    MEDIUMSeverity: important bug or performance issue with bounded impactbugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions