decision-lifecycle
Author and track Architecture Decision Records. Routed to when the user invokes /adr to record a new decision or /adr-status to list ADR health. Authors numbered, dated, user-attributed ADRs under .codearbiter/decisions/, maintains supersede chains, and reports status read-only.
Install
npx skills add https://github.com/arbiterForge/codeArbiter/tree/main/plugins/ca/skills/decision-lifecycle
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install arbiterforge-codearbiter@llmmart
git clone https://github.com/arbiterForge/codeArbiter.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole arbiterforge/codearbiter collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
decision-lifecycle
Author and track ADRs. Routed to when the user invokes /adr "<title>" (author a new ADR) or /adr-status [--adr N] (list ADR health, read-only). Every ADR is user-attributed — this skill never records a decision the user did not explicitly make.
The append-only decision-log format (entry fields, supersession protocol) lives in ${CLAUDE_PLUGIN_ROOT}/includes/smarts/decision-log-format.md. Read it before writing a log line; do not restate it here.
Boundary with decision-variance. This skill owns ADR authoring and status (/adr, /adr-status) — recording a decision the user has already made, and reporting ADR health. decision-variance owns arbitration — detecting variances between artifacts and the scaffold, scoring options via SMARTS, and the decision log itself. The two share the canonical SMARTS reference under ${CLAUDE_PLUGIN_ROOT}/includes/smarts/ (core.md for scoring, decision-log-format.md for the log) and one ADR template (references/adr-template.md); they are one domain split by responsibility, not duplicated. When a decision needs making (competing options), route to decision-variance; when it needs recording (already decided), stay here.
Pre-flight
Read these, or STOP and surface the gap — never guess a path:
${CLAUDE_PROJECT_DIR}/.codearbiter/decisions/— the ADR directory and existing records. Create it on first/adrif absent.- For
/adr: confirm the user explicitly authorized this decision and supplied (or confirmed) its content. An ADR is never authored as the disposition of a routine finding.
Phase 1 — Index · gate: BLOCK
Scan ${CLAUDE_PROJECT_DIR}/.codearbiter/decisions/ for existing NNNN-*.md ADR files. Record each by filename stem (0014-githook-shim-dropin-fail-closed), title, and status. Determine the next sequential number (no gaps) for /adr; for /adr-status this is the working set.
The stem is the identifier; the number is only a sort key. Two ADRs may already share a number — this repository holds two numbered 0014 — so a bare number can name more than one document. Index by stem, and never assume NNNN resolves to one file until you have checked.
Gate: the existing ADRs are indexed by stem and, for /adr, the next number is fixed and unused — a number already taken by an existing stem is not available, even for an unrelated decision.
Phase 2 — Author (/adr) · gate: STOP
Confirm the decision content with the user — context, the decision itself, alternatives, consequences. MUST NOT fill these from inference. Surface any unknown as an inline [CONFIRM-NN] placeholder; do not resolve it by guessing.
Drop the authoring marker first. The pre-write/pre-edit hooks block any write to .codearbiter/decisions/NNNN-*.md unless a fresh authoring marker is present — that block is the mechanism enforcing "ADRs only via /adr" (arbiter.md §3), so the sanctioned path must arm it itself. Immediately before writing, create the marker at the path the hooks check (project root = git top level):
mkdir -p "$(git rev-parse --show-toplevel)/.codearbiter/.markers"
touch "$(git rev-parse --show-toplevel)/.codearbiter/.markers/adr-authoring-active"
The marker is honored for 30 minutes. Then write ${CLAUDE_PROJECT_DIR}/.codearbiter/decisions/NNNN-<slug>.md using the canonical ADR template — ${CLAUDE_PLUGIN_ROOT}/skills/decision-lifecycle/references/adr-template.md (the single source of truth for the ADR shape, shared with decompose). Author it with status: proposed. If this decision supersedes an existing one, set supersedes: to that ADR's full filename stem — supersedes: 0014-githook-shim-dropin-fail-closed, never supersedes: 0014 — and leave the prior ADR's file untouched (forward-only chain — do not edit it to add a back-reference).
If the new ADR supersedes only part of the prior decision, say which part in the body. supersedes: names a document, not a clause, so a chain may legitimately fork — two ADRs can each supersede different clauses of one predecessor. That fork is correct and must not be "repaired"; only the prose can carry the scope.
After writing the ADR, append a corresponding entry to the decision log per the format in ${CLAUDE_PLUGIN_ROOT}/includes/smarts/decision-log-format.md — Decided by: names the user. Status transitions (proposed → accepted → superseded | rejected) require explicit user instruction; never advance status on this skill's own judgment.
governs: makes the decision live. When an ADR names path globs in governs:, the post-write
hook surfaces a one-line notice on any Write/Edit touching a matching file — "this file is governed
by ADR-NNNN" — so a recorded decision pushes back at edit time instead of waiting for a checkpoint
sweep. Offer the field whenever a decision constrains identifiable files; omit it for decisions
without a file footprint. Globs are fnmatch-style against repo-relative forward-slash paths.
Once the ADR file and its log entry are written (and any user-instructed status edit is applied), remove the marker — it exists only for one authoring pass:
rm -f "$(git rev-parse --show-toplevel)/.codearbiter/.markers/adr-authoring-active"
Gate: the ADR file is written with a real decided-by user attribution, numbered without a gap, and its log entry is appended. An ADR with no user attribution, or authored as the disposition of a finding, does not pass — STOP.
Accepted/Planned binding
accepted means Accepted/Planned. It records the user's governance decision; it does not claim
that any obligation is Implemented or Verified. When the user explicitly authorizes acceptance:
- Change only the ADR's status fields to accepted. Derive stable, stem-scoped obligations from every normative clause in its immutable record, bind each obligation to exact ADR text, and obtain independent review that the sealed obligation set is complete.
- Route through
commit-gateto commit the accepted ADR and decision-log append. Do not add the acceptance binding to that commit: itssource_commitcannot truthfully name a commit that does not exist yet. - From that exact commit, hash the committed Git blob bytes and the separately canonicalized
immutable record: strict UTF-8 with LF-normalized line endings, containing the complete ADR while
replacing only the recognized status value in the strictly parsed frontmatter
status:field and## Statussection with fixed sentinels. The two values must agree. All remaining Status prose, including approval attribution, stays bound alongside title, date,decided-by, supersession, governed paths, H1, and every other section. Malformed or duplicate frontmatter, status, or headings fail closed. Append oneacceptanceevent to${CLAUDE_PROJECT_DIR}/.codearbiter/decisions/adr-lifecycle.jsonl, then persist that acceptance binding in a subsequent commit. The event uses schemaadr-lifecycle/v1and recordsadr(full stem),recorded_at,source_commit,blob_sha256,body_sha256,obligations,obligations_sha256, andobligations_sealed: true. A second acceptance or baseline binding for the same stem is invalid. - Preserve ADR source ancestry through delivery. Before opening the PR and again before
its merge offer, follow the finishing skill's
--merge-methodpreflight on the exact base/head. A source not already in base ancestry requires a true merge commit with--match-head-commit; squash or rebase would orphan its identity. Missing source ancestry blocks delivery. Never rewrite the acceptance binding or rely on deleted branch objects remaining remotely fetchable.
The lifecycle ledger is append-only. A legacy accepted ADR receives a baseline with no fabricated
acceptance commit, an observed_commit whose Git blob is rechecked as the migration snapshot, an
empty or incrementally mapped obligation list, and
obligations_sealed: false; it remains Accepted/Planned. Later delivery evidence appends records:
implemented binds one declared obligation to a source commit and relevant input digests;
verified additionally binds a unique event ID, explicit proof contract, repository-scoped claim,
producer, command/workflow identity, timezone-aware observation and expiry times, and the same current
inputs. Evidence paths and digests are recomputed from the named Git commit, never trusted from the
caller. A later uniquely identified event may renew expired or changed-input evidence; an append-only
invalidation event may withdraw a prior evidence event. Only a complete,
sealed obligation set with current implementation inputs and fresh verification inputs derives
Implemented or Verified. Changed inputs invalidate the derived state; history is never rewritten.
After acceptance, do not edit any bound ADR content. A later user-authorized stored status transition
may change only the recognized status value in the strictly parsed frontmatter status: and
## Status; approval prose remains immutable. Supersession remains a forward reference in the new
ADR. The acceptance commit retains the exact original blob while the immutable-record digest proves
every other byte-equivalent field did not change.
Phase 3 — Status (/adr-status) · gate: BLOCK
Read-only. For each ADR (or the --adr N target), report: stem, title, stored governance status,
derived delivery state, date, and supersession state. Read adr-lifecycle.jsonl when present. Display
stored accepted as Accepted/Planned. Display Implemented or Verified only when every obligation
in a sealed binding has the required current, input-bound evidence; otherwise name the narrow reason
(unsealed, incomplete, stale, expired, or mismatched) and do not promote the ADR. Repository evidence
never implies live-host, publication, support, legal, or other external truth. Find supersession by
scanning forward for any later ADR whose supersedes: resolves to it.
Resolve a supersedes: value like this, and never guess:
- The value is a stem → it names that ADR. Done.
- The value is a bare number → collect every stem with that number. Exactly one → it names that ADR. More than one → ambiguous: report it as an error and resolve nothing. Zero → a dangling reference; report that too.
none(or empty) → no predecessor.
.github/scripts/check_adr_identity.py enforces this same rule mechanically in CI; if it disagrees with this report, the report is wrong.
If a supersession candidate contradicts an accepted ADR with no clear direction, do not pick one — flag it for /conflict.
## ADR Status — YYYY-MM-DD
### Active
- ADR-NNNN-<slug> — <title> — governance: <status>; delivery: <Accepted/Planned | Implemented | Verified> (<date>)
### Superseded
- ADR-NNNN-<slug> — <title> — superseded by ADR-MMMM-<slug>
### Ambiguous supersession
- ADR-NNNN-<slug> — supersedes: <value> names <N> ADRs (<stems>) — unresolved
### Unresolved CONFIRM-NN
- ADR-NNNN-<slug> — [CONFIRM-NN]: <text>
Every ADR is named by its stem, so a shared number never collapses two rows into one. An empty section is marked "None" — not omitted. MAY dispatch decision-challenger (${CLAUDE_PLUGIN_ROOT}/agents/decision-challenger.md) to stress-test an ADR; optional, never forced.
Gate: every indexed ADR appears with its current status and supersession state; no [CONFIRM-NN] resolved; no file modified.
Hard rules
- MUST author an ADR only via
/adrwith explicit user attribution. MUST NOT author an ADR as the disposition of a routine finding — an out-of-scope finding gets an inline[NEEDS-TRIAGE]marker instead. - MUST NOT record a decision the user did not explicitly make. "Use your best judgment," "I trust you" are declined.
- MUST NOT resolve a
[CONFIRM-NN]placeholder by guessing. Surface it and stop. - MUST NOT advance an ADR's status without explicit user instruction.
- MUST NOT report accepted as Implemented or Verified without complete, sealed, current lifecycle evidence.
- MUST NOT rewrite or truncate a committed
adr-lifecycle.jsonl, create a second binding, or fabricate legacy acceptance evidence. - MUST NOT edit a prior ADR or a prior decision-log entry to add a back-reference — supersession is a forward-only chain; append a new record whose
supersedes:names the prior one. - The never-edit rule protects decision CONTENT, not identifiers. Rewriting what was decided corrupts the record; disambiguating which document a pointer names repairs it. Maintainer ruling, 2026-07-25: "the never edit rule is meant to prevent this situation, not prevent this situation from being fixed." So a correction that is provably identifier-only — a
supersedes:value changed from a number to the stem it already meant — is permissible, and nothing else about the file is. Any such correction MUST be a single-line diff that alters not one word of any decision, MUST be visible in its own commit, and still requires the maintainer-armedadr-authoring-activemarker. MUST NOT touch Context, Decision, Alternatives, Consequences, Risks,status:,date:,decided-by:, ortitle:under this allowance. - MUST NOT number an ADR with a gap, and MUST NOT reuse a number an existing stem already holds — a shared number makes every bare reference to it ambiguous.
- MUST NOT modify any file under
/adr-status— it is read-only. - MUST NOT force the
decision-challengeragent — its dispatch is MAY only.
Files (codearbiter)
-
references
-
adr-template.md 4.2 KB
# Canonical ADR template The single source of truth for the shape of an Architecture Decision Record under `${CLAUDE_PROJECT_DIR}/.codearbiter/decisions/`. Both `decision-lifecycle` (via `/adr`) and `decompose` (Layer 4 DRAFT ADRs) author to this exact format, so `/adr-status` and the `governs:` post-write hook parse every ADR the same way regardless of who wrote it. ## Filename `NNNN-<slug>.md` — a zero-padded 4-digit sequential number with no gaps (`0001-…`, `0002-…`), numbered across the existing `decisions/` directory. **The filename stem is the ADR's identifier** — `0014-githook-shim-dropin-fail-closed`, not `0014`. The number alone is a sort key, not a name: this repository already holds two ADRs numbered 0014, so `supersedes: 0014` named two documents at once until it was disambiguated. Reference an ADR by its full stem everywhere a machine reads it. ## File format ```markdown --- status: proposed date: YYYY-MM-DD title: <title> decided-by: <user identifier> supersedes: NNNN-<slug> | none governs: <optional, comma-separated path globs this decision constrains — e.g. src/auth/*, config/tls/*> --- # ADR-NNNN — <title> ## Status <Proposed | Accepted | Superseded | Rejected | Draft> ## Context <What situation, constraint, or requirement prompted this decision?> ## Decision <What was decided. One clear statement.> ## Alternatives considered - **<Option A>** — <why not chosen> - **<Option B>** — <why not chosen> ## Consequences <What becomes easier or harder as a result.> ## Risks <What could go wrong; what would prove this decision wrong.> ``` ## Field & status semantics - **`status:` (frontmatter) is authoritative** — `/adr-status` reads it. The `## Status` body line mirrors it for human readers. Keep the two in agreement. - **Status lifecycle:** `proposed → accepted → superseded | rejected`. `decompose` authors Layer 4 ADRs as **`status: draft`** during the interview and promotes each to `status: accepted` at its Phase 5 in one sanctioned status edit that changes both the frontmatter `status:` field and the `## Status` value, without changing any other body content. Status transitions otherwise require explicit user instruction; never advance status on the skill's own judgment. - **`accepted` means Accepted/Planned.** It records an approved governance decision and does not imply implementation. Implemented and Verified are derived delivery states from the separate append-only `adr-lifecycle.jsonl`; they are never written into ADR frontmatter. After acceptance, the decision record is immutable except for the recognized, agreeing status value in the strictly parsed frontmatter `status:` field and `## Status` section. Approval attribution and all other Status prose remain bound with title, date, `decided-by`, supersession, governed paths, H1, and every other section. A later explicit status transition changes only those recognized status values. - **`decided-by:`** names the user who made the decision — real attribution, never inferred. - **`supersedes:`** names the prior ADR's full filename stem — `supersedes: 0014-githook-shim-dropin-fail-closed`, not `supersedes: 0014` — or `none`. A bare number is still accepted for the legacy records that carry one, but ONLY while it names exactly one ADR; once a number is shared it is an error, not a guess, and this repository's own CI fails the build (the identity check is CI-only and is not shipped, so a consumer enforces this rule by review rather than by script). Supersession is a forward-only chain: set it on the new ADR; never edit the prior ADR to add a back-reference. - **`supersedes:` cannot say WHICH CLAUSE it supersedes.** A partial supersession — the new ADR replaces some clauses of the prior one and leaves the rest in force — must say so in prose, and a chain may legitimately fork when two ADRs supersede different clauses of one predecessor. The frontmatter records only *which document*; the body records *how much of it*. - **`governs:`** (optional) lists fnmatch-style, repo-relative forward-slash path globs. When present, the post-write hook surfaces a "governed by ADR-NNNN" notice on any Write/Edit touching a matching file. Omit it for decisions without a file footprint.
-
-
SKILL.md 13.7 KB
--- name: decision-lifecycle description: Author and track Architecture Decision Records. Routed to when the user invokes /adr to record a new decision or /adr-status to list ADR health. Authors numbered, dated, user-attributed ADRs under .codearbiter/decisions/, maintains supersede chains, and reports status read-only. Never authors an ADR as its own judgment — every ADR carries explicit user attribution. --- # decision-lifecycle Author and track ADRs. Routed to when the user invokes `/adr "<title>"` (author a new ADR) or `/adr-status [--adr N]` (list ADR health, read-only). Every ADR is user-attributed — this skill never records a decision the user did not explicitly make. The append-only decision-log format (entry fields, supersession protocol) lives in `${CLAUDE_PLUGIN_ROOT}/includes/smarts/decision-log-format.md`. Read it before writing a log line; do not restate it here. **Boundary with `decision-variance`.** This skill owns ADR *authoring* and *status* (`/adr`, `/adr-status`) — recording a decision the user has already made, and reporting ADR health. `decision-variance` owns *arbitration* — detecting variances between artifacts and the scaffold, scoring options via SMARTS, and the decision log itself. The two share the canonical SMARTS reference under `${CLAUDE_PLUGIN_ROOT}/includes/smarts/` (`core.md` for scoring, `decision-log-format.md` for the log) and one ADR template (`references/adr-template.md`); they are one domain split by responsibility, not duplicated. When a decision needs *making* (competing options), route to `decision-variance`; when it needs *recording* (already decided), stay here. ## Pre-flight Read these, or STOP and surface the gap — never guess a path: - `${CLAUDE_PROJECT_DIR}/.codearbiter/decisions/` — the ADR directory and existing records. Create it on first `/adr` if absent. - For `/adr`: confirm the user explicitly authorized this decision and supplied (or confirmed) its content. An ADR is never authored as the disposition of a routine finding. ## Phase 1 — Index · gate: BLOCK Scan `${CLAUDE_PROJECT_DIR}/.codearbiter/decisions/` for existing `NNNN-*.md` ADR files. Record each by **filename stem** (`0014-githook-shim-dropin-fail-closed`), title, and status. Determine the next sequential number (no gaps) for `/adr`; for `/adr-status` this is the working set. **The stem is the identifier; the number is only a sort key.** Two ADRs may already share a number — this repository holds two numbered 0014 — so a bare number can name more than one document. Index by stem, and never assume `NNNN` resolves to one file until you have checked. Gate: the existing ADRs are indexed by stem and, for `/adr`, the next number is fixed and **unused** — a number already taken by an existing stem is not available, even for an unrelated decision. ## Phase 2 — Author (/adr) · gate: STOP Confirm the decision content with the user — context, the decision itself, alternatives, consequences. MUST NOT fill these from inference. Surface any unknown as an inline `[CONFIRM-NN]` placeholder; do not resolve it by guessing. **Drop the authoring marker first.** The `pre-write`/`pre-edit` hooks block any write to `.codearbiter/decisions/NNNN-*.md` unless a fresh authoring marker is present — that block is the mechanism enforcing "ADRs only via `/adr`" (arbiter.md §3), so the sanctioned path must arm it itself. Immediately before writing, create the marker at the path the hooks check (project root = git top level): ```bash mkdir -p "$(git rev-parse --show-toplevel)/.codearbiter/.markers" touch "$(git rev-parse --show-toplevel)/.codearbiter/.markers/adr-authoring-active" ``` The marker is honored for 30 minutes. Then write `${CLAUDE_PROJECT_DIR}/.codearbiter/decisions/NNNN-<slug>.md` using the canonical ADR template — `${CLAUDE_PLUGIN_ROOT}/skills/decision-lifecycle/references/adr-template.md` (the single source of truth for the ADR shape, shared with `decompose`). Author it with `status: proposed`. If this decision supersedes an existing one, set `supersedes:` to that ADR's **full filename stem** — `supersedes: 0014-githook-shim-dropin-fail-closed`, never `supersedes: 0014` — and leave the prior ADR's file untouched (forward-only chain — do not edit it to add a back-reference). If the new ADR supersedes only *part* of the prior decision, say which part in the body. `supersedes:` names a document, not a clause, so a chain may legitimately fork — two ADRs can each supersede different clauses of one predecessor. That fork is correct and must not be "repaired"; only the prose can carry the scope. After writing the ADR, append a corresponding entry to the decision log per the format in `${CLAUDE_PLUGIN_ROOT}/includes/smarts/decision-log-format.md` — `Decided by:` names the user. Status transitions (`proposed → accepted → superseded | rejected`) require explicit user instruction; never advance status on this skill's own judgment. **`governs:` makes the decision live.** When an ADR names path globs in `governs:`, the post-write hook surfaces a one-line notice on any Write/Edit touching a matching file — "this file is governed by ADR-NNNN" — so a recorded decision pushes back at edit time instead of waiting for a checkpoint sweep. Offer the field whenever a decision constrains identifiable files; omit it for decisions without a file footprint. Globs are fnmatch-style against repo-relative forward-slash paths. Once the ADR file and its log entry are written (and any user-instructed status edit is applied), remove the marker — it exists only for one authoring pass: ```bash rm -f "$(git rev-parse --show-toplevel)/.codearbiter/.markers/adr-authoring-active" ``` Gate: the ADR file is written with a real `decided-by` user attribution, numbered without a gap, and its log entry is appended. An ADR with no user attribution, or authored as the disposition of a finding, does not pass — STOP. ### Accepted/Planned binding `accepted` means **Accepted/Planned**. It records the user's governance decision; it does not claim that any obligation is Implemented or Verified. When the user explicitly authorizes acceptance: 1. Change only the ADR's status fields to accepted. Derive stable, stem-scoped obligations from every normative clause in its immutable record, bind each obligation to exact ADR text, and obtain independent review that the sealed obligation set is complete. 2. Route through `commit-gate` to commit the accepted ADR and decision-log append. Do not add the acceptance binding to that commit: its `source_commit` cannot truthfully name a commit that does not exist yet. 3. From that exact commit, hash the committed Git blob bytes and the separately canonicalized immutable record: strict UTF-8 with LF-normalized line endings, containing the complete ADR while replacing only the recognized status value in the strictly parsed frontmatter `status:` field and `## Status` section with fixed sentinels. The two values must agree. All remaining Status prose, including approval attribution, stays bound alongside title, date, `decided-by`, supersession, governed paths, H1, and every other section. Malformed or duplicate frontmatter, status, or headings fail closed. Append one `acceptance` event to `${CLAUDE_PROJECT_DIR}/.codearbiter/decisions/adr-lifecycle.jsonl`, then persist that acceptance binding in a subsequent commit. The event uses schema `adr-lifecycle/v1` and records `adr` (full stem), `recorded_at`, `source_commit`, `blob_sha256`, `body_sha256`, `obligations`, `obligations_sha256`, and `obligations_sealed: true`. A second acceptance or baseline binding for the same stem is invalid. 4. Preserve **ADR source ancestry** through delivery. Before opening the PR and again before its merge offer, follow the finishing skill's `--merge-method` preflight on the exact base/head. A source not already in base ancestry requires a true merge commit with `--match-head-commit`; squash or rebase would orphan its identity. Missing source ancestry blocks delivery. Never rewrite the acceptance binding or rely on deleted branch objects remaining remotely fetchable. The lifecycle ledger is append-only. A legacy accepted ADR receives a `baseline` with no fabricated acceptance commit, an `observed_commit` whose Git blob is rechecked as the migration snapshot, an empty or incrementally mapped obligation list, and `obligations_sealed: false`; it remains Accepted/Planned. Later delivery evidence appends records: `implemented` binds one declared obligation to a source commit and relevant input digests; `verified` additionally binds a unique event ID, explicit proof contract, repository-scoped claim, producer, command/workflow identity, timezone-aware observation and expiry times, and the same current inputs. Evidence paths and digests are recomputed from the named Git commit, never trusted from the caller. A later uniquely identified event may renew expired or changed-input evidence; an append-only invalidation event may withdraw a prior evidence event. Only a complete, sealed obligation set with current implementation inputs and fresh verification inputs derives Implemented or Verified. Changed inputs invalidate the derived state; history is never rewritten. After acceptance, do not edit any bound ADR content. A later user-authorized stored status transition may change only the recognized status value in the strictly parsed frontmatter `status:` and `## Status`; approval prose remains immutable. Supersession remains a forward reference in the new ADR. The acceptance commit retains the exact original blob while the immutable-record digest proves every other byte-equivalent field did not change. ## Phase 3 — Status (/adr-status) · gate: BLOCK Read-only. For each ADR (or the `--adr N` target), report: stem, title, stored governance status, derived delivery state, date, and supersession state. Read `adr-lifecycle.jsonl` when present. Display stored `accepted` as **Accepted/Planned**. Display Implemented or Verified only when every obligation in a sealed binding has the required current, input-bound evidence; otherwise name the narrow reason (unsealed, incomplete, stale, expired, or mismatched) and do not promote the ADR. Repository evidence never implies live-host, publication, support, legal, or other external truth. Find supersession by scanning forward for any later ADR whose `supersedes:` **resolves to** it. Resolve a `supersedes:` value like this, and never guess: - The value is a **stem** → it names that ADR. Done. - The value is a **bare number** → collect every stem with that number. Exactly one → it names that ADR. More than one → **ambiguous: report it as an error and resolve nothing.** Zero → a dangling reference; report that too. - `none` (or empty) → no predecessor. `.github/scripts/check_adr_identity.py` enforces this same rule mechanically in CI; if it disagrees with this report, the report is wrong. If a supersession candidate contradicts an `accepted` ADR with no clear direction, do not pick one — flag it for `/conflict`. ``` ## ADR Status — YYYY-MM-DD ### Active - ADR-NNNN-<slug> — <title> — governance: <status>; delivery: <Accepted/Planned | Implemented | Verified> (<date>) ### Superseded - ADR-NNNN-<slug> — <title> — superseded by ADR-MMMM-<slug> ### Ambiguous supersession - ADR-NNNN-<slug> — supersedes: <value> names <N> ADRs (<stems>) — unresolved ### Unresolved CONFIRM-NN - ADR-NNNN-<slug> — [CONFIRM-NN]: <text> ``` Every ADR is named by its stem, so a shared number never collapses two rows into one. An empty section is marked "None" — not omitted. MAY dispatch `decision-challenger` (`${CLAUDE_PLUGIN_ROOT}/agents/decision-challenger.md`) to stress-test an ADR; optional, never forced. Gate: every indexed ADR appears with its current status and supersession state; no `[CONFIRM-NN]` resolved; no file modified. ## Hard rules - MUST author an ADR only via `/adr` with explicit user attribution. MUST NOT author an ADR as the disposition of a routine finding — an out-of-scope finding gets an inline `[NEEDS-TRIAGE]` marker instead. - MUST NOT record a decision the user did not explicitly make. "Use your best judgment," "I trust you" are declined. - MUST NOT resolve a `[CONFIRM-NN]` placeholder by guessing. Surface it and stop. - MUST NOT advance an ADR's status without explicit user instruction. - MUST NOT report accepted as Implemented or Verified without complete, sealed, current lifecycle evidence. - MUST NOT rewrite or truncate a committed `adr-lifecycle.jsonl`, create a second binding, or fabricate legacy acceptance evidence. - MUST NOT edit a prior ADR or a prior decision-log entry to add a back-reference — supersession is a forward-only chain; append a new record whose `supersedes:` names the prior one. - **The never-edit rule protects decision CONTENT, not identifiers.** Rewriting what was decided corrupts the record; disambiguating *which document a pointer names* repairs it. Maintainer ruling, 2026-07-25: *"the never edit rule is meant to prevent this situation, not prevent this situation from being fixed."* So a correction that is provably identifier-only — a `supersedes:` value changed from a number to the stem it already meant — is permissible, and nothing else about the file is. Any such correction MUST be a single-line diff that alters not one word of any decision, MUST be visible in its own commit, and still requires the maintainer-armed `adr-authoring-active` marker. MUST NOT touch Context, Decision, Alternatives, Consequences, Risks, `status:`, `date:`, `decided-by:`, or `title:` under this allowance. - MUST NOT number an ADR with a gap, and MUST NOT reuse a number an existing stem already holds — a shared number makes every bare reference to it ambiguous. - MUST NOT modify any file under `/adr-status` — it is read-only. - MUST NOT force the `decision-challenger` agent — its dispatch is MAY only.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.