Skill: decide-adr
The post-hoc / asynchronous ADR path (pipeline stage 8a). design spawns ADRs synchronously and Accepted while you walk it Socratically; decide-adr records a decision that missed that pass — already in code, agreed in a chat, sketched on a whiteboard, or flagged by a tasks/review gate as a contract with no ADR behind it. It can also run a Proposed → Accepted review flow when the decision still needs a reviewer's sign-off. One file = one decision; it reuses design's MADR template, so there is no second ADR format here.
It is a recording utility, not a Socratic design stage — it does not run the shared Socratic loop or critic. The two shared dependencies are question phrasing and the worthiness gate:
→ ../_shared/ask-style.md · ../design/references/blast-radius.md
ADR prose (context / drivers / consequences) follows artifact_language — the MADR headings and Status: values (Proposed / Accepted / …) stay English → ../_shared/artifact-language.md.
Owner
Decision author (usually the Architect or Tech Lead). A reviewer (Tech Lead, plus Security when relevant) signs off the Proposed → Accepted transition.
Inputs
<slug>— the feature slug, same as every earlier stage.<title>— kebab-case, describes the decision, not the problem (time-sortable-ids, notid-strategy).- The decision itself + its alternatives — pulled from
sad.md§4 Solution strategy / §9 ADR index / §11 Risks, or supplied by the user. - Input gate (soft). Expects
docs/features/<slug>/to exist, ideally withsad.md(decide-adr reads its §4/§9/§11 for context and drivers). If the decision is genuinely standalone — no feature folder yet — allow it, but note the missing design context in the ADR's Context section and warn the user, rather than refusing.
Protocol
- Locate the feature.
test -d docs/features/<slug>. Missing → ask whether to proceed standalone (AskUserQuestion, phrasing per../_shared/ask-style.md). On «yes», createdocs/features/<slug>/adr/and flag that design context is absent.sad.mdpresent → read its §4 (strategy), §9 (existing ADR index), §11 (risks); absent → note it and source context from the user. - Worthiness check. Score the decision against the blast-radius gate —
../design/references/blast-radius.md(irreversible / multi-module / has legitimate alternatives). 2-of-3 → proceed. Below the bar → tell the user it's likely inline-in-sad.mdmaterial, not an ADR, and confirm before writing one anyway. - Dedup.
ls docs/features/<slug>/adr/*.md 2>/dev/null. An Accepted ADR on the same topic exists → don't duplicate: propose either editing it or a new ADR that marks the old oneSuperseded by NNNN(and stamps the old one'sstatus+updated_at). - Pick the number.
NNNN= (count of existingadr/*.md) + 1, zero-padded to 4 digits (0001,0002, …). Never reuse a number. - Copy the template. Copy
../design/templates/adr.md→docs/features/<slug>/adr/NNNN-<title>.md. This is the canonical MADR shape, owned bydesignand referenced here — do not invent a variant. Patch frontmatter:owner,updated_at: <today>,feature_size(from.sizeif present),ticket. - Context. 2–4 sentences: what forced this decision (an NFR, an incident, a constraint), and — if
sad.mdis absent — an explicit note that there is no design document, so the context is reconstructed from the author. - Decision drivers. Bullets — the quality goals / constraints that pushed the choice, each traceable to a real source (spec §6 NFR, sad.md §2 Constraints, a §1 top-3 quality goal). Don't invent drivers; they filter out pet decisions.
- Considered options. List all serious options (≥2 — one option is a declaration, not a decision), one line each with its trade-off. No strawman (an option an existing constraint already rules out).
- Decision outcome. «Chosen: » + 1–2 sentences on why it won, citing the drivers above.
- Consequences. Positive and Negative and Neutral — cons included, or it's rationalisation, not a record. Name what changes in the codebase, ops, monitoring, onboarding.
<!-- TBD -->only where a number honestly needs a spike. - Status.
Proposedwhile a reviewer still has to sign off;Acceptedonce final. Run the review flow when needed: writeProposed, fillreviewers, and on sign-off flip toAcceptedand bumpupdated_at. A reader six months on must be able to tell a live plan from a settled fact. - Close the loop. Add a row to
sad.md§9 ADR index (and link fromtasks/_epic.mdif the ADR scopes a specific task). The ADR's own## Linksmust point up to the spec + the relevantsad.md§N — no orphans. - Structural self-check — per
../_shared/self-check.md: re-read the written ADR from disk and verify 6 items: (1)NNNN= prioradr/*.mdcount + 1 and is unique in the folder; (2) ≥2 options under Considered options; (3) Consequences carries at least one Negative; (4)status∈ {Proposed, Accepted}; (5) a row for this ADR exists insad.md§9 (whensad.mdexists); (6)## Linksis non-empty. Fix + re-check ≤2 cycles; surface anything unresolved. - Propose commit + handoff.
adr: <slug> NNNN <title>. Then emit the stage-handoff block per../_shared/handoff.md(utility variant) — What I did (incl. «self-check: 6/6 pass») + Review (adr/NNNN-<title>.md) + Run next: resume the gate that needed it (/sdd:tasks <slug>or/sdd:plan-tests <slug>);/clearoptional.
Definition of Done
docs/features/<slug>/adr/NNNN-<title>.mdexists in design's MADR format (frontmatter + Context + Decision drivers + Considered options + Decision outcome + Consequences + Links).NNNNis correct (existing count + 1, 4-digit) and the title is in decision-form (0007-time-sortable-ids.md✓ vs0007-id-strategy.md✗).statusis explicit —Accepted(final) orProposed(reviewer pending,reviewersfilled).- ≥2 considered options, no strawman; Consequences carry real Negatives, not only Positives.
- Linked both ways: a row in
sad.md§9 (whensad.mdexists) and the ADR's## Linkspoint up to spec + sad §N. A genuinely standalone ADR notes the missing design context instead. - Dedup ran; a same-topic prior decision is
Superseded by NNNN, never silently duplicated.
Anti-patterns
- Using this for a live decision. A choice made now with the user belongs in
design(spawned inline,Accepted);decide-adris for what missed that pass. - ADR without options. «We chose X» with no alternatives is a declaration. List ≥2 serious options; no strawman.
- ADR as a changelog. «Tried it, didn't work» is a news feed, not a decision record.
- ADR as a spec. Acceptance criteria / NFRs don't live here — an ADR is trade-off and reasoning. That detail is in
spec.md/data-model/api. - No status. A reader six months on can't tell a current plan from an old decision.
- Problem-form title (
0007-id-strategy.md) — in the §9 index it's unclear which decision exists. Use the decision (0007-time-sortable-ids.md). - All-positive consequences — an honest ADR names its Negatives and Neutrals too.
- Reinventing the template. Reuse
../design/templates/adr.md; a second ADR format fragments the genre. - Orphan ADR. Written but not in §9 and with no
## Linksup to spec/sad — six-month archaeology can't find it.
References & template
../design/templates/adr.md— the canonical MADR scaffold this skill copies and fills (owned bydesign; do not duplicate it here).../design/references/blast-radius.md— the 3-criteria worthiness gate (irreversible / multi-module / legitimate alternatives); same gatedesignruns, applied here to confirm the decision earns an ADR.../_shared/ask-style.md— phrasing for the standalone-confirm, worthiness-borderline, and Superseded questions.
Example invocation
User: «ADR for time-sortable-ids on checkout-discounts —
tasksflagged a missing ADR for the id-generation choice» Skill:docs/features/checkout-discounts/exists withsad.md→ reads §4/§9/§11. Blast-radius: id strategy is irreversible (a switch later needs a backfill across every row) + multi-module (other modules read the ids) → 2-of-3, proceed.ls adr/→0001,0002exist →NNNN = 0003. Title0003-time-sortable-ids.md(decision-form). Copies../design/templates/adr.md. Context: the §11 risk on hot-row contention forced an explicit id choice. Drivers: spec §6 NFR (predictable ordering) + the existing capability in the stack. Options: (a) time-sortable ids generated in the app; (b) database auto-increment; (c) random ids. Outcome: «Chosen: (a)» — keeps natural ordering without a central sequence; (b) couples to one writer, (c) loses ordering. Consequences: + ordered without coordination; − slightly larger ids than auto-increment; neutral: switching later needs a backfill. StatusAccepted. Adds a §9 row, fills## Links. Commitadr: checkout-discounts 0003 time-sortable-ids.