Superseding a record

Replace an accepted record with a new one, and keep both records saying so.

ctxgrd checks the replacement from both sides. core.supersedes-reciprocal checks the new record. core.successor-link checks the old one. This guide covers the first rule.

Before you start

Your ADR or PRD namespace must bind core.supersedes-reciprocal. The project-docs pack binds it on both namespaces since 5.1.0. Check your version:

ctxgrd --version

If your ctxgrd.toml predates 5.1.0, adopt the rule with ctxgrd pack migrate. Migrate rewrites blocks you have not edited. It prints a diff for blocks you have edited, and you merge those by hand.

ctxgrd pack migrate --dry-run
ctxgrd pack migrate

Name the record you replace

In the new record, list the replaced records under supersedes. A bare string also works for one entry.

---
id: ADR-002
title: Use CockroachDB
status: accepted
supersedes: [ADR-001]
---

Lint the repository. ADR-001 is still accepted, so ctxgrd warns on the supersedes line of ADR-002:

warning[core.supersedes-reciprocal]: ADR-002 supersedes ADR-001, but ADR-001 has status `accepted` and no `superseded_by`
  --> docs/adrs/002-use-cockroachdb.md:7:0
      |
    7 | supersedes: [ADR-001]
      | ^
      |
  help: on ADR-001, set `status: superseded` and `superseded_by: ADR-002`

found: 0 errors · 1 warning

Mark the old record superseded

Edit the replaced record. Set its status to superseded and name the new record in superseded_by.

---
id: ADR-001
title: Use Postgres
status: superseded
superseded_by: ADR-002
---

Run ctxgrd again. The warning is gone:

ok: 2 documents · 15 rules · 0 diagnostics

When the rule fires

The rule checks a record only when its own status is accepted. A draft record can name what it will replace without triggering a warning.

For each entry in supersedes, the replaced record must have both of these:

  • status: superseded
  • a superseded_by that names the new record

ctxgrd reports one warning per offending entry, on the supersedes line. A wrong superseded_by counts as an offense.

Fix an entry that names no document

An entry that matches no record in the run is reported at any status, including draft. Suppose ADR-002 lists ADR-009, which does not exist:

warning[core.supersedes-reciprocal]: ADR-002: `supersedes` entry 'ADR-009' does not resolve to a document in the run
  --> docs/adrs/002-use-cockroachdb.md:7:0
      |
    7 | supersedes: [ADR-001, ADR-009]
      | ^
      |
  help: create the replaced record or fix the `supersedes` entry

Correct the id, or create the missing record.

Make the finding fail CI

The rule reports at warning level, and warnings never change the exit code. To fail the run, set severity to error in the namespace’s rule table:

[ADR."core.supersedes-reciprocal"]
severity = "error"

The accepted values are error and warning. With error, the finding above prints as error[core.supersedes-reciprocal] and ctxgrd exits with code 1.