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 | Decision record policy | two streams (ADR technical / BDR business), MADR format, sub-scope via Tags never new acronyms, gapless numbering | Accepted |
| 002 | Specs by capability | specs live at specs/<capability>/, never per-ticket or per-page | Accepted |
| 003 | Specs are buildable | a spec must let an agent rebuild and verify the capability without the code; verbatim contracts, not prose | Accepted |
| 004 | 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 | 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 | Personas gate everything | every idea/spec/backlog item names the persona it serves or is parked; persona conflicts resolve by BDR | Accepted |
| 007 | Modernize is plan-then-refactor | document the repo first, record each move, then refactor - never bump-and-fix | Accepted |
| 008 | 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 | Transition skills never ship | lifecycle skills ship with the tree and stay; the transition router runs from this repo only | Accepted |
| 010 | 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 | 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 | In-repo instructions are the source of truth | repo rules live at their taxonomy homes; personal memory/config may point, never hold | Accepted |
| 013 | Spec Kit vendored as a pinned engine | superseded: the engine is extracted, not vendored | Superseded by 015 |
| 014 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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.
