How pbr-cpp-memory-pool is governed in the maintained-product phase (post-v1.0.0): how to decide a release's SemVer level, how a fix reaches users, how security issues and deprecations are handled. This is the governance layer; the mechanical step-by-step for cutting any release lives in release.md, the decision is recorded in ADR-0034, and the versioning policy it builds on is ADR-0004. The agent-vs-human boundary (and the tag delegation) is AGENTS.md §11 + ADR-0008.
Post-1.0.0 the project is strict SemVer 2.0.0. The "public API" that the version number protects is, precisely:
- the C ABI — the four spec §5 functions and the always-present introspection accessors in
memory_pool.h; - the C++ surface —
Pool,TypedPool<T>,PoolAllocator<T>,InstrumentedPool,PoolObserver, and the diagnostic iterator, in the public headers.
The compile-time knobs (PBR_MEMORY_POOL_THREAD_SAFETY, PBR_MEMORY_POOL_DIAGNOSTICS, PBR_MEMORY_POOL_ENABLE_DIAGNOSTICS) and the CMake package name / imported target (pbr::memory_pool) are part of the contract too — renaming or repurposing them is a breaking change.
| Level | Meaning here | Examples |
|---|---|---|
MAJOR (2.0.0) |
A source- or binary-incompatible change to the surface above. | Remove/rename a function, change a signature or documented semantics, change the metadata budget in a consumer-visible way, rename the imported target. |
MINOR (1.x.0) |
Backward-compatible additions. Existing code keeps compiling and behaving. | A new public function/type/overload, a new opt-in option, a new milestone's additive feature set, a deprecation (the symbol still works). |
PATCH (1.0.x) |
Backward-compatible bug fixes and changes with no public-API change. | A logic fix, a docs/i18n change, a packaging change, a perf improvement, a build-system fix. The shipped library may be byte-identical (e.g. v1.0.1 — packaging only). |
Ask, in order:
- Does the change remove, rename, or alter the signature/semantics of any public symbol, knob, or the imported target — such that existing consumer code would fail to compile or link, or behave differently? → MAJOR. Requires its own ADR (justifying the break) and a migration note in the release notes. Prefer the deprecation path (below) over an abrupt break.
- Does it add new public surface, a new opt-in capability, or a milestone's worth of additive work — while every existing use keeps working?
→ MINOR. (Closing a roadmap milestone is the canonical MINOR — e.g. Milestone 8 →
v1.1.0.) A genuinely new capability is planned on the roadmap first — usually as a new milestone (Milestone 9,10, …), perAGENTS.md§7.3 and ADR-0037. - Otherwise — a bug fix, docs/i18n, packaging, perf, or CI change with no public-API change. → PATCH.
When a change is ambiguous (e.g. a "fix" that subtly changes documented behaviour), treat it as the higher level — a wrongly-low version number is the costly mistake (it breaks consumers who trusted SemVer). Record the call in the release notes.
The mechanics are identical to a milestone close (release.md §1–§8); only which component of version.hpp moves differs:
- PATCH
1.0.x— bumpPATCHonly; update thepool_smokeversion-checkTEST_CASE. Roll the relevantUnreleasedlines into## [1.0.x] — <date>. Adddocs/releases/v1.0.x.md. Refresh the README status badge. (v1.0.1, the packaging patch, is the worked example.) - MINOR
1.x.0— bumpMINOR, resetPATCHto0. Same changelog roll + release notes; also refresh the README milestone table (a MINOR usually closes a milestone). - MAJOR
x.0.0— bumpMAJOR, resetMINOR/PATCHto0. Same mechanics, plus the breaking-change ADR and a migration section indocs/releases/vx.0.0.md.
In all cases the agent prepares the release PR; the maintainer merges; the agent tags; the maintainer publishes (AGENTS.md §11, ADR-0008).
Defects are tracked in the in-repo bug ledger under docs/bugs/ — one Markdown file per defect, BUG-NNNN-<slug>.md under a discovery-date tree, the ledger being the source of truth (ADR-0039). The ledger and this protocol meet at the point a defect is fixed:
- Record — a verified defect (found internally) or a confirmed third-party report becomes a
confirmedledger file. An unsubstantiated report is recorded ascannot-reproduce/rejected/duplicate. The agent rule isAGENTS.md§7.7. - Assess the SemVer level of the fix by the decision tree above (a logic fix is usually a PATCH; a fix that must change documented behaviour is MINOR/MAJOR).
- Fix through the hotfix/backport flow below. In the same PR, flip the record to
status: fixed, setfixed-in: vX.Y.Z, link the fixing PR, and add theCHANGELOGline underFixed(orSecurityfor a vulnerability). The ledger record and theCHANGELOGline cross-reference each other — keep them in lockstep. - Security defects follow the embargoed flow below, not the public ledger, until the advisory is published; the record is then added (or de-embargoed) with the advisory / CVE reference.
The bugs consistency check (below) guards the record's structure and the fixed↔fixed-in link.
Two cases, decided by whether master is currently releasable:
masteris releasable (the common case —masteris the release line). Fix on a normalfix/<name>branch offmaster, add a test and aFixedCHANGELOGline, merge, then cut the next PATCH frommaster(release.md— Hotfix flow). No separate branch is needed.masterhas unreleased changes that cannot ship yet (e.g. work-in-progress toward the next MINOR/MAJOR). Branchhotfix/v<X.Y.Z+1>from the released tag (notmaster), apply the minimal fix + test there, cut the PATCH from that branch, then forward-port the fix tomaster(cherry-pick) so it is not lost on the next release. The forward-port is mandatory and is part of the same hotfix task.
A hotfix is always the smallest change that fixes the defect — no refactors, no unrelated improvements ride along.
- Report privately, never in a public issue/PR: via GitHub private vulnerability reporting on the repository (Security tab → Report a vulnerability). The public-facing policy — supported versions, what to include, what to expect — is
SECURITY.md. - Triage & fix under embargo on a private branch / draft advisory; assess the SemVer level by the decision tree (a fix is usually a PATCH, but a fix that must change public behaviour is MINOR/MAJOR).
- Coordinated release: cut the release, then publish the advisory. Record the fix in
CHANGELOG.mdunder aSecuritycategory (Keep a Changelog) with the advisory / CVE reference. - Backport to every still-supported release line per the hotfix workflow.
The public API is not removed abruptly. To retire or change a public symbol:
- Deprecate in a MINOR. Mark the symbol deprecated in its Doxygen (
@deprecated) and add aDeprecatedCHANGELOGline; the symbol keeps working unchanged. Record the intent (and the eventual replacement) in an ADR. - Honour a deprecation window — the symbol remains for at least the rest of the current MAJOR line (≥ one subsequent MINOR), giving consumers time to migrate.
- Remove in the next MAJOR, with the breaking-change ADR (decision-tree step 1) and a migration note.
A deprecation is itself a backward-compatible change (the symbol still works), so it ships in a MINOR.
Run python tools/consistency_lint.py before drafting any post-1.0 PR (AGENTS.md §6.4; the PR template carries the checkbox; CI re-runs it via the consistency job — ADR-0035). Each failure prints [check] message; fix it as follows:
| Failing check | What it means | Remediation |
|---|---|---|
version-lockstep |
version.hpp, the newest dated CHANGELOG block, the README Status-vX.Y.Z badge, and the newest docs/releases/vX.Y.Z.md disagree. |
Move all four together per the per-level mechanics above (and release.md). Outside a release PR, they should already equal the last released version. |
adr-index |
An ADR file is missing from docs/adr/README.md (or vice-versa), or numbering has a gap. |
Add the index row for the new NNNN-*.md (ADRs are appended with the next sequential number — never reuse/renumber). |
patterns |
An Adopted catalogue row cites an ADR or a src/main/cpp/ path that does not exist. |
Fix the moved/renamed path or add the missing ADR link in docs/patterns/README.md. |
spec-map |
A Spec Coverage Map row has an empty Roadmap items cell or no status glyph. | Give the spec row at least one fulfilling roadmap item and a legend glyph (⏳/🚧/✅/❎). |
i18n-freshness |
A translated page's English source changed after the source commit recorded in the manifest. |
Re-sync the affected docs/i18n/<lang>/… page to the new source, then update that manifest row's source commit (or, if the source change does not affect the prose, re-pin the commit after reviewing). |
milestones |
The README marks a milestone ✅ while a ROADMAP item in it is unchecked, or a checkbox is malformed. | Check the remaining ROADMAP item(s), or correct the README table; fix any - [ ]/- [x] typo. |
bugs |
A docs/bugs/ record has bad frontmatter (missing key, unknown status/severity/reporter), its filename/path disagrees with its id/discovered, ids are non-unique or gapped, the index ↔ files bijection is broken, or a fixed record has no fixed-in. |
Fix the record per docs/bugs/README.md: match the filename to BUG-NNNN, file it under <discovered-year>/<month>/, use the next free id, add/repair the index row, and set fixed-in once status: fixed. |
- The agent-vs-human release boundary and tag delegation are unchanged (AGENTS.md §11, ADR-0008).
- The one-PR-at-a-time rule and the documentation-ships-with-code rule still apply to every fix.
- The mechanical release steps still live in
release.md; this document only adds the which-level / how-a-fix-flows / deprecation / security governance on top.
- ADR-0034 — the decision this document operationalizes.
- ADR-0004 — the versioning & release policy.
- ADR-0008 — tag creation/push delegated to the agent.
release.md— the mechanical step-by-step for cutting a release.AGENTS.md§11 — versioning & release, agent-vs-human boundary.- Semantic Versioning 2.0.0 · Keep a Changelog 1.1.0.