Architecture Decision Record

BSFG ADR-0024

Status: Accepted · Date: 2026-03-06

Status: Accepted

Date: 2026-03-06

Context

BSFG stores large artifacts out-of-band and references them from facts. This creates a design question: should the boundary contract expose a single convenience operation that both uploads an artifact and appends the referencing fact, or should these remain separate primitives?

The architecture already distinguishes:

  • artifact storage as object-store durability
  • fact append as semantic log history

The decision must preserve conceptual clarity without making common client flows unnecessarily awkward.

Options Considered

Option Description Benefits Drawbacks
Single combined primitive only Expose one core RPC that uploads the artifact and appends the fact in one operation. simple client experience
one obvious path for attachments
mixes artifact durability with fact semantics
hides two distinct failure modes behind one call
encourages false expectations of atomicity
Best-effort wrapper as the only public API Expose only a convenience wrapper that internally calls object storage and fact append separately. pleasant client ergonomics
server can enforce policy centrally
core model becomes obscured
wrapper semantics can be misunderstood as fundamental
less explicit failure handling
Separate core operations (Selected) Keep PutObject and AppendFact as distinct primitives; allow wrappers only as optional conveniences outside the core contract. preserves conceptual clarity
makes failure modes explicit
keeps the core boundary contract minimal
matches the architecture’s fact-vs-artifact distinction
two-step client flow
orphaned uploads must be cleaned up if append never occurs
Artifact-first implicit append Make object upload itself create a fact automatically. very small client surface
artifact provenance is automatic
wrong abstraction boundary
not every stored object implies a fact worth appending
semantic control is lost

Decision

BSFG keeps artifact upload and fact append as separate core operations.

PutObject(blob)   -> object store durability
AppendFact(ref)  -> semantic history

The canonical boundary contract therefore remains:

AppendFact
FetchFacts
ConfirmReceipt
PutObject

A fact that references an artifact is appended only after the artifact reference is known. The reference must include sufficient integrity and retrieval metadata, such as bucket, key, digest, size, and media type.

Convenience wrappers such as AppendWithAttachment may exist in higher-level SDKs or service facades, but they are not part of the core BSFG architectural primitive.

Consequences

Benefits:

  • the fact log remains semantically explicit
  • artifact durability and fact durability are modeled separately
  • operators can diagnose storage failures independently from append failures
  • the core protocol stays narrow and principled

Tradeoffs:

  • clients perform a two-step write path for large artifacts
  • implementations need orphan cleanup for uploaded-but-unreferenced objects
  • SDKs may add convenience layers that must not be mistaken for the core model