80 lines
2.9 KiB
Python
80 lines
2.9 KiB
Python
#!/usr/bin/env python3
|
||||
|
|
"""pruefe_upstream_drift.py — Byte-Vergleich gegen die gepinnte Baseline.
|
|||
|
|
|
|||
|
|
Schützt die übernommenen Framework-Dateien vor stillem Umschreiben
|
|||
|
|
(Entscheidung 8 im Design 2026-08-11, Frage von sorb: „wird die
|
|||
|
|
AGENTS.md ggf. durch Agenten umgeschrieben?"). Die Baseline liegt unter
|
|||
|
|
docs/sources/upstream/neckbeard-v0.1.1/ (siehe HERKUNFT.md dort); ein
|
|||
|
|
Framework-Upgrade aktualisiert Baseline und Arbeitskopie im selben,
|
|||
|
|
bewussten Commit.
|
|||
|
|
|
|||
|
|
Prüfungen (Fehler, Exit 1):
|
|||
|
|
* byte-identische Paare laut PAARE
|
|||
|
|
* AGENTS.md beginnt byte-identisch mit der Baseline-AGENTS.md und
|
|||
|
|
trägt direkt danach die Marke des Projektabschnitts
|
|||
|
|
Fehlt eine Baseline-Datei, ist das ein Fehler, kein Skip
|
|||
|
|
(Stillstandsprüfungs-Regel: eine Prüfung ohne Gegenseite ist ungeprüft).
|
|||
|
|
|
|||
|
|
Usage: python scripts/pruefe_upstream_drift.py [repo-root]
|
|||
|
|
"""
|
|||
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
import sys
|
|||
|
|
from pathlib import Path
|
|||
|
|
|
|||
|
|
BASELINE = "docs/sources/upstream/neckbeard-v0.1.1"
|
|||
|
|
MARKE = "<!-- projektabschnitt -->"
|
|||
|
|
|
|||
|
|
# (Arbeitskopie, Baseline-Datei) — byte-identisch
|
|||
|
|
PAARE = [
|
|||
|
|
("CLAUDE.md", "CLAUDE.md"),
|
|||
|
|
("WORKFLOW.md", "WORKFLOW.md"),
|
|||
|
|
("docs/adr/template.md", "templates/adr-template.md"),
|
|||
|
|
("docs/design/template.md", "templates/design-template.md"),
|
|||
|
|
("docs/aar/template.md", "templates/aar-template.md"),
|
|||
|
|
("docs/issues/template.md", "templates/issue-template.md"),
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
|
|||
|
|
def main() -> int:
|
|||
|
|
root = Path(sys.argv[1]) if len(sys.argv) > 1 else Path.cwd()
|
|||
|
|
base = root / BASELINE
|
|||
|
|
fehler: list[str] = []
|
|||
|
|
|
|||
|
|
for arbeit, original in PAARE:
|
|||
|
|
a, b = root / arbeit, base / original
|
|||
|
|
if not b.is_file():
|
|||
|
|
fehler.append(f"Baseline fehlt: {BASELINE}/{original}")
|
|||
|
|
continue
|
|||
|
|
if not a.is_file():
|
|||
|
|
fehler.append(f"Arbeitskopie fehlt: {arbeit}")
|
|||
|
|
continue
|
|||
|
|
if a.read_bytes() != b.read_bytes():
|
|||
|
|
fehler.append(f"DRIFT: {arbeit} weicht von {BASELINE}/{original} ab")
|
|||
|
|
|
|||
|
|
agents, agents_base = root / "AGENTS.md", base / "AGENTS.md"
|
|||
|
|
if not agents_base.is_file():
|
|||
|
|
fehler.append(f"Baseline fehlt: {BASELINE}/AGENTS.md")
|
|||
|
|
elif not agents.is_file():
|
|||
|
|
fehler.append("Arbeitskopie fehlt: AGENTS.md")
|
|||
|
|
else:
|
|||
|
|
upstream = agents_base.read_bytes()
|
|||
|
|
arbeit = agents.read_bytes()
|
|||
|
|
if not arbeit.startswith(upstream):
|
|||
|
|
fehler.append("DRIFT: AGENTS.md — Upstream-Teil (§1–5) ist "
|
|||
|
|
"nicht mehr byte-identisch mit der Baseline")
|
|||
|
|
else:
|
|||
|
|
rest = arbeit[len(upstream):].decode("utf-8", "replace")
|
|||
|
|
if MARKE not in rest.splitlines()[0:3]:
|
|||
|
|
fehler.append(f"AGENTS.md: Marke '{MARKE}' fehlt direkt "
|
|||
|
|
"nach dem Upstream-Teil")
|
|||
|
|
|
|||
|
|
for f in fehler:
|
|||
|
|
print(f"FEHLER {f}")
|
|||
|
|
print(f"pruefe_upstream_drift: {len(fehler)} Fehler")
|
|||
|
|
return 1 if fehler else 0
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
sys.exit(main())
|