docs: audit links, glossary, readability pass #2
@@ -33,9 +33,6 @@ jobs:
|
|||||||
- name: Fetch base branch for ADR immutability
|
- name: Fetch base branch for ADR immutability
|
||||||
run: git fetch --depth=1 origin main
|
run: git fetch --depth=1 origin main
|
||||||
|
|
||||||
- name: Install checker dependencies
|
|
||||||
run: pip install --quiet pyyaml
|
|
||||||
|
|
||||||
- name: ADR immutability (no edits to accepted records)
|
- name: ADR immutability (no edits to accepted records)
|
||||||
run: python bin/check_adrs.py --base origin/main
|
run: python bin/check_adrs.py --base origin/main
|
||||||
|
|
||||||
|
|||||||
+3
-10
@@ -4,17 +4,13 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import json
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
try:
|
|
||||||
import yaml
|
|
||||||
except ImportError: # pragma: no cover - stdlib fallback for minimal envs
|
|
||||||
yaml = None # type: ignore[assignment]
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[1]
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
RULES_PATH = Path(__file__).with_name("docs_rules.yaml")
|
RULES_PATH = Path(__file__).with_name("docs_rules.json")
|
||||||
|
|
||||||
LINK_RE = re.compile(r"!?\[[^\]]*\]\(([^)]+)\)")
|
LINK_RE = re.compile(r"!?\[[^\]]*\]\(([^)]+)\)")
|
||||||
BARE_SEE_RE = re.compile(r"(?<![\[(/])see\s+(\d{2})(?![\w-])", re.IGNORECASE)
|
BARE_SEE_RE = re.compile(r"(?<![\[(/])see\s+(\d{2})(?![\w-])", re.IGNORECASE)
|
||||||
@@ -22,10 +18,7 @@ SKIP_SCHEMES = ("http://", "https://", "mailto:", "tel:", "#")
|
|||||||
|
|
||||||
|
|
||||||
def load_rules(path: Path = RULES_PATH) -> dict:
|
def load_rules(path: Path = RULES_PATH) -> dict:
|
||||||
text = path.read_text(encoding="utf-8")
|
return json.loads(path.read_text(encoding="utf-8"))
|
||||||
if yaml is not None:
|
|
||||||
return yaml.safe_load(text)
|
|
||||||
raise RuntimeError("PyYAML is required to load docs_rules.yaml")
|
|
||||||
|
|
||||||
|
|
||||||
def slug_heading(text: str) -> str:
|
def slug_heading(text: str) -> str:
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"markdown_paths": [
|
||||||
|
"docs/**/*.md",
|
||||||
|
"README.md",
|
||||||
|
"CONTRIBUTING.md",
|
||||||
|
"AGENTS.md",
|
||||||
|
"simulator/README.md",
|
||||||
|
"prototype/README.md",
|
||||||
|
"infra/**/README.md"
|
||||||
|
],
|
||||||
|
"glossary": {
|
||||||
|
"file": "docs/00-glossary.md"
|
||||||
|
},
|
||||||
|
"banned_link_targets": [
|
||||||
|
"03-storage-design.md"
|
||||||
|
],
|
||||||
|
"glossary_section_anchors": [
|
||||||
|
"data--storage",
|
||||||
|
"swarm--robotics",
|
||||||
|
"infrastructure--delivery"
|
||||||
|
],
|
||||||
|
"preferred_term_anchors": [
|
||||||
|
"t0--hot",
|
||||||
|
"t1--warm",
|
||||||
|
"t2--shared",
|
||||||
|
"t3--warehouse",
|
||||||
|
"t4--dev",
|
||||||
|
"source-of-truth",
|
||||||
|
"architecture-layer-1--ingestion",
|
||||||
|
"architecture-layer-2--storage-and-transform",
|
||||||
|
"architecture-layer-3--serving-and-sync",
|
||||||
|
"pipeline-stage",
|
||||||
|
"bulk-sync",
|
||||||
|
"offload",
|
||||||
|
"rclone",
|
||||||
|
"adr",
|
||||||
|
"asr"
|
||||||
|
],
|
||||||
|
"readability": {
|
||||||
|
"forbid_bare_see_refs": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
# Documentation rules enforced by CI (bin/check_docs.py).
|
|
||||||
# See docs/improvement/ci-rules.md for rationale and PR workflow.
|
|
||||||
|
|
||||||
markdown_paths:
|
|
||||||
- docs/**/*.md
|
|
||||||
- README.md
|
|
||||||
- CONTRIBUTING.md
|
|
||||||
- AGENTS.md
|
|
||||||
- simulator/README.md
|
|
||||||
- prototype/README.md
|
|
||||||
- infra/**/README.md
|
|
||||||
|
|
||||||
glossary:
|
|
||||||
file: docs/00-glossary.md
|
|
||||||
|
|
||||||
# Relative link targets that must never reappear (known regressions).
|
|
||||||
banned_link_targets:
|
|
||||||
- 03-storage-design.md
|
|
||||||
|
|
||||||
# Glossary links to these section headers are allowed but reported as warnings
|
|
||||||
# when a term-specific ### anchor exists (see preferred_term_anchors).
|
|
||||||
glossary_section_anchors:
|
|
||||||
- data--storage
|
|
||||||
- swarm--robotics
|
|
||||||
- infrastructure--delivery
|
|
||||||
|
|
||||||
# First-use vocabulary should link to these ### anchors, not section headers.
|
|
||||||
preferred_term_anchors:
|
|
||||||
- t0--hot
|
|
||||||
- t1--warm
|
|
||||||
- t2--shared
|
|
||||||
- t3--warehouse
|
|
||||||
- t4--dev
|
|
||||||
- source-of-truth
|
|
||||||
- architecture-layer-1--ingestion
|
|
||||||
- architecture-layer-2--storage-and-transform
|
|
||||||
- architecture-layer-3--serving-and-sync
|
|
||||||
- pipeline-stage
|
|
||||||
- bulk-sync
|
|
||||||
- offload
|
|
||||||
- rclone
|
|
||||||
- adr
|
|
||||||
- asr
|
|
||||||
|
|
||||||
readability:
|
|
||||||
# Fail when prose uses bare "see 05" instead of a markdown link.
|
|
||||||
forbid_bare_see_refs: true
|
|
||||||
@@ -15,7 +15,7 @@ Issues, PRs, and reviews default to **caveman-full** ([`CONTRIBUTING.md`](../../
|
|||||||
|
|
||||||
## CI automation
|
## CI automation
|
||||||
|
|
||||||
Enforced in Gitea Actions (`docs-verify` job). Rules live in [`bin/docs_rules.yaml`](../../bin/docs_rules.yaml); see [ci-rules.md](ci-rules.md).
|
Enforced in Gitea Actions (`docs-verify` job). Rules live in [`bin/docs_rules.json`](../../bin/docs_rules.json); see [ci-rules.md](ci-rules.md).
|
||||||
|
|
||||||
Originally tracked in [issue #1](https://git.produktor.io/eSlider/swarm-house/issues/1).
|
Originally tracked in [issue #1](https://git.produktor.io/eSlider/swarm-house/issues/1).
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Automated checks for markdown in this repository. Enforced on every **pull request** and on **push to `main`** (including docs-only pushes that skip the simulator gate).
|
Automated checks for markdown in this repository. Enforced on every **pull request** and on **push to `main`** (including docs-only pushes that skip the simulator gate).
|
||||||
|
|
||||||
Implementation: [`bin/check_docs.py`](../../bin/check_docs.py) reads [`bin/docs_rules.yaml`](../../bin/docs_rules.yaml).
|
Implementation: [`bin/check_docs.py`](../../bin/check_docs.py) reads [`bin/docs_rules.json`](../../bin/docs_rules.json).
|
||||||
|
|
||||||
Workflow: [`.github/workflows/release.yaml`](../../.github/workflows/release.yaml) job **`Verify documentation`**.
|
Workflow: [`.github/workflows/release.yaml`](../../.github/workflows/release.yaml) job **`Verify documentation`**.
|
||||||
|
|
||||||
@@ -53,6 +53,6 @@ python bin/check_docs.py --warnings-as-errors # treat section-link warnings as
|
|||||||
|
|
||||||
## Changing rules
|
## Changing rules
|
||||||
|
|
||||||
1. Edit `bin/docs_rules.yaml` (paths, banned targets, preferred anchors).
|
1. Edit `bin/docs_rules.json` (paths, banned targets, preferred anchors).
|
||||||
2. Adjust `bin/check_docs.py` only when adding a new rule *type*.
|
2. Adjust `bin/check_docs.py` only when adding a new rule *type*.
|
||||||
3. Add a row to the table above and mention it in the audit/improvement record if the change is significant.
|
3. Add a row to the table above and mention it in the audit/improvement record if the change is significant.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@@ -59,15 +60,18 @@ def test_broken_link_detected(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -
|
|||||||
(docs / "bad.md").write_text("See [missing](missing.md).\n")
|
(docs / "bad.md").write_text("See [missing](missing.md).\n")
|
||||||
rules = tmp_path / "bin"
|
rules = tmp_path / "bin"
|
||||||
rules.mkdir()
|
rules.mkdir()
|
||||||
(rules / "docs_rules.yaml").write_text(
|
(rules / "docs_rules.json").write_text(
|
||||||
"markdown_paths:\n - docs/**/*.md\n"
|
json.dumps(
|
||||||
"glossary:\n file: docs/00-glossary.md\n"
|
{
|
||||||
"banned_link_targets: []\n"
|
"markdown_paths": ["docs/**/*.md"],
|
||||||
"glossary_section_anchors: []\n"
|
"glossary": {"file": "docs/00-glossary.md"},
|
||||||
"preferred_term_anchors: []\n"
|
"banned_link_targets": [],
|
||||||
"readability:\n forbid_bare_see_refs: false\n"
|
"glossary_section_anchors": [],
|
||||||
|
"preferred_term_anchors": [],
|
||||||
|
"readability": {"forbid_bare_see_refs": False},
|
||||||
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
checker = SCRIPTS / "check_docs.py"
|
|
||||||
monkeypatch.setattr("check_docs.ROOT", tmp_path)
|
monkeypatch.setattr("check_docs.ROOT", tmp_path)
|
||||||
monkeypatch.setattr("check_docs.RULES_PATH", rules / "docs_rules.yaml")
|
monkeypatch.setattr("check_docs.RULES_PATH", rules / "docs_rules.json")
|
||||||
assert run_checks() == 1
|
assert run_checks() == 1
|
||||||
|
|||||||
Reference in New Issue
Block a user