Skip to content

Commit f3b4396

Browse files
authored
Merge pull request #1732 from counterfact/copilot/create-adr-process
feat: add ADR process with auto-numbering CI workflow
2 parents 6dbb527 + 2934ca3 commit f3b4396

File tree

4 files changed

+208
-0
lines changed

4 files changed

+208
-0
lines changed

.github/scripts/number_adrs.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#!/usr/bin/env python3
2+
"""Assign sequential numbers to ADR files that use the placeholder 'xxx' prefix.
3+
4+
Scans docs/adr/ for files matching the pattern xxx-*.md, determines the next
5+
available sequential number based on already-numbered files in the same
6+
directory, renames each placeholder file, and prints a summary.
7+
8+
Exit codes:
9+
0 – all placeholder files renamed successfully (or none found)
10+
1 – one or more files could not be renamed
11+
"""
12+
13+
import glob
14+
import os
15+
import re
16+
import sys
17+
18+
19+
ADR_DIR = "docs/adr"
20+
PLACEHOLDER_PATTERN = "xxx-*.md"
21+
NUMBERED_PATTERN = re.compile(r"^(\d+)-")
22+
23+
24+
def next_adr_number(adr_dir: str) -> int:
25+
"""Return the next available sequential ADR number.
26+
27+
Scans *adr_dir* for files whose names begin with one or more digits
28+
followed by a hyphen (e.g. ``001-some-decision.md``) and returns the
29+
highest such number plus one. Returns 1 if no numbered files exist yet.
30+
"""
31+
highest = 0
32+
for filepath in glob.glob(os.path.join(adr_dir, "*.md")):
33+
filename = os.path.basename(filepath)
34+
match = NUMBERED_PATTERN.match(filename)
35+
if match:
36+
highest = max(highest, int(match.group(1)))
37+
return highest + 1
38+
39+
40+
def main() -> None:
41+
placeholder_glob = os.path.join(ADR_DIR, PLACEHOLDER_PATTERN)
42+
placeholders = sorted(glob.glob(placeholder_glob))
43+
44+
if not placeholders:
45+
print("No ADR placeholder files found — nothing to do.")
46+
return
47+
48+
failed = False
49+
50+
for filepath in placeholders:
51+
filename = os.path.basename(filepath)
52+
# Strip the leading "xxx-" prefix to get the rest of the name.
53+
suffix = filename[len("xxx-"):]
54+
55+
number = next_adr_number(ADR_DIR)
56+
new_filename = f"{number:03d}-{suffix}"
57+
new_filepath = os.path.join(ADR_DIR, new_filename)
58+
59+
if os.path.exists(new_filepath):
60+
print(
61+
f"Error: target path {new_filepath!r} already exists - skipping {filepath!r}.",
62+
file=sys.stderr,
63+
)
64+
failed = True
65+
continue
66+
67+
os.rename(filepath, new_filepath)
68+
print(f"Renamed: {filepath!r}{new_filepath!r}")
69+
70+
if failed:
71+
sys.exit(1)
72+
73+
74+
if __name__ == "__main__":
75+
main()

.github/workflows/number-adrs.yaml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: Number ADRs
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- 'docs/adr/xxx-*.md'
9+
10+
jobs:
11+
number-adrs:
12+
runs-on: ubuntu-latest
13+
permissions:
14+
contents: write
15+
16+
steps:
17+
- name: Check out repository
18+
uses: actions/checkout@v6
19+
with:
20+
# A custom token is required so that the automated commit can trigger
21+
# subsequent workflows (the default GITHUB_TOKEN cannot do this).
22+
token: ${{ secrets.CUSTOM_GITHUB_TOKEN }}
23+
24+
- name: Assign sequential numbers to ADR placeholder files
25+
run: python3 .github/scripts/number_adrs.py
26+
27+
- name: Commit renamed ADR files
28+
run: |
29+
git config user.name "github-actions[bot]"
30+
git config user.email "github-actions[bot]@users.noreply.github.com"
31+
git add docs/adr/
32+
if git diff --cached --quiet; then
33+
echo "No ADR files were renamed — nothing to commit."
34+
else
35+
git commit -m "chore: assign sequential numbers to ADR files"
36+
git pull --rebase
37+
git push
38+
fi

docs/adr/README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Architecture Decision Records
2+
3+
This directory contains Architecture Decision Records (ADRs) for Counterfact, using Andrew Harmel-Law's "Architecture Advice" template from _Facilitating Software Architecture_.
4+
5+
## What is an ADR?
6+
7+
An ADR captures the context, options considered, decision taken, and expected consequences for a significant architectural choice. ADRs are living documents reviewed and discussed in pull requests before a decision is finalised.
8+
9+
## Template Sections
10+
11+
Each ADR uses these sections:
12+
13+
| Section | Purpose |
14+
|---------|---------|
15+
| **Title** | Short, descriptive name for the decision |
16+
| **Status** | `proposed`, `accepted`, `superseded by [NNN]`, etc. |
17+
| **Context** | The problem or forces that prompted this decision |
18+
| **Decision** | The choice that was made |
19+
| **Options** | Alternatives that were considered (with brief pros/cons) |
20+
| **Consequences** | Outcomes, trade-offs, and follow-up work resulting from the decision |
21+
| **Advice** | Guidance for anyone implementing or working within this decision |
22+
23+
## File Naming
24+
25+
New ADR files are named `xxx-short-title.md` (with a literal `xxx` prefix) when first drafted. When the PR is merged to `main`, a CI automation replaces `xxx` with the next sequential three-digit number (e.g. `001`, `002`).
26+
27+
## Workflow
28+
29+
1. **Identify** a significant architectural problem or decision point.
30+
2. **Draft** an ADR as `docs/adr/xxx-short-title.md` on a new branch.
31+
3. **Discuss** the ADR in a pull request — update the document as the conversation evolves.
32+
4. **Decide** — update the Status to `accepted` and fill in the Decision section.
33+
5. **Merge** the PR. CI automatically assigns the next sequential ADR number.
34+
6. **Plan implementation** — create a follow-up issue asking Copilot to break the decision into implementation tasks.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Architecture Decision Records
2+
3+
## Title
4+
5+
Architecture Decision Records
6+
7+
## Status
8+
9+
Accepted
10+
11+
## Context
12+
13+
Counterfact is growing in complexity. Significant technical and process decisions are being made regularly — about code generation, server design, developer experience, and the development workflow itself. Without a structured record of these decisions, the reasoning behind choices becomes lost over time, making it hard for contributors (human or AI) to understand why things are the way they are, or to make consistent future decisions.
14+
15+
Copilot is increasingly involved in implementing features. For Copilot to make good decisions, it needs clear architectural context. An ADR process creates a durable, reviewable record of that context.
16+
17+
There are many ADR formats. Andrew Harmel-Law's "Architecture Advice" template, described in _Facilitating Software Architecture_, was chosen because it emphasises advice and consequences rather than just recording what was decided — making it actionable for future contributors.
18+
19+
## Decision
20+
21+
Introduce an ADR process for Counterfact using Andrew Harmel-Law's "Architecture Advice" template. ADRs live under `docs/adr/`. A CI automation assigns sequential numbers to new ADRs when they are merged.
22+
23+
## Options
24+
25+
### Option A: No ADR process (status quo)
26+
27+
Decisions are captured in issue comments, PR descriptions, and commit messages.
28+
29+
- **Pro:** No extra overhead.
30+
- **Con:** Reasoning is scattered and hard to locate. Context is lost over time.
31+
32+
### Option B: Lightweight ADRs in `docs/adr/` (chosen)
33+
34+
A simple Markdown file per decision, reviewed in PRs, auto-numbered on merge.
35+
36+
- **Pro:** Low overhead. Decisions are easy to find and link to. Reviewable before being finalised.
37+
- **Con:** Requires discipline to write ADRs for all significant decisions. Auto-numbering adds a small CI step.
38+
39+
### Option C: Third-party ADR tooling (e.g. `adr-tools`)
40+
41+
Use an existing CLI tool to manage ADRs.
42+
43+
- **Pro:** Tooling handles numbering and cross-references automatically.
44+
- **Con:** Adds a dependency. Less flexible for custom workflows. Doesn't integrate naturally with GitHub PR review.
45+
46+
## Consequences
47+
48+
- All significant architectural decisions for Counterfact will be documented in `docs/adr/`.
49+
- Contributors (including Copilot) can consult ADRs to understand the reasoning behind design choices.
50+
- A CI workflow must be created and maintained to auto-number ADR files on merge.
51+
- Discipline is required: not every change needs an ADR, but anything affecting the architecture, developer workflow, or external contracts should have one.
52+
- Future decisions may supersede existing ADRs; superseded ADRs are updated with a `Superseded by [NNN]` status rather than deleted.
53+
54+
## Advice
55+
56+
- Draft ADRs early — even a partially filled-in ADR creates useful discussion. (Copilot/Claude)
57+
- Keep ADRs concise. They should capture context and reasoning, not replace implementation documentation. (Copilot/Claude)
58+
- When implementing a decision, link the relevant ADR in commit messages and PR descriptions. (Copilot/Claude)
59+
- When asking Copilot to implement a decision, reference the ADR so it has the necessary context. (Copilot/Claude)
60+
- When a decision is revisited or reversed, update the old ADR's status to `Superseded by [NNN]` and create a new ADR explaining the change. (Copilot/Claude)
61+
- The three-stage workflow for acting on a decision is: ADR → plan → implementation, with a human review at each stage. (Copilot/Claude)

0 commit comments

Comments
 (0)