# decision-records/ - this repo's own decision log (zone 1)

The repository-standards project's own ADRs, flat in this folder. Clients never
receive copies - they adopt these decisions by reference from the living standard - always latest
(ADR-004); the shipped tree carries only the empty log skeleton
(`standard/docs/decision-records/`) for a client's own records.

Read the table instead of opening every record - the gist column says what each
one settled.

**Keep a record as short as the decision actually is.** Length is a cost, not a sign of
rigour: write the shortest thing that still answers *why* for someone who was not in the
room, and let a section with nothing to say be one line. Comprehensive means every question
is answered, not that each answer is long - a record nobody finishes reading fails at the
only job it has. Before writing one at all, check it earns the shape: a choice that is cheap
to reverse is a convention for `CONTRIBUTING.md` or a rule for `SPEC.md`, not a full
Context/Options/Consequences record.

| # | Title | Decides | Status |
|---|-------|---------|--------|
| [001](ADR-001-decision-record-policy.md) | Decision record policy | two streams (ADR technical / BDR business), MADR format, sub-scope via Tags never new acronyms, gapless numbering | Accepted |
| [002](ADR-002-specs-by-capability.md) | Specs by capability | specs live at `specs/<capability>/`, never per-ticket or per-page | Accepted |
| [003](ADR-003-specs-buildable-not-descriptive.md) | Specs are buildable | a spec must let an agent rebuild and verify the capability without the code; verbatim contracts, not prose | Accepted |
| [004](ADR-004-standard-decisions-by-reference.md) | Standard decisions by reference | consuming repos adopt the standard's decisions by link; deviations are local superseding records. **Revised by ADR-025**: references resolve at `main` - latest, not a pinned version | Accepted |
| [005](ADR-005-align-engine-is-a-manifest.md) | Align-engine is a manifest | what an aligned repo must have lives in `standard.manifest.json` (data), not prose/JS; self-verify reads it, drift is a number | Accepted |
| [006](ADR-006-personas-are-a-validation-gate.md) | Personas gate everything | every idea/spec/backlog item names the persona it serves or is parked; persona conflicts resolve by BDR | Accepted |
| [007](ADR-007-modernize-is-plan-then-refactor.md) | Modernize is plan-then-refactor | document the repo first, record each move, then refactor - never bump-and-fix | Accepted |
| [008](ADR-008-standard-repo-three-zones.md) | Zones in this repo | repo-own life vs the standard's source; zone mechanics revised by ADR-014, stacks clause by ADR-016 | Accepted, revised by 014/016 |
| [009](ADR-009-skills-lifecycle-vs-transition.md) | Transition skills never ship | lifecycle skills ship with the tree and stay; the transition router runs from this repo only | Accepted |
| [010](ADR-010-artifact-lifecycle-and-tracker.md) | One artifact lifecycle + tracker | ideas -> records/specs (living) -> plan/tasks (ephemeral, cleaned at close); statuses with the clarify gate; GitHub Issues default, Jira/Linear adapters | Accepted, revised by 028 |
| [011](ADR-011-one-standard-two-profiles.md) | Core vs scale profiles | one repo, two verified profiles - core keeps knowledge alive (every repo), scale coordinates people (teams); declared per manifest entry | Accepted, revised by 040 |
| [012](ADR-012-in-repo-instructions-are-the-source-of-truth.md) | In-repo instructions are the source of truth | repo rules live at their taxonomy homes; personal memory/config may point, never hold | Accepted |
| [013](ADR-013-spec-kit-is-an-engine-by-reference.md) | Spec Kit vendored as a pinned engine | superseded: the engine is extracted, not vendored | Superseded by 015 |
| [014](ADR-014-one-authored-tree.md) | One authored tree | `standard/` is the single committed, consumable tree at real-repo paths; no second source, no reflect; repo-own material lives outside it | Accepted |
| [015](ADR-015-spec-engine-extracted.md) | Spec engine extracted | five engine prompts become the standard's own `spec-*` skills + `scripts/spec/`; no `.specify/`, no speckit namespace; upstream improvements are cherry-picked | Accepted |
| [016](ADR-016-stacks-are-satellite-repos.md) | Stacks are satellite repos | one repo per technology, named for the technology in the `repository-standards` org, official only via the `stacks.json` registry; variation = profiles/adoption modes, never sibling repos; the stack points back at the registry (range clause revised by ADR-022), core never chases | Accepted |
| [017](ADR-017-consumed-versions-pinned-exact.md) | Consumed versions pinned exact | dependencies, overrides, images, runners and actions name exact versions or digests - nothing floats, upgrades are reviewed diffs; cooldown before adoption (R21) | Accepted |
| [018](ADR-018-history-lives-in-the-changelog.md) | History lives in the changelog | living documents carry no change-log sections; git + the changelog process are the only history; capability globs skip manifests/lockfiles (R4). **Revised 2026-08-02**: the `changes/` fragments mechanism removed - one path at every profile | Accepted |
| [019](ADR-019-lifecycle-procedures-are-agent-portable.md) | Lifecycle procedures are agent-portable | the procedures are normative (R22); `.claude/skills` is the reference form; a non-Claude repo ports them strictly to its agent's mechanism - a partial port is drift | Accepted |
| [020](ADR-020-intake-first-adoption.md) | Intake-first adoption | align opens with step 0 - measure, then one question round (intent, technology + Layer 2 consent, appetite, plan-only vs execute); per-direction gate order; assessment-only is a named outcome; plan items name an owner role | Accepted |
| [021](ADR-021-adoption-feeds-the-standard.md) | Adoption feeds the standard | align/update runs offer consent-gated upstream issues - stack requests on registry misses, friction reports on rough runs; templates give the signal one shape | Accepted |
| [022](ADR-022-stacks-linked-not-version-locked.md) | Stacks linked, not version-locked | a stack declares it belongs to the ecosystem (registry pointer), never a core version range; self-verify notes the layer, checks nothing version-shaped | Accepted |
| [023](ADR-023-method-docs-live-beside-the-tree.md) | Method docs live beside the tree | the method manual moves to `docs/method/`; the tree is literally the client repo at day zero; clients adopt the method by reference (manifest `references`), never as copies | Accepted |
| [024](ADR-024-discovery-dossiers-beside-the-specs.md) | Discovery dossiers beside the specs | `docs/discovery/<topic>/` holds provenance-stamped extracts, never normative; the `Last reconciled:` stamp ends re-asking; typed open markers let a spec draft early and gate honestly. **Narrowed by ADR-049**: the stamp bounds asking, not reading | Accepted, narrowed by 049 |
| [025](ADR-025-the-standard-is-living-latest-is-the-target.md) | The standard is living - latest is the only target | no version ranges or requirements anywhere, ever; every align/update targets latest; `.standards-version` is a bookmark of the last aligned state, never a constraint; references resolve at `main` deliberately | Accepted |
| [026](ADR-026-rebase-merge-onto-a-linear-main.md) | Rebase-merge onto a linear `main` | branches update by rebase and never back-merge; every PR is based on the mainline; a PR lands as one readable unit - rebase-merge on the paved road, squash where per-commit hygiene is not held (R23) | Accepted, narrowed by 035 |
| [027](ADR-027-the-database-schema-lives-in-the-repo-with-a-typed-twin.md) | The database schema lives in the repo, with a typed twin | executable DDL under `database/schema/` rebuilds the database from a checkout; a typed definition in the stack's idiom is what every access path goes through; the two are a declared 1:1 pair that moves in one PR (R24) | Accepted |
| [028](ADR-028-work-cycles-live-in-the-repo-and-bind-only-at-scale.md) | Work cycles live in the repo, and bind only at scale | a cycle is a goal-bearing, dated grouping of backlog intents at `docs/cycles/<team>/`; one intent is in the pool or in exactly one cycle, never both; `/cycle-close` writes one aggregate outcome because the grouping is not recoverable afterwards - narrowing ADR-010; scale only | Accepted, renamed by 041 |
| [029](ADR-029-measurement-forecasts-sizes-only-cold-start.md) | Measurement forecasts the work; sizes only cover the cold start | measured item duration is the forecast; optional `S`/`M`/`L` is a splitting trigger and a cold-start estimate below three closed cycles, never summed, never charted, and ignored entirely once measurement exists - no blended mode; an item that overruns its cycle is split, not re-sized | Accepted |
| [030](ADR-030-the-current-holder-is-cycle-state-not-history.md) | The current holder of an in-flight intent is cycle state, not history | `assignee` names who holds an intent **now**, on cycle rows only; the pool has none, reassignment overwrites, and the closed cycle is archived as written rather than aggregated - narrowing ADR-010 by tense, not replacing it | Accepted |
| [031](ADR-031-one-domain-surface-first-urls.md) | One domain, surface first in the URL | `/` and `/docs/` are the core's, `/node/` and `/docs/node/` a stack's; each repo knows only `site_root` and `base_path`, every internal link is root-absolute, and the ecosystem switcher derives "here" from its own base rather than being told | Accepted |
| [032](ADR-032-re-entry-is-core-tracker-sync-is-an-extension.md) | Re-entering a spec mid-development is core; tracker sync is an extension | going back to a spec while work is in flight is one of the loop's core assumptions and was unsupported: nothing downstream read the spec delta, and positional task ids collided with already-exported tracker items so new work was silently skipped. Re-entry detection lands in core for every adopter; identity and reconciliation move to an optional per-capability sidecar a repo without a tracker never sees | Accepted |
| [033](ADR-033-the-spec-loop-reads-the-decision-log-before-it-writes.md) | The spec loop reads the decision log before it writes | `/spec-specify` and `/spec-clarify` read the decision-record index before drafting or asking - bounded by the index, in full only where the subject overlaps. An Accepted record outranks the dossier, the draft and the user's answer in the moment; a contradiction stops the run, and the routes are change the request or supersede the record. Retirement is checked at the PO's entry point too, not only the developer's | Accepted |
| [034](ADR-034-embargoed-work-is-a-private-mirror-not-an-exemption.md) | Embargoed work is a private mirror, not an exemption | work whose publication is itself the harm (an unfixed vulnerability, a third party's material, an unannounced move) is held in a private mirror of the repo under every one of the standard's rules and rejoins the mainline when the embargo lifts; the embargo names its lifting condition and its owner at the start, and an unbounded one is the R3 violation it always was | Accepted |
| [035](ADR-035-maintained-release-lines-are-integration-targets.md) | A maintained release line is an integration target | a declared, protected, never-rewritten release branch is a legal PR base exactly as the mainline is, and every R23 requirement binds it identically; a multi-line fix lands on the mainline first and reaches each supported line as its own PR, with that line's own `## Unreleased` entry - narrowing R23's "based on the mainline" to what it was written for, another open PR's branch | Accepted |
| [036](ADR-036-a-retired-spec-is-frozen-against-extension-not-against-correction.md) | A retired spec is frozen against extension, not against correction | three shipped rules met a retired spec whose content a later change had falsified and each pointed a different way - stop, resolve, and never detect it at all - so the case had no legal path. `retired` freezes behaviour: the spec never gains behaviour, and it is corrected to say what it did whenever a change makes one of its sentences false, in that change's own pull request | Accepted |
| [037](ADR-037-a-repo-may-register-more-than-one-stack.md) | A repo may register more than one technology stack | a repo whose stacks coexist permanently carries `stack.<technology>.manifest.json` per stack beside the unchanged single-stack name; every one is read, the drift stays one number, an unparseable one is drift, and two stacks claiming one path is reported rather than collapsed | Accepted |
| [038](ADR-038-adopted-percentage-is-structural-substance-is-judgment.md) | The adopted percentage measures structure; substance stays the judgment tier | a `fill-from-repo` entry is content the adopter writes, so it can carry neither a hash nor required keys and scored on existence alone - six files reading `TODO.` moved a sparse repo from 21% to 37% adopted with its substance unchanged. Required sections and length thresholds were both rejected as converting substance into ceremony; instead the number says what it counts, the warning detects only "visibly nothing written", and the file list comes from the manifest rather than a hardcoded list | Accepted |
| [039](ADR-039-capabilities-whose-code-is-not-here.md) | A capability may be bound to a repository this one does not own | a capability whose implementation lives in a satellite repo, plugin or vendor SDK declares `{ external, reason }` in the capability map instead of a glob that matches nothing; nothing is enforced for it, the spec still lives here, and every audit run names it | Accepted |

| [040](ADR-040-the-scale-profile-binds-on-reach-not-headcount.md) | The scale profile binds on reach, not on headcount | the picker's "flip at the second regular contributor" made a pair the enterprise ADR-011 exists to spare, and the discount it advertised was not the one the manifest gives - CI is a core required entry, personas and architecture are core, and the tracker bridge and curated release notes are required at no profile. `scale` now binds on what leaves the room (async handoff, contributors outside the conversation, outside readers of execution state, a release audience, users nobody here is); the 2-5 range gets a recorded route - `scale` with exceptions, or `core` carrying what a condition triggered - never a third profile | Accepted |
| [041](ADR-041-the-bounded-period-of-work-is-called-a-sprint.md) | The bounded period of work is called a sprint | `cycle` was chosen against `sprint` to avoid importing the ceremony, and lost to use: readers stop at the unfamiliar word and ask whether it is a sprint. Renamed everywhere - `docs/sprints/`, `sprint-open`/`sprint-close`, `sprint-guard.mjs`, the `work-sprints` spec - with the borrowed word defined against what it usually carries: no points, no velocity as a commitment, an agreed date rather than a timebox, and no prescribed ceremony. Renames 028's vocabulary, not its substance | Accepted |
| [042](ADR-042-intake-is-a-required-artifact-not-a-performed-step.md) | Intake is a required artifact, not a performed step | Step 0 (ADR-020) measured and asked but left nothing checkable behind - an agent that ran it and one that guessed produced the same diff. New rule R26 and a required `docs/adoption-intake.md` manifest entry give it the same standing PRODUCT/personas already have: never deferred, and `self-verify` now reports a skipped intake instead of missing it entirely | Accepted |
| [043](ADR-043-an-existing-decision-process-gets-an-exception-not-a-second-home.md) | An existing decision process gets an exception, not a second home | Step 0 proposed `docs/decision-records/` for git and vim alike, though both already run a working decision process (a mailing list, a maintainer-led process) older than this standard. Step 0 now detects the signal and asks instead of assuming: adopt this standard's ADR/BDR mechanism, or keep the repo's own process, recorded as a named `exceptions` entry against R5's manifest requirement - reusing the mechanism, no new rule | Accepted |
| [044](ADR-044-r18-splits-by-publishable-unit-not-by-team.md) | R18 splits by publishable unit, not by team | `rails/rails`'s thirteen independently-versioned gems, each with its own changelog on one branch, is not a release-line problem (R23) - it is a different axis. The proposed reuse of the per-team sprint mechanism (ADR-028/041) was checked and does not fit: sprints split work in time, by team, scale-profile only; this is code structure, at every profile, present even for a solo two-package repo. R18 gets a second, independent clause instead - one changelog per unit, same one-mechanism rule, no new tooling | Accepted |
| [045](ADR-045-record-run-feeds-the-existing-corpus-consent-gated.md) | `record-run` feeds the existing corpus, consent-gated | the human-prompting corpus's own weakest point - every prompt written by people who already know the product - had no inbound channel from a real session. The new 21st shipped skill assembles the run that just happened into the existing `prompts.md`/`runs/*.json` shape, offers two consent levels (prompts only, or the full run), and sends nothing without a per-item yes, mirroring ADR-021's pattern for a second upstream channel | Accepted |
| [046](ADR-046-backlog-is-the-one-index-open-questions-and-ideas-get-a-type.md) | `backlog.md` is the one index; open questions and ideas get a `type` | Three separate index files meant the dashboard's Backlog tab could see build work but not standing doubts or unapproved features. One table now, distinguished by a `type` column (`task`/`bug`/`open-question`/`idea`), each with its own status vocabulary; decision records stay a separate stream since a record is a fork already taken and these rows are not; full deliberation stays in the per-topic file, the backlog row is only the index entry | Accepted |
| [047](ADR-047-adoption-ping-is-informed-not-asked-and-minimal.md) | The adoption ping is informed, not asked, and minimal | `align-to-standards` sends one anonymous ping per completed run (stack, standard version, drift, fully-aligned, day) to a Cloudflare Worker, disclosed in its output rather than gated behind a yes/no (voluntary prompts don't get answered); no repo name, no IP, no cross-ping identifier; opt-out via `REPOSTDS_NO_TELEMETRY=1`; v1 endpoint is the account's free `workers.dev` address, a custom subdomain deferred after Cloudflare's self-serve flow refused a bare subdomain | Accepted |
| [048](ADR-048-gate-artifacts-are-read-for-shape-not-presence.md) | Gate artifacts are read for shape, not presence | ADR-042 made Gate 0's intake a required entry because a run that skipped it left no trace; Gates 2 and 5 had the same hole and a real adoption fell through it, reaching drift 0 having produced neither the health report nor the count the human decides on. Adds R27, the `docs/adoption-assessment.md` entry, and an `adoption-gates` guard reading shape and arithmetic - eight passes rated, the scope block summing to its own total, an owner role per item; the scope block also moves into the backlog template, where the adopter can actually see it, and Step 0's "plan-only or execute" becomes an intent whose consent is re-asked after Gate 2 | Accepted |
| [049](ADR-049-discovery-entries-are-typed-and-the-stamp-bounds-asking.md) | Discovery entries are typed; the stamp bounds asking | An entry recorded that a meeting happened but not what kind it was, why it was called, what came of it, or what else it touched - and ADR-024's `Last reconciled:` stamp, whose job is to stop a question being asked twice, was implemented by every consumer as a bound on *reading* too, hiding the one thing a dossier holds that no record or spec ever will: the explanation. Adds a typed entry header (`Kind` from a closed vocabulary, `Purpose`, `Touches`, per-entry `Outcome`, `## Explained here`), mirrors it in the dossier table, and narrows rule 4 so research reads the whole dossier and cites it instead of re-deriving it. A generated index was considered and rejected as a second description of the same data | Accepted |
| [050](ADR-050-a-decision-record-must-name-what-would-reopen-it.md) | A decision record must name what would reopen it | `discovery-digest` step 4 greps every record's `Revisit when` to catch a decision sitting past its own trigger, and claimed to read all of them - 25 of 48 carried the field, and the 23 that did not included every record from 040 to 048. The field becomes required and `decision-records-check` fails without it, reading the section for shape (missing, empty, or still carrying the template's prompt all count as no signal); superseded and rejected records are exempt; an honest "nothing reopens this short of X" is a legal answer and an invented threshold is not; the 23 are backfilled from what each record already stated | Accepted |
| [051](ADR-051-closing-a-backlog-row-is-a-relocation-not-a-deletion.md) | Closing a backlog row is a relocation, not a deletion | the standard said when a row may close and left where it goes to an aside - "drop `done` rows on release, or let the Backlog.md tool archive them" - naming no destination, no rule and a third-party tool this project has never run. Deleting destroys findings that exist nowhere else, so adopters do neither: this repo's own pool holds finished, measured work under `todo` because closing it means throwing it away, and its 1.1.0 cut deleted seventeen rows, leaving two epics as a heading with no rows. A row now closes only once its content has a home - record, spec or dossier, plus the CHANGELOG for what shipped - and then moves to `docs/backlog-archive.md` carrying a `where` pointer; `backlog-archive-check` fails a row removed from the pool without reaching the archive, an empty `where` and a `where` that resolves to nothing, which makes "a row that cannot be relocated was not done" a diagnostic rather than an aspiration | Accepted, revised by 053 |
| [052](ADR-052-alignment-tracks-a-provenance-commit-not-a-version-string.md) | Alignment tracks a provenance commit, not a version string | a version string can no longer name one exact tree now that PRs bump PATCH by default, so `update-to-version` (renamed `update-to-latest`) stops deriving its delta from `.standards-version` and instead reads/writes a `provenanceCommit` field carrying the standards repo's own SHA; separately, the manifest gains a hand-maintained `removedPaths` list and `self-verify` gains a check that fails a repo still carrying a path the standard has removed, waivable only through the existing `exceptions` mechanism | Accepted |
| [053](ADR-053-the-backlog-view-does-not-carry-the-archive.md) | The backlog view does not carry the archive | ADR-051 made "closed rows stay reachable in the view" binding and named the "show finished" chip, which 1.1.13 removed - leaving a requirement with no surface, blocking the first archive cut behind a design nobody needed. Measured rather than argued: the generator reads no archive at all, and Timeline, the first candidate, reads the sprint projection and would have needed a second unrelated input. The clause is narrowed to nothing - no tab, no control, at either profile - because "not hidden" was written against masking closed rows inside the pool view, and a file with its own name is not a mask; ADR-051's clauses, guard and `where` pointer are untouched | Accepted |

Add one row per record; the template ships in the tree
(`standard/docs/decision-records/adr/_template.md`). Numbers are gapless and never
reused.
