Owner: Vadim Rudakov, rudakow
1. Architectural Overview: The SVA Principle¶
This script validates that ADR (Architecture Decision Record) files in architecture/adr/ are synchronized with the index at architecture/adr_index.md.
It ensures:
Every ADR file has a corresponding entry in the index
No orphan entries exist (entries pointing to non-existent files)
Links in the index point to the correct file paths
Index entries are in numerical order
This tool is designed to serve as a quality gate in CI/CD, ensuring the ADR index stays synchronized with ADR files.
SVA = right tool for the job
It adheres to the Smallest Viable Architecture (SVA) principle.
SVA isn’t about minimal code — it’s about minimal cognitive and operational overhead.
Zero External Dependencies: Uses only the Python standard library (
argparse,re,subprocess,sys,pathlib).Pattern-Based Detection: Parses ADR headers and index entries using regex patterns.
Git Integration: Optional
--check-stagedmode for pre-commit integration.
2. Key Capabilities & Logic¶
A. ADR File Discovery¶
The script discovers ADR files by:
| Step | Description |
|---|---|
| Glob pattern | Finds files matching architecture/adr/adr_*.md |
| Template exclusion | Excludes adr_template.md |
| Header parsing | Extracts number and title from # ADR NNNNN: Title header |
| Sorting | Returns files sorted by ADR number ascending |
B. Index Parsing¶
The script parses the MyST glossary format:
:::{glossary}
ADR 26001
: [Title](path/to/adr_26001_slug.md)
ADR 26002
: [Another Title](path/to/adr_26002_slug.md)
:::| Field | Extraction |
|---|---|
| Number | From ADR NNNNN line |
| Title | From markdown link text [Title] |
| Link | From markdown link path (/path/to/file.md) |
C. Validation Rules¶
| Error Type | Description |
|---|---|
missing_in_index | ADR file exists but has no index entry |
orphan_in_index | Index entry points to non-existent file |
wrong_link | Index link path doesn’t match actual file path |
wrong_order | Index entries are not in numerical order |
duplicate_number | Multiple files have the same ADR number |
D. Auto-Fix Mode¶
When run with --fix, the script:
Reads all valid ADR files
Regenerates the index with correct entries
Sorts entries by ADR number
Removes orphan entries
Reports all changes made
3. Operational Guide¶
CLI Options¶
| Option | Description |
|---|---|
--verbose, -v | Show detailed output including counts |
--fix | Automatically fix index by regenerating it |
--check-staged | Only check staged ADR files (for pre-commit) |
Basic Usage¶
cd ../../../# Validate ADR index synchronization (default)
env -u VIRTUAL_ENV uv run tools/scripts/check_adr_index.py# Verbose output
env -u VIRTUAL_ENV uv run tools/scripts/check_adr_index.py --verboseChecking ADR index synchronization...
Found 13 ADR files
Found 13 index entries
All ADRs are synchronized with the index.
# Auto-fix issues
env -u VIRTUAL_ENV uv run tools/scripts/check_adr_index.py --fix --verboseChecking ADR index synchronization...
Running in fix mode...
No changes needed.
# Check only staged files (for pre-commit)
env -u VIRTUAL_ENV uv run tools/scripts/check_adr_index.py --check-staged --verboseChecking ADR index synchronization...
No staged ADR files to check.
Exit Codes¶
| Code | Meaning |
|---|---|
0 | All ADRs are synchronized with the index |
1 | One or more synchronization errors found |
4. Validation Layers¶
Pre-commit Hook¶
The script runs automatically via pre-commit when ADR or index files change:
- id: check-adr-index
name: Check ADR Index
entry: uv run --active tools/scripts/check_adr_index.py
language: python
files: ^architecture/(adr/adr_.*\.md|adr_index\.md)$
pass_filenames: false
stages: [pre-commit, manual]GitHub Actions¶
The script runs in CI via the adr-index job in quality.yml:
adr-index:
runs-on: ubuntu-latest
steps:
- name: Run ADR Index Check
run: uv run tools/scripts/check_adr_index.py --verbose5. Test Suite¶
The test suite covers:
| Test Class | Coverage |
|---|---|
TestGetAdrFiles | ADR file discovery, template exclusion, sorting |
TestParseIndex | Glossary parsing, entry extraction |
TestValidateSync | Sync validation (missing, orphan, wrong link, order) |
TestAutoFixIndex | Fix mode (add entries, maintain order, remove orphans) |
TestCli | CLI integration (exit codes, verbose, fix flag) |
TestEdgeCases | Edge cases (special characters, whitespace, relative paths) |
Run tests with:
uv run pytest tools/tests/test_check_adr_index.py -venv -u VIRTUAL_ENV uv run pytest tools/tests/test_check_adr_index.py -q................................................. [100%]
49 passed in 0.09s
env -u VIRTUAL_ENV uv run pytest tools/tests/test_check_adr_index.py --cov=. --cov-report=term-missing -q................................................. [100%]
================================ tests coverage ================================
_______________ coverage: platform linux, python 3.13.11-final-0 _______________
Name Stmts Miss Cover Missing
-------------------------------------------------------------------
tools/scripts/check_adr_index.py 183 2 99% 353-354
tools/tests/test_check_adr_index.py 395 1 99% 47
-------------------------------------------------------------------
TOTAL 578 3 99%
49 passed in 0.13s
6. Common Scenarios¶
Adding a New ADR¶
Create new ADR file:
architecture/adr/adr_26014_new_feature.mdRun validation:
uv run tools/scripts/check_adr_index.pySee error: “ADR 26014 (adr_26014_new_feature.md) not in index”
Fix automatically:
uv run tools/scripts/check_adr_index.py --fix
Renaming an ADR¶
Rename file:
adr_26001_old.md→adr_26001_new.mdRun validation: detects wrong link
Fix:
uv run tools/scripts/check_adr_index.py --fix
Removing an ADR¶
Delete ADR file
Run validation: detects orphan entry
Fix:
uv run tools/scripts/check_adr_index.py --fix