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, andlabelsremain envelope concernssubject,predicate, andobject_jsonremain fact concerns- labels express policy treatment, not business truth
- routing and lineage must not be encoded inside
object_jsonmerely 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