Maintainability
This is the single entry point for contributors. It gathers the habits that keep Wanderer auditable without adding tooling ceremony. If you are about to open a pull request, skim this page first.
CHANGELOG discipline
Every merged change updates CHANGELOG.md
under ## [Unreleased]. Use the Keep-a-Changelog sections
(Added, Changed, Deprecated, Removed, Fixed, Security)
and prefer short, imperative entries that reference the OpenSpec
change they came from. A breaking change to pkg/* goes under
### Changed (breaking) and SHALL also cite an ADR.
Housekeeping fixes (typos, lint) still get a one-line ### Fixed
entry. It is cheap and it keeps the log complete.
ADR discipline
Decisions that constrain future work live in
docs/decisions/ as Architecture Decision
Records. Write one when a change adds a cross-cutting dependency,
introduces a new data-model contract, moves the passive/active
boundary, or declares the stability class of a new public package.
Do not write one for tactical fixes.
ADRs are additive: do not delete old ones, supersede them with a
new entry and update the Status field on the old one.
OpenSpec discipline
Non-trivial changes — new command, new probe, new data type, any
change to pkg/models — start as an OpenSpec change proposal
under openspec/changes/<name>/. Use the
/opsx:propose and /opsx:apply skills (or the equivalent
openspec-* skills) to drive them. Rationale and details are in
ADR-0001.
Small, behaviour-preserving fixes go straight to a pull request with just a CHANGELOG entry.
API stability
Two classes, fully described in ADR-0002:
pkg/— stable public contract. Breaking changes require a### Changed (breaking)CHANGELOG entry and an ADR.internal/— private. Reshape freely. External imports are unsupported.
Default location for new types is internal/. Promote to pkg/
only when an external consumer needs it.
Testing baseline
Every new Go package ships with at least one _test.go file and a
package-level doc comment of two to four sentences describing
intent. Coverage targets:
internal/*— ≥ 70% line coverage.pkg/models— ≥ 90% line coverage.
Table-driven tests are the default style. Mocks are acceptable at
package boundaries; integration tests in internal/api and
internal/store should exercise real HTTP handlers and the real
SQLite backend respectively, not reimplement them.
Documentation baseline
Every new Go package has a // Package <name> … doc comment.
Every user-facing feature has a matching section or file under
docs/. If a flag, environment variable, or HTTP
route is added, it appears in docs/operator.md.
Dependency policy
Policy summary (full rationale in ADR-0003):
- Prefer the standard library.
- Prefer pure-Go dependencies; CGo needs an ADR.
- Pin versions in
go.mod; commitgo.sum; no automated bumps. - Each new top-level dependency gets a one-line justification in the introducing proposal or design document.
Commit and pull-request style
- Subject line: short imperative, ≤ 72 characters, prefixed with a
conventional type (
feat:,fix:,chore:,docs:,refactor:,test:). Scope is optional. - Body: wrap at 72 columns. Explain the why, not the what — the diff already shows what.
- Trailers:
Co-Authored-By: …when pair-coded or agent-assisted. No ticket IDs required; OpenSpec is the tracker. - One logical change per commit where practical. Squash-merging is fine when a branch has noisy intermediate commits.
What is deliberately not here
No commit-message hooks, no CHANGELOG-enforcement CI, no PR template, no labelling bot, no Dependabot. These are good at scale; at this project's current size they trade real friction for speculative quality. Revisit once concrete drift shows up.