Skip to content

Relayed reactions are all attributed to the relay — read the originator-identity stamp #1007

@thatSFguy

Description

@thatSFguy

Follow-up to #926 (which converged Columba onto the upstream fields[0x40] reaction shape — thanks!). This is about attribution of reactions that arrive via a re-originating group relay.

Symptom

Columba already emits and parses the canonical fields[0x40] = {0x00: target, 0x01: emoji}, so reactions relayed through a group relay (e.g. reticulum-forwarding-service) render correctly on the right message — but they are all attributed to the relay, not to the person who reacted.

Why

A re-originating relay re-signs each message (and each reaction) as itself, so the carrying source_hash is the relay's. A reaction has no body to carry a [Nick] prefix, so ReactionWireCodec.parseCanonical (which sets sender = sourceHashHex) collapses every relayed reaction onto the relay's identity. Per the LXMF spec this is expected — §5.9.8 says reaction attribution rides on source_hash — and it's only a problem in the relay case.

The convention (app-layer, on reserved fields)

The relay restores attribution by stamping the reactor's source_hash (its lxmf.delivery destination hash — the same value a direct reaction carries, and what contacts are keyed by, per §9.1) into the reserved app-convention custom fields (§5.9.1):

fields[0xFB] FIELD_CUSTOM_TYPE = "originator-identity"   # exact UTF-8
fields[0xFC] FIELD_CUSTOM_DATA = <reactor source_hash, raw 16 bytes>

A cooperating client reads the stamp on a 0x40 reaction and attributes by 0xFC instead of the carrying source_hash, falling back to source_hash when the stamp is absent. Purely additive — the 0x40 wire format is untouched and spec-only clients ignore it.

Full convention + rationale + cross-client decode notes: reticulum-forwarding-service/docs/reaction-attribution.md.

Proposed fix

PR #1006 — a ~12-line change in the shared rns-api ReactionWireCodec (covers both backends): read the stamp in parseCanonical and use it as sender when fields[0xFB] == "originator-identity". No serializer change needed (AppDataParser.serializeFieldsToJson already surfaces 251/252).

Happy to adjust to fit Columba's conventions. (Note: I couldn't run ./gradlew :rns-api:test here — no Android toolchain — so please run it before merge.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions