Architecture Decision Record

BSFG ADR-0037

Status: Accepted · Date: 2026-03-06

Status: Accepted

Date: 2026-03-06

Context

Messaging systems classically distinguish header from body: the header carries meta-information such as origin and destination, while the body carries the transmitted application data. :contentReference[oaicite:0]{index=0}

BSFG already adopted:

message = envelope + fact
fact    = (subject, predicate, object_json)

The remaining architectural question is not whether both parts exist, but whether teams are allowed to blur them by placing policy, routing, or lineage semantics into the fact body, or by placing domain meaning into envelope metadata.

Options Considered

Option Description Benefits Drawbacks
Loose mixed model Allow envelope and fact body to carry whichever metadata is convenient for each producer. maximal short-term flexibility
few structural constraints
semantic drift
weak replay discipline
routing/policy logic leaks into domain content
Everything in the body Treat the envelope as minimal transport glue and move most metadata into the fact body. single place to inspect data
reduced top-level fields
system metadata stops being uniform
transport concerns pollute domain semantics
harder operational filtering and governance
Everything in the envelope Push semantic meaning upward into metadata and keep the body opaque. simple transport processing
header-driven routing becomes easy
domain meaning becomes impoverished
replay loses semantic clarity
fact model becomes vestigial
Strict separation of system metadata and domain fact content (Selected) Envelope carries system-level metadata; fact body carries domain-level assertions only. clean architectural boundary
replay stays semantically coherent
ops and policy remain inspectable without parsing business payloads
fact content stays domain-focused
requires discipline from producers
some duplicated-looking information must remain intentionally separated

Decision

BSFG enforces a strict semantic separation:

envelope = system-level metadata
fact     = domain-level assertion

Therefore:

  • message_id, from_zone, to_zone, correlation_id, causation_id, and labels remain envelope concerns
  • subject, predicate, and object_json remain fact concerns
  • labels express policy treatment, not business truth
  • routing and lineage must not be encoded inside object_json merely for convenience
  • domain meaning must not be hidden in ad hoc envelope labels

This matches the classic message-header/body split in messaging systems, where headers carry meta-information used by the messaging system and the body carries the actual application data. :contentReference[oaicite:1]{index=1}

Consequences

Benefits:

  • fact history remains semantically clean and replayable
  • system-level concerns are inspectable uniformly across all messages
  • policy and routing logic do not infect domain payload schemas
  • producers and consumers have a clearer contract boundary

Tradeoffs:

  • teams must resist convenience-driven leakage across the boundary
  • review and governance are needed to keep labels from becoming pseudo-domain fields
  • some data may appear in both places for different reasons and must stay conceptually distinct