Skip to content

docs: adopt ADRs (Architecture Decision Records) for load-bearing decisions #28

@jamesarich

Description

@jamesarich

Observation

A lot of the load-bearing architectural wisdom in this repo — transport interface as the sole platform boundary, internal-by-default API surface, single-Mutex send serialization, MQTT 5.0-first design, the nonWebMain source-set trick — currently lives in AGENTS.md and the README. That's great for onboarding agents and humans to what the rules are, but it's harder to recover why a constraint exists when a future contributor (or future-you) hits it and is tempted to "simplify" it away.

What's already here

Credit where due — docs/adr/ is already seeded with five solid ADRs:

# Title
0001 Transport abstraction as a pure-common interface
0002 Zero non-essential dependencies in commonMain
0003 Sealed MqttPacket hierarchy with free-function codecs
0004 In-memory QoS 1/2 state machine with session resumption hooks
0005 Coroutines-first public API (suspend + Flow)

So the foundation and the Michael Nygard template are already in place. This issue is really a proposal to extend the set, not start one. (If a richer template ever feels useful, MADR is a popular drop-in superset.)

Proposed additions

Reading through AGENTS.md, these feel like decisions a future contributor might reasonably want to second-guess and that would benefit from a recorded rationale:

  • Single-Mutex send serialization — one packet on the wire at a time. Worth capturing the alternatives considered (channel-based actor, lock-free queue) and why a Mutex won.
  • Public API allowlist (~15 types) — the "internal by default" stance with an explicit whitelist (MqttClient, MqttConfig, MqttMessage, QoS, ConnectionState, ReasonCode, etc.) is a strong claim that's enforced by apiCheck. An ADR would explain the SemVer/evolution reasoning so the bar for promoting a new type to public stays high.
  • nonWebMain custom intermediate source set — the interaction with applyDefaultHierarchyTemplate() (call it first, then layer nonWebMain with explicit dependsOn()) is non-obvious and easy to break. An ADR documenting why nonWebMain exists vs expect/actual would save someone a confusing afternoon.
  • MQTT 5.0-first, no 3.1.1 retrofit — worth recording explicitly so the answer to "should we add 3.1.1 support?" is a deliberate revisit rather than a default-yes.
  • GPL-3.0-only licensing — load-bearing for downstream consumers and worth a short ADR capturing the rationale and any considered alternatives (LGPL, Apache-2.0).
  • Packet ID allocation strategy — monotonic 16-bit wrap with Mutex-guarded state. Lightweight but has implications for high-throughput use.

The bar I'd suggest is still "load-bearing" — anything a future contributor might reasonably want to second-guess or revert. ADRs add ceremony, so trivial decisions don't belong here.

Prior art for shape comparison

Plenty of well-known OSS projects use ADRs in roughly this style if it's useful to skim formats:

Offer

Happy to send a PR seeding two or three of the above (probably the Mutex send serialization, public API allowlist, and nonWebMain source-set ones, since those are the ones most likely to trip a contributor) if you're open to extending the directory. Let me know if there's a preferred ordering or a different short-list you'd rather see first.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions