Tracer bullet of the migration design (Gate 4, slice 1): pinned v0.1.1 baseline under docs/sources/upstream/ with provenance note, the Karpathy block moved verbatim to docs/sources/regelwerk/ (standing rule mapped onto the sources read-only mechanism), AGENTS.md assembled from the byte-true upstream sections plus the project section 6 (group rules condensed from the old CLAUDE.md), CLAUDE.md reduced to the upstream pointer, WORKFLOW.md and all four templates copied, schema.yaml extended (issue milestone/priority/status columns, component type, wiki area vision - all flagged in the header), validate.py and gen_status.py forked with marked extensions, pruefe_upstream_drift.py added, STATUS.md generated, CI gains the offline validate job, README directory link defused. Verified: validate 0 errors 0 warnings (the three pre-existing directory-link errors are gone), gen_status --check current, drift check 0 findings, baseline byte-identical to the reference checkout (10/10 files), four negative tests fire (WIP limit 3x in-progress, waiting without wartegrund, component slug mismatch, single-byte drift in WORKFLOW.md). gen_status needs Python >= 3.10 locally (write_text newline) - noted for the design AAR. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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())
|