Feature Specifications¶
A specification is the decision record a change cites. For a library consumed by other modules and by real services, the expensive mistakes are design mistakes — a public API shape that cannot be changed cheaply, or a dependency that lands in every downstream binary. A spec is where those get caught, before there is code to defend.
Specs are drafted collaboratively with an AI assistant and reviewed by a human before any implementation begins.
When a spec is required¶
| Change | Spec? |
|---|---|
| A new package | Yes |
| Any public API addition or change | Yes |
| A new dependency | Yes — this is the one that gets waved through, and shouldn't |
| A change to the OTel version floor | Yes — it is a cross-repo change |
A new configuration or resolution rule in otelcore |
Yes |
| Bug fix with no public API change | No |
| Documentation correction | No |
| Internal refactor, public API untouched | No |
| Dependency bump within the existing pins (Renovate) | No |
Where they live¶
The specs live in the project wiki, as
specs/NNNN-<feature-name>, numbered in creation order. They are point-in-time decision
records rather than living documentation, and keeping them in docs/ buries the
documentation that is living.
This page stays in the repo because it is process documentation — the format and lifecycle a spec must follow — not a decision record itself.
| # | Spec | Status |
|---|---|---|
| 0001 | RED/USE instrumentation helpers | DRAFT |
Pre-extraction specs¶
This module was extracted from go-tool-base; specs written before the extraction settled stayed there, including observability module extraction and the telemetry analytics/observability split.
Lifecycle¶
| Status | Meaning |
|---|---|
DRAFT |
Written, not yet reviewed. Do not implement. |
IN REVIEW |
Under human review. Do not implement. |
APPROVED |
Reviewed and accepted. Implementation may begin. |
IN PROGRESS |
Implementation underway. |
IMPLEMENTED |
Shipped. |
SUPERSEDED |
Replaced by a later spec — link to it. |
Status appears in both the frontmatter and the document header, and both are updated together.
A spec and its implementation share a branch and a merge request, so the rationale lands next to
the code in git history. A spec-only merge request is prefixed [SPEC].
Format¶
Frontmatter¶
---
title: "<Feature name> for go/observability"
description: "<A dense paragraph: what this builds, what it deliberately does not, and why.>"
date: YYYY-MM-DD
status: DRAFT
tags:
- specification
- observability
author:
- name: <Human author>
email: <email>
- name: <AI assistant, if one drafted it>
role: AI drafting assistant
---
Crediting an AI drafting assistant in a spec's author block is correct and expected — a spec is a
design record, and knowing how it was produced is part of reading it well. This is the one place AI
attribution belongs: it must never appear in commit messages, merge request descriptions, or merge
request comments, where the human who approves the change owns it entirely.
Document header¶
Below the # title, using Material definition-list syntax:
Authors
: <names>
Date
: YYYY-MM-DD
Status
: DRAFT (YYYY-MM-DD). <What it is waiting on.>
Related
: <Other specs, upstream issues, or external references this builds on.>
Required sections¶
- Context & goal — the problem, and what currently forces the caller to solve it themselves.
- What NOT to build — for this module especially, scope is defined as much by exclusion as inclusion. The OTel ecosystem already covers a great deal (runtime instrumentation, otelhttp and otelgrpc request metrics, SDK-native exemplars, resource attributes); reimplementing any of it is a defect. Name what you are deliberately leaving to upstream.
- Invariant check — argue the design against the three invariants in the
contributor guide, explicitly:
- Framework-free — does this add a dependency? Justify it against
depfootprint_test.goand say whether the forbidden list needs extending. - Typed values in, providers out — does this pull config sourcing, environment scanning, or file parsing into the module? It must not.
- Signal independence — does this make a trace-only service link the log or metric exporter? It must not.
- Framework-free — does this add a dependency? Justify it against
- Public API — exact signatures, types, and their contracts. Prefer functional options on the
existing
NewProvidersignatures so adoption is not a breaking change; where a break is warranted, state what it costs go-tool-base as the primary consumer. - Data models — types, defaults, and resolution rules.
- Error cases — what fails, what it wraps, and what the caller can do about it.
- Testing strategy — TDD front and centre: which contracts become failing tests first, which
failure paths get
exporter_error_test.gocoverage, and whether integration tests against a real collector are needed (with the environment-variable gate they use). If the feature needs mockery, testcontainers, or godog, resolve the structural questions here rather than in the test file — see the contributor guide. - Documentation plan — a hard requirement, not a follow-up. Name the pages to add or update and
the Diátaxis quadrant each belongs to. All four quadrants are in-repo: a public API addition
needs a
docs/reference/page covering its keys, options, defaults and failure modes as well as doc comments, and a tutorial belongs indocs/tutorials/rather than only as a blog post. Note any page being moved or renamed, and thedocs/_redirectsentry that keeps its old URL alive. Specs written before 2026-08 state the opposite on both counts — see the contributor guide for what changed. - Implementation phases — a prioritised breakdown, each phase independently testable.
- Open questions — every unresolved design decision, gap, and ambiguity. These must be answered or explicitly deferred before implementation starts, not discovered mid-build.
Implementing an approved spec¶
Implementation is test-driven, phase by phase: write the failing tests for a phase from its
contracts and error cases, implement the minimum code to pass them, refactor with the suite green,
then run just test-race and just lint-fix before moving on.
Before marking a spec IMPLEMENTED:
just cipasses — tests, race detector, and lint, including thedepfootprint_test.goguard.- New code has at least 90% coverage.
- No
//nolintwas added to bypass an issue. - Every exported symbol has a doc comment; pkg.go.dev is this module's API reference.
- The documentation named in the spec's documentation plan has landed.
- Any public API break is noted in the commit body with the downstream impact.
Specs¶
- RED/USE instrumentation helpers —
DRAFT. OpenTelemetry parity with the Prometheus RED/USE helpers ingo/transport-metrics.