Skip to content

gz adr demote

Demote a feature or foundation ADR back to pool — the inverse of gz adr promote. Strips kind/semver from frontmatter, moves the ADR file from pre-release/ or foundation/ to pool/, deletes the source package directory (briefs, closeout form), and emits an artifact_renamed ledger event with reason="pool_demotion".

Authored under GHI #521 as the Day-0 tooling prerequisite for the get-out-of-jail prequel sweep (GHI #520).


Usage

Bash
gz adr demote <ADR-ID> --ghi <NUMBER> [OPTIONS]

Options

Option Type Description
--ghi int Required. GitHub Issue number this demotion is tracked under. Every demotion must be auditable.
--note string Free-text operator rationale; stored in the ledger event extras.
--operator string Operator identity (name only; never email per Local Agent Rules). Defaults to omitted.
--dry-run flag Show planned actions without writing files or ledger events.
--json flag Emit a structured JSON result payload to stdout.
--force flag Override both exit-3 safety checks: dependent children (orphans any ADRs whose parent: frontmatter points at the demoted ADR) and live @covers decorators naming REQs from the deleted briefs (GHI #773).
--on-collision choice How to handle a pre-existing pool file at the target slug. fail (default) blocks; keep-pool deletes the source feature/foundation package and keeps the existing pool ADR — reversing any stale status: Superseded / promoted_to: / promotion-note markers that name the ADR now being demoted (GHI #558), and leaving an unrelated pool file at the same slug untouched; take-demoted writes the demoted ADR's current content to the pool slug, overwriting the retained intake (GHI #775). The ledger event records collision_resolution: "keep-pool" when that path is taken.

Behavior (Enforced)

  1. Source ADR must be feature or foundation kind with a valid semver field. Pool ADRs are rejected (already pool — nothing to demote).
  2. Pool target id is derived as ADR-pool.<slug>, where <slug> comes from the source ADR's id (ADR-X.Y.Z-<slug> → <slug>).
  3. Target file path: docs/design/adr/pool/ADR-pool.<slug>.md.
  4. Collision check. If the pool target file already exists, the demotion is rejected (exit 1) by default. A promote/demote round trip always collides, because gz adr promote retains the pool file as historical intake by design — so the choice of policy is the choice of which document survives. Pass --on-collision take-demoted when the ADR was worked after promotion: it writes the demoted ADR's current content to the pool slug, so what gets drawn from the queue later is the thinking as it stands. keep-pool is correct only when the promoted ADR did not diverge from its intake — otherwise it exits 0 having silently discarded every decision recorded after promotion (GHI #775). The superseded intake remains in git history either way. Passing --on-collision keep-pool resolves the collision by deleting the source feature/foundation package. If the kept pool ADR's promoted_to: still names the ADR being demoted (i.e. this demotion reverses that prior promotion), its status/promoted_to/promotion-note markers are reversed to their canonical pre-promotion state (status: Pool, promoted_to: stripped, the > Promoted to ... note removed) — this is the symmetric inverse of what gz adr promote writes on the pool side (GHI #558). A pool file colliding on slug but promoted to a different ADR is left untouched. The ledger event records the resolution either way.
  5. Frontmatter strip. kind, semver, frontmatter date and promoted_from (GHI #775) are removed. id is rewritten to the pool id, and so is the id in the body H1 (GHI #776). status is set to Pool. The ## OBPI Acceptance Note (Human Acknowledgment) section is stripped (GHI #777). Other fields (lane, parent, inspired_by, etc.) are preserved.
  6. OBPI briefs deleted. Per the 2026-05-23 get-out-of-jail prequel Q1=b decision, pool ADRs carry no OBPIs by doctrine; brief files under <source-dir>/obpis/ are deleted via the source-dir removal. A later gz adr promote regenerates briefs from the pool's scope and unparks the OBPIs this demotion parked.
  7. Source directory removed. The entire docs/design/adr/{pre-release,foundation}/<source-id>/ directory is deleted (taking the briefs, closeout form, and any other authoring artifacts with it).
  8. Dependent children check (fail-closed). If any other non-pool ADR has parent: <source-id> in its frontmatter, demotion is rejected with exit 3. Pass --force to orphan those children deliberately.
  9. Live @covers check (fail-closed, GHI #773). If any @covers decorator under tests/ names a REQ of this ADR's semver, demotion is rejected with exit 3: deleting the briefs would make those test modules fail to import. Remove or retarget the decorators, or pass --force.
  10. Ledger events. One artifact_renamed event is appended with reason="pool_demotion", followed by one obpi_parked event per child OBPI (parked_to: <pool-id>, reversible on re-promotion, GHI #584). The rename carries these extras (plus collision_resolution: "keep-pool" on that path):

    JSON
    {
      "prior_kind": "feature",
      "prior_semver": "0.27.0",
      "demoted_at": "<RFC 3339 UTC timestamp>",
      "ghi": 520,
      "operator": "<optional>",
      "note": "<optional>"
    }
    

Per state doctrine (Layer 2 ledger = source of truth for state transitions), the demote event is the canonical record of the prior life. Pool files do not carry previously: frontmatter; gz state <pool-id> is the query path.


Exit Codes

Code Meaning
0 Demotion completed (or dry-run succeeded).
1 User/config error: missing --ghi, pool target collision, ADR already pool, missing kind/semver.
2 System/IO error: frontmatter parse failure, ledger write failure.
3 Policy breach: dependent children exist, or live @covers decorators name REQs from the briefs being deleted; --force overrides.

Examples

Bash
# Preview demotion (mandatory --ghi)
gz adr demote ADR-0.27.0-arb-receipt-system-absorption --ghi 520 --dry-run

# Short-form ADR id resolves the same source
gz adr demote ADR-0.27.0 --ghi 520 --dry-run

# Apply demotion with operator-supplied rationale
gz adr demote ADR-0.27.0 --ghi 520 --note "prequel queue collapse"

# JSON output for scripted sweeps
gz adr demote ADR-0.27.0 --ghi 520 --json

# Override dependent-children safety (orphans the children)
gz adr demote ADR-0.27.0 --ghi 520 --force

# Resolve a pool-slug collision by keeping the existing pool ADR
gz adr demote ADR-0.42.0 --ghi 520 --on-collision keep-pool

# Round-trip an ADR that was worked after promotion: its current content
# becomes the pool file, replacing the retained pre-promotion intake
gz adr demote ADR-0.44.0 --ghi 773 --on-collision take-demoted --operator g0

See Also

  • gz adr promote — the forward inverse motion.
  • docs/governance/return-to-health-plan-2026-05-30.md — the current recovery plan; the prior emergency plan was removed.
  • GHI #520 — the 24-ADR sweep this verb enables.
  • GHI #521 — the tracking GHI for this verb's authoring.