0003. Dependency policy
- Status: accepted
- Date: 2026-04-24
Context
Every added dependency is a perpetual cost: transitive CVE exposure, cross-compilation friction when C code sneaks in, version drift, and one more thing to audit when the output of Wanderer is itself used as evidence. A small greenfield project can avoid those costs cheaply if the policy is explicit from the start; retrofitting a policy after dozens of dependencies have landed is never effective.
The MVP already made one deliberate, non-obvious choice:
modernc.org/sqlite (pure Go) instead of mattn/go-sqlite3 (CGo).
That choice keeps go build ./... trivial on every supported
platform without a C tool-chain. Policy-wise, it should be the
default expectation, not an exception.
Decision
-
Prefer the standard library. If the standard library covers a need adequately, do not add a dependency even if a third-party package is "nicer".
-
Pure-Go over CGo. New dependencies SHALL be pure Go unless a strong justification is captured in the proposing change's
design.mdand an accompanying ADR. The carrying cost of losingGOOS=linux GOARCH=arm64 go build ./...without a cross tool-chain is higher than most ergonomic wins. -
Pinning. Versions SHALL be pinned in
go.mod(Go does this by default).go.sumis committed. No auto-upgrade bots are configured by policy — the cost of a spurious update is higher than the cost of a deliberate periodic review. -
Minimum supported Go. Documented in
go.modand kept in lockstep with the CI matrix. Current target: the latest stable Go release. Bumping the minimum is a CHANGELOG entry and does not require an ADR. -
Rationale on introduction. Every new top-level dependency gets a one-line justification in the proposing change's
proposal.mdordesign.md. For decisions that constrain future changes (e.g. "we are now committed to chi for routing"), write a dedicated ADR. -
No vendoring. The module cache is the source of truth. Vendoring is only revisited if a regulatory requirement forces it.
Consequences
go build ./...stays trivial and reproducible on every platform the project targets.- Adding a dependency is a small, visible friction: it needs a sentence somewhere. That friction is the point.
- If a future change genuinely needs a CGo dependency (e.g. a protocol library with no pure-Go alternative), the policy is overridable by explicit ADR — it is not a hard no.
- Dependency review is a periodic human task, not a CI gate: we accept the risk of a short lag behind upstream security releases in exchange for not chasing bot-generated churn.