Skip to content

copy_publish_fields silently drops a scalar relay_url when the relay_urls key is present-but-null/empty, losing relay attribution from the normalized projection #322

Description

@erskingardner

Summary

copy_publish_fields gates storing the scalar relay_url on "relay_urls" not in kind (key-existence), while the companion copy_optional_str_list("relay_urls") treats a present-but-null/empty relay_urls the same as absent. When an event carries both a real relay_url and a null/empty relay_urls, the two functions disagree on what "relay_urls is present" means and neither stores the relay — silently, with no validation error.

Location

forensics/ingest.py:1272-1277

relay_url = kind.get("relay_url")
if relay_url is not None:
    if not isinstance(relay_url, str):
        errors.append("relay_url must be a string when present")
    elif "relay_urls" not in kind:      # key-existence, not "a usable list was produced"
        normalized["relay_urls"] = [relay_url]

Failure scenario

{"type":"publish_failure", "relay_url":"wss://relay.example", "relay_urls":null} (or "relay_urls":[]):

  1. copy_publish_fields runs. relay_url is a valid string, but "relay_urls" not in kind is False (the key exists), so relay_url is not stored.
  2. For publish_attempt/publish_outcome, the follow-up copy_optional_str_list(kind, ..., "relay_urls") sees null/[] and stores nothing. For publish_failure, there is no follow-up call at all.

Net: the relay attribution is discarded from normalized["relay_urls"] with the event still marked valid (no error). The raw line is preserved, so this is a normalized-projection evidence gap rather than raw-evidence loss, but it silently weakens relay attribution in every derived view.

Fix

Gate on whether a usable relay_urls list was actually produced, not on key existence — e.g. check not normalized.get("relay_urls") after the list copy, or treat a null/empty relay_urls as absent when deciding whether to fall back to the scalar relay_url.

Relationship to existing issues

No existing issue touches the relay_urlrelay_urls interaction or this silent-drop path.

Filed by an automated code-review pass.

Metadata

Metadata

Assignees

No one assigned

    Labels

    LOWSeverity: minor correctness, polish, or maintainability issuebugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions