Automatischer Push: 45 Datei(en) geändert
- .claude/agents/planer.md - .claude/agents/quorum-stimme.md - .claude/skills/bookstack-upload/SKILL.md - .claude/skills/bookstack-upload/scripts/bookstack/archiv.py - .claude/skills/bookstack-upload/scripts/bookstack/auswahl.py - .claude/skills/bookstack-upload/scripts/bookstack/beschreibung.py - .claude/skills/bookstack-upload/scripts/bookstack/bilder.py - .claude/skills/bookstack-upload/scripts/bookstack/ergebnis.py - .claude/skills/bookstack-upload/scripts/bookstack/hochladen.py - .claude/skills/bookstack-upload/scripts/bookstack/konvertierung.py - .claude/skills/bookstack-upload/scripts/bookstack/struktur.py - .claude/skills/bookstack-upload/scripts/bookstack/verweise.py - … und 33 weitere Erzeugt vom PostToolUse-Hook .vault-tools/auto-push/auto_push.py. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
1 parent
e8472409e9
commit
eb48f8822d
45 files changed
+8645
-262
No files matched your search
@@ -5,7 +5,7 @@ status: draft
|
||||
summary: "Legt waisen_bestand.py an, das verwaiste Notizen über Muster ihrem Hub zuordnet, im Probelauf nur auflistet und mit --anwenden erst sichert und dann anhängt, und faelle_waisen_bestand.py mit Git-Fällen und Rotlauf."
|
||||
tags: [plan-task, vault-tools]
|
||||
created: 2026-09-29
|
||||
updated: 2026-09-29
|
||||
updated: 2026-09-30
|
||||
modell: haiku
|
||||
modell_begruendung: "Zwei neue Dateien stehen wörtlich im Plan und werden per Skript angelegt; keine typografischen Zeichen in den Codeblöcken."
|
||||
---
|
||||
@@ -62,6 +62,11 @@ REGELN, alle über Muster, ohne Namen einzelner Projekte oder Kunden
|
||||
Code Projekte/<p>/CHANGELOG.md und jede Datei unter Code Projekte/<p>/docs/
|
||||
außerhalb von Planordnern
|
||||
eine Zeile mit relativem Link aufs Projekt-README.
|
||||
docs/plans/<ordner>/<datei>.md an der Vault-Wurzel
|
||||
wie ein Planordner in Code Projekte, aber die Zeile heißt "Vault:" und
|
||||
verlinkt README.md der Vault-Wurzel.
|
||||
jede andere Datei unter docs/ an der Vault-Wurzel
|
||||
eine Zeile mit relativem Link auf README.md der Vault-Wurzel.
|
||||
IT Workspace/**/_arbeitsstand/**
|
||||
Planordner wie oben, aber der Link nach oben ist ein Wikilink auf die
|
||||
einzige _MOC-*.md im Ordner über _arbeitsstand; jede andere Datei
|
||||
@@ -76,9 +81,10 @@ REGELN, alle über Muster, ohne Namen einzelner Projekte oder Kunden
|
||||
Alles andere kommt auf die Liste für den Koordinator. Geraten wird nichts.
|
||||
|
||||
ÜBERSPRUNGEN UND AUFGELISTET wird eine Zieldatei, die
|
||||
* in einem Git-Repo unterhalb des Vaults liegt und dort in irgendeinem
|
||||
Arbeitsbaum uncommittet geändert oder neu ist oder auf einem anderen
|
||||
lokalen Zweig seit dem gemeinsamen Stand geändert wurde,
|
||||
* in einem Git-Repo im Vault liegt, auch dem der Vault-Wurzel, und dort in
|
||||
irgendeinem Arbeitsbaum uncommittet geändert oder neu ist oder auf einem
|
||||
anderen lokalen Zweig seit dem gemeinsamen Stand geändert wurde; was das
|
||||
Repo ignoriert, zählt nicht als geändert,
|
||||
* nicht als UTF-8 lesbar ist oder gemischte Zeilenenden hat,
|
||||
* die anzuhängende Überschrift oder Linkzeile schon enthält.
|
||||
Ein Git-Repo, das sich nicht prüfen lässt, sperrt alle seine Zieldateien.
|
||||
@@ -218,6 +224,21 @@ def _dump(rel: str, teile: list, vault: Path) -> tuple:
|
||||
return ("zeile", rel, f"Tagesnotiz: [[Inbox/{tag}]]", f"Inbox/{tag}.md")
|
||||
|
||||
|
||||
def _wurzel_docs(rel: str, teile: list, vault: Path) -> tuple:
|
||||
# Pläne und Specs unter docs/ an der Vault-Wurzel: Hub ist README.md dort.
|
||||
hub = "README.md"
|
||||
if not existiert(vault, hub):
|
||||
return ("rest", "", "README.md der Vault-Wurzel fehlt", "")
|
||||
if teile[1] == "plans" and len(teile) == 4:
|
||||
kopf = "/".join(teile[:-1]) + "/00-uebersicht.md"
|
||||
if not existiert(vault, kopf):
|
||||
return ("rest", "", "Planordner ohne 00-uebersicht.md", "")
|
||||
return ("ordner", kopf, f"Vault: [README]({rel_link(kopf, hub)})", hub)
|
||||
if teile[1] == "plans" and len(teile) > 4:
|
||||
return ("rest", "", "Plandatei tiefer als ein Ordner unter docs/plans", "")
|
||||
return ("zeile", rel, f"Vault: [README]({rel_link(rel, hub)})", hub)
|
||||
|
||||
|
||||
def klassifiziere(rel: str, vault: Path) -> tuple:
|
||||
"""Liefert (art, ziel, wert, hub). art ist zeile, ordner, befund oder rest."""
|
||||
teile = rel.split("/")
|
||||
@@ -229,6 +250,8 @@ def klassifiziere(rel: str, vault: Path) -> tuple:
|
||||
return _befund(rel, teile, vault)
|
||||
if teile[:2] == ["AI", "secondbrain"] and len(teile) == 4:
|
||||
return _dump(rel, teile, vault)
|
||||
if teile[0] == "docs" and len(teile) >= 2:
|
||||
return _wurzel_docs(rel, teile, vault)
|
||||
return ("rest", "", "keine Regel passt", "")
|
||||
|
||||
|
||||
@@ -311,9 +334,12 @@ def anhang_bytes(alt: bytes, zeilen: list, ende: str) -> bytes:
|
||||
|
||||
def repo_von(vault: Path, rel: str) -> Optional[Path]:
|
||||
ordner = (vault / rel).parent
|
||||
while ordner != vault and vault in ordner.parents:
|
||||
# Auch die Vault-Wurzel kann ein Repo sein; über ihr wird nicht gesucht.
|
||||
while ordner == vault or vault in ordner.parents:
|
||||
if (ordner / ".git").exists():
|
||||
return ordner
|
||||
if ordner == vault:
|
||||
return None
|
||||
ordner = ordner.parent
|
||||
return None
|
||||
|
||||
@@ -527,6 +553,11 @@ eigener Prozess. Die Git-Fälle legen im Wegwerf-Vault ein Repo mit Zweig oder
|
||||
Arbeitsbaum an und brauchen git im PATH. Verglichen wird jede Datei des
|
||||
Wegwerf-Vaults vor und nach dem Lauf, Byte für Byte.
|
||||
|
||||
Zwei Fälle laufen über HUELLE: Sie lädt waisen_bestand.py in einen eigenen
|
||||
Prozess und setzt entweder einen fremden Schreiber ein, der nach der Sicherung
|
||||
an CHANGELOG.md anhängt, oder schreibt je git-Aufruf den Wert von
|
||||
GIT_OPTIONAL_LOCKS mit.
|
||||
|
||||
--rotlauf baut jeden Mutanten aus MUTANTEN in eine Kopie des Skripts und fährt
|
||||
die genannten Fälle dagegen. Getötet heißt: jeder genannte Fall schlägt fehl.
|
||||
|
||||
@@ -555,6 +586,9 @@ E = P + "/docs/plans/2026-01-01-eins"
|
||||
S = "IT Workspace/SEO/kunde-audit/15012026"
|
||||
X = "IT Workspace/Thema/Projekt X"
|
||||
XP = X + "/_arbeitsstand/docs/plans/2026-01-03-p"
|
||||
W = "docs/plans/2026-01-04-w"
|
||||
SPEC = "docs/specs/2026-01-04-spec.md"
|
||||
NEU = P + "/docs/plans/2026-01-09-neu"
|
||||
DUMP = "AI/secondbrain/alpha-memory/2026-01-01-thema.md"
|
||||
DUMP_OHNE = "AI/secondbrain/alpha-memory/2026-01-05-ohne.md"
|
||||
UMLAUT = "task-09-prüfung x.md"
|
||||
@@ -565,6 +599,7 @@ BEFUND_KOPF = "## Befunddateien dieses Laufs"
|
||||
ZIELE = {
|
||||
P + "/CHANGELOG.md": ["Projekt: [README](README.md)"],
|
||||
P + "/docs/code/modul.md": ["Projekt: [README](../../README.md)"],
|
||||
P + "/docs/lose.md": ["Projekt: [README](../README.md)"],
|
||||
P + "/docs/plans/2026-01-02-einzel.md": ["Projekt: [README](../../README.md)"],
|
||||
E + "/00-uebersicht.md": ["Projekt: [README](../../../README.md)", "", ORDNER_KOPF, "",
|
||||
"- [task-01-a.md](task-01-a.md)", f"- [{UMLAUT}]({UMLAUT_LINK})"],
|
||||
@@ -573,12 +608,64 @@ ZIELE = {
|
||||
X + "/_arbeitsstand/notiz.md": [f"Projekt: [[{X}/_MOC-projekt-x]]"],
|
||||
XP + "/00-uebersicht.md": [f"Projekt: [[{X}/_MOC-projekt-x]]", "", ORDNER_KOPF, "",
|
||||
"- [task-01-t.md](task-01-t.md)"],
|
||||
W + "/00-uebersicht.md": ["Vault: [README](../../../README.md)", "", ORDNER_KOPF, "",
|
||||
"- [task-01-w.md](task-01-w.md)"],
|
||||
SPEC: ["Vault: [README](../../README.md)"],
|
||||
}
|
||||
REST = {
|
||||
P + "/notizen.md": "keine Regel passt",
|
||||
DUMP_OHNE: "Tagesnotiz Inbox/2026-01-05.md fehlt",
|
||||
W + "/befunde/b1.md": "Plandatei tiefer als ein Ordner unter docs/plans",
|
||||
}
|
||||
|
||||
HUELLE = '''"""Huelle aus faelle_waisen_bestand.py: laedt waisen_bestand.py und biegt zwei Stellen um."""
|
||||
import importlib.util
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
skript, art, *rest = sys.argv[1:]
|
||||
# Die Variable darf nicht schon von aussen kommen, sonst misst der Fall die Shell.
|
||||
os.environ.pop("GIT_OPTIONAL_LOCKS", None)
|
||||
spec = importlib.util.spec_from_file_location("waisen_bestand_huelle", skript)
|
||||
modul = importlib.util.module_from_spec(spec)
|
||||
# Vor exec_module eintragen: dataclasses sucht das Modul in sys.modules.
|
||||
sys.modules["waisen_bestand_huelle"] = modul
|
||||
spec.loader.exec_module(modul)
|
||||
aufrufe = []
|
||||
echt_run = subprocess.run
|
||||
echt_copy2 = modul.shutil.copy2
|
||||
|
||||
|
||||
def run(befehl, *a, **k):
|
||||
# Git-Double: merkt sich je git-Aufruf den Wert von GIT_OPTIONAL_LOCKS.
|
||||
if befehl and befehl[0] == "git":
|
||||
aufrufe.append((k.get("env") or os.environ).get("GIT_OPTIONAL_LOCKS"))
|
||||
return echt_run(befehl, *a, **k)
|
||||
|
||||
|
||||
def copy2(quelle, ziel, *a, **k):
|
||||
# Fremder Schreiber: haengt nach der Sicherung von CHANGELOG.md etwas an.
|
||||
ergebnis = echt_copy2(quelle, ziel, *a, **k)
|
||||
if art == "fremd" and Path(quelle).name == "CHANGELOG.md":
|
||||
with open(quelle, "ab") as datei:
|
||||
datei.write(b"fremd")
|
||||
return ergebnis
|
||||
|
||||
|
||||
subprocess.run = run
|
||||
modul.shutil.copy2 = copy2
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
code = modul.main(rest)
|
||||
ohne = [wert for wert in aufrufe if wert != "0"]
|
||||
if aufrufe and not ohne:
|
||||
print("HUELLE git ok")
|
||||
else:
|
||||
print(f"HUELLE git: {len(aufrufe)} Aufrufe, {len(ohne)} ohne GIT_OPTIONAL_LOCKS=0")
|
||||
raise SystemExit(code)
|
||||
'''
|
||||
|
||||
|
||||
def schreibe(v: Path, rel: str, inhalt) -> None:
|
||||
# Immer Bytes: write_text würde unter Windows jedes LF zu CRLF machen.
|
||||
@@ -614,12 +701,14 @@ def nichts(v: Path) -> None:
|
||||
def baue_grundlinie(v: Path) -> None:
|
||||
schreibe(v, ".obsidian/app.json", '{"userIgnoreFilters": ["_index/"]}')
|
||||
schreibe(v, "Wissen/start.md",
|
||||
f"[[{P}/README]]\n[[IT Workspace/SEO/_MOC-seo]]\n[[{X}/_MOC-projekt-x]]\n")
|
||||
f"[[{P}/README]]\n[[IT Workspace/SEO/_MOC-seo]]\n[[{X}/_MOC-projekt-x]]\n[[README]]\n")
|
||||
schreibe(v, "README.md", "# Vault\n")
|
||||
schreibe(v, P + "/README.md", "# Alpha\n")
|
||||
schreibe(v, P + "/CHANGELOG.md", "# Changelog")
|
||||
schreibe(v, P + "/notizen.md", "# Notizen\n")
|
||||
schreibe(v, P + "/data/2026-01-01.md", "# Auswertung\n")
|
||||
schreibe(v, P + "/docs/code/modul.md", b"# Modul\r\n\r\nText\r\n")
|
||||
schreibe(v, P + "/docs/lose.md", "# Lose\n")
|
||||
schreibe(v, P + "/docs/plans/2026-01-02-einzel.md", "# Einzel\n")
|
||||
schreibe(v, E + "/00-uebersicht.md", "# Eins\n")
|
||||
schreibe(v, E + "/task-01-a.md", "# A\n")
|
||||
@@ -635,6 +724,10 @@ def baue_grundlinie(v: Path) -> None:
|
||||
schreibe(v, X + "/_arbeitsstand/notiz.md", "# N\n")
|
||||
schreibe(v, XP + "/00-uebersicht.md", "# P\n")
|
||||
schreibe(v, XP + "/task-01-t.md", "# T\n")
|
||||
schreibe(v, W + "/00-uebersicht.md", "# W\n")
|
||||
schreibe(v, W + "/task-01-w.md", "# T\n")
|
||||
schreibe(v, W + "/befunde/b1.md", "# B\n")
|
||||
schreibe(v, SPEC, "# Spec\n")
|
||||
schreibe(v, "Bookstack/archiv/seite.md", "# S\n")
|
||||
schreibe(v, "_index/INDEX.md", "# I\n")
|
||||
|
||||
@@ -689,6 +782,43 @@ def sauberes_repo(v: Path) -> None:
|
||||
repo_anlegen(v)
|
||||
|
||||
|
||||
def neuer_planordner(v: Path) -> None:
|
||||
# Ganz ungetrackter Ordner: im Modus normal nennt git nur den Ordner.
|
||||
repo_anlegen(v)
|
||||
schreibe(v, NEU + "/00-uebersicht.md", "# Neu\n")
|
||||
schreibe(v, NEU + "/task-01-x.md", "# X\n")
|
||||
|
||||
|
||||
def umbenannt_im_index(v: Path) -> None:
|
||||
# Der alte Pfad ab/CHANGELOG.md ohne seine ersten drei Zeichen wäre CHANGELOG.md.
|
||||
schreibe(v, P + "/ab/CHANGELOG.md", "# Alt\n")
|
||||
repo = repo_anlegen(v)
|
||||
git(repo, "mv", "ab/CHANGELOG.md", "ab/neu.md")
|
||||
# Ohne erkannte Umbenennung misst der Fall nichts.
|
||||
status = subprocess.run(["git", "-C", str(repo), "status", "--porcelain"],
|
||||
capture_output=True, stdin=subprocess.DEVNULL).stdout
|
||||
if not status.startswith(b"R "):
|
||||
raise RuntimeError(f"git meldet keine Umbenennung: {status!r}")
|
||||
|
||||
|
||||
def wurzel_repo(v: Path, ignorieren: str) -> None:
|
||||
schreibe(v, ".gitignore", ignorieren)
|
||||
git(v, "init", "-q", "-b", "main")
|
||||
git(v, "config", "core.autocrlf", "false")
|
||||
git(v, "add", ".gitignore")
|
||||
git(v, "commit", "-q", "-m", "Stand")
|
||||
|
||||
|
||||
def wurzel_ignoriert_alles(v: Path) -> None:
|
||||
# Wie die Positivliste der Vault-Wurzel: alles ignoriert außer .gitignore.
|
||||
wurzel_repo(v, "/*\n!/.gitignore\n")
|
||||
|
||||
|
||||
def wurzel_docs_offen(v: Path) -> None:
|
||||
# docs/ ist nicht ignoriert, seine Dateien sind also neu im Repo der Wurzel.
|
||||
wurzel_repo(v, "/*\n!/.gitignore\n!/docs/\n")
|
||||
|
||||
|
||||
def abbild(v: Path) -> dict:
|
||||
ergebnis = {}
|
||||
for pfad in sorted(v.rglob("*")):
|
||||
@@ -703,7 +833,7 @@ def abbild(v: Path) -> dict:
|
||||
class Fall:
|
||||
name: str
|
||||
aendern: Callable = nichts
|
||||
# probe, anwenden, zweimal, ohne_sicherung, sicherung_da, sicherung_im_vault, anwenden_abbruch
|
||||
# probe, anwenden, zweimal, ohne_sicherung, sicherung_da, sicherung_im_vault, anwenden_abbruch, anwenden_fremd
|
||||
modus: str = "probe"
|
||||
code: int = 0
|
||||
ziele: Optional[dict] = None
|
||||
@@ -715,15 +845,17 @@ class Fall:
|
||||
ueber: dict = field(default_factory=dict)
|
||||
texte: list = field(default_factory=list)
|
||||
nachher: dict = field(default_factory=dict)
|
||||
# leer: Skript direkt; fremd oder sperre: über HUELLE
|
||||
huelle: str = ""
|
||||
|
||||
|
||||
GRUNDLINIE = Fall("GRUNDLINIE", ziele=ZIELE, rest=REST,
|
||||
texte=["Waisen außerhalb der Ausnahmen vorher: 15",
|
||||
texte=["Waisen außerhalb der Ausnahmen vorher: 20",
|
||||
"Durch Anhänge mitverbunden, ohne eigene Regel: 1"])
|
||||
|
||||
FAELLE = [
|
||||
Fall("anwenden | schreibt genau die erwarteten Bytes", modus="anwenden", ziele=ZIELE, rest=REST,
|
||||
texte=["Waisen außerhalb der Ausnahmen nachher: 2"],
|
||||
texte=["Waisen außerhalb der Ausnahmen nachher: 3"],
|
||||
nachher={
|
||||
P + "/CHANGELOG.md": b"# Changelog\n\nProjekt: [README](README.md)\n",
|
||||
P + "/docs/code/modul.md": b"# Modul\r\n\r\nText\r\n\r\nProjekt: [README](../../README.md)\r\n",
|
||||
@@ -742,6 +874,13 @@ FAELLE = [
|
||||
Fall("anwenden | Befund des Zaehlers bricht ohne Schreiben ab",
|
||||
lambda v: entferne(v / ".obsidian"), modus="anwenden_abbruch", code=2,
|
||||
texte=["Bestandslauf - ABGEBROCHEN", "Ordner .obsidian fehlt"]),
|
||||
Fall("anwenden | fremder Schreiber zwischen Lesen und Anhaengen bricht ab", modus="anwenden_fremd",
|
||||
huelle="fremd", code=2,
|
||||
texte=["hat sich seit dem Lesen geändert", "Vor dem Abbruch schon angehängt (1)"],
|
||||
nachher={
|
||||
DUMP: b"# Dump\n\nTagesnotiz: [[Inbox/2026-01-01]]\n",
|
||||
P + "/CHANGELOG.md": b"# Changelogfremd",
|
||||
}),
|
||||
Fall("zeilenende | gemischte Zeilenenden werden uebersprungen",
|
||||
lambda v: schreibe(v, P + "/docs/code/modul.md", b"# Modul\r\nText\n"),
|
||||
ueber={P + "/docs/code/modul.md": "gemischte Zeilenenden"}, ohne_ziel=[P + "/docs/code/modul.md"]),
|
||||
@@ -757,6 +896,17 @@ FAELLE = [
|
||||
Fall("git | nie committete Datei zaehlt als geaendert", nie_committet,
|
||||
ueber={P + "/CHANGELOG.md": "Arbeitsbaum"}),
|
||||
Fall("git | sauberes Repo ohne Zweig wird angehaengt", sauberes_repo, ziele=ZIELE, rest=REST),
|
||||
Fall("git | ungetrackter Planordner zaehlt je Datei", neuer_planordner,
|
||||
ueber={NEU + "/00-uebersicht.md": "Arbeitsbaum"}, mit_ziel=[P + "/CHANGELOG.md"]),
|
||||
Fall("git | Umbenennung: alter Pfad ist kein eigener Eintrag", umbenannt_im_index,
|
||||
mit_ziel=[P + "/CHANGELOG.md"]),
|
||||
Fall("git | jeder git-Aufruf mit GIT_OPTIONAL_LOCKS=0", sauberes_repo, huelle="sperre",
|
||||
ziele=ZIELE, rest=REST, texte=["HUELLE git ok"]),
|
||||
Fall("git | Vault-Wurzel als Repo, ignorierte Dateien zaehlen nicht", wurzel_ignoriert_alles,
|
||||
ziele=ZIELE, rest=REST),
|
||||
Fall("git | Vault-Wurzel als Repo, docs/ nicht ignoriert", wurzel_docs_offen,
|
||||
ueber={W + "/00-uebersicht.md": "Arbeitsbaum", SPEC: "Arbeitsbaum"},
|
||||
mit_ziel=[DUMP, P + "/CHANGELOG.md"]),
|
||||
Fall("regel | Planordner ohne 00-uebersicht.md",
|
||||
lambda v: (v / E / "00-uebersicht.md").unlink(),
|
||||
mit_rest={E + "/task-01-a.md": "Planordner ohne 00-uebersicht.md",
|
||||
@@ -789,6 +939,14 @@ FAELLE = [
|
||||
Fall("regel | Dump tiefer als ein Ordner",
|
||||
lambda v: schreibe(v, "AI/secondbrain/alpha-memory/drehbuecher/2026-01-01-x.md", "# D\n"),
|
||||
mit_rest={"AI/secondbrain/alpha-memory/drehbuecher/2026-01-01-x.md": "keine Regel passt"}),
|
||||
Fall("regel | Vault-Wurzel ohne README",
|
||||
lambda v: (v / "README.md").unlink(),
|
||||
mit_rest={W + "/task-01-w.md": "README.md der Vault-Wurzel fehlt",
|
||||
SPEC: "README.md der Vault-Wurzel fehlt"},
|
||||
ohne_ziel=[W + "/00-uebersicht.md", SPEC]),
|
||||
Fall("regel | Wurzel-Planordner ohne 00-uebersicht.md",
|
||||
lambda v: (v / W / "00-uebersicht.md").unlink(),
|
||||
mit_rest={W + "/task-01-w.md": "Planordner ohne 00-uebersicht.md"}),
|
||||
]
|
||||
|
||||
ALLE = [GRUNDLINIE] + FAELLE
|
||||
@@ -822,6 +980,54 @@ MUTANTEN = [
|
||||
" if sicherung_pfad == vault or vault in sicherung_pfad.parents:",
|
||||
" if False:",
|
||||
["anwenden | Sicherungsordner im Vault"]),
|
||||
("fremde Aenderung vor dem Anhaengen nicht erkannt",
|
||||
" if pfad.read_bytes() != alt:",
|
||||
" if False:",
|
||||
["anwenden | fremder Schreiber zwischen Lesen und Anhaengen bricht ab"]),
|
||||
("GEAENDERT.txt unter anderem Namen",
|
||||
r' (sicherung / "GEAENDERT.txt").write_text("\n".join(GESCHRIEBEN) + "\n", encoding="utf-8", newline="\n")',
|
||||
r' (sicherung / "ANDERS.txt").write_text("\n".join(GESCHRIEBEN) + "\n", encoding="utf-8", newline="\n")',
|
||||
["anwenden | schreibt genau die erwarteten Bytes"]),
|
||||
("ungetrackte Ordner nur als Ordner",
|
||||
' roh = git(Path(baum), "status", "--porcelain", "-z", "--untracked-files=all")',
|
||||
' roh = git(Path(baum), "status", "--porcelain", "-z", "--untracked-files=normal")',
|
||||
["git | ungetrackter Planordner zaehlt je Datei"]),
|
||||
("ignorierte Dateien zaehlen als geaendert",
|
||||
' roh = git(Path(baum), "status", "--porcelain", "-z", "--untracked-files=all")',
|
||||
' roh = git(Path(baum), "status", "--porcelain", "-z", "--untracked-files=all", "--ignored")',
|
||||
["git | Vault-Wurzel als Repo, ignorierte Dateien zaehlen nicht"]),
|
||||
("Umbenennung als zwei Eintraege gelesen",
|
||||
' if "R" in eintrag[:2] or "C" in eintrag[:2]:',
|
||||
" if False:",
|
||||
["git | Umbenennung: alter Pfad ist kein eigener Eintrag"]),
|
||||
("git ohne GIT_OPTIONAL_LOCKS",
|
||||
' umgebung["GIT_OPTIONAL_LOCKS"] = "0"',
|
||||
" pass",
|
||||
["git | jeder git-Aufruf mit GIT_OPTIONAL_LOCKS=0"]),
|
||||
("Vault-Wurzel nicht als Repo geprueft",
|
||||
" while ordner == vault or vault in ordner.parents:",
|
||||
" while ordner != vault and vault in ordner.parents:",
|
||||
["git | Vault-Wurzel als Repo, docs/ nicht ignoriert"]),
|
||||
("docs/ an der Wurzel ohne Regel",
|
||||
' if teile[0] == "docs" and len(teile) >= 2:',
|
||||
" if False:",
|
||||
["GRUNDLINIE"]),
|
||||
("Wurzel-README nicht geprueft",
|
||||
" if not existiert(vault, hub):",
|
||||
" if False:",
|
||||
["regel | Vault-Wurzel ohne README"]),
|
||||
("Wurzel-Planordner ohne Uebersicht nicht erkannt",
|
||||
" if not existiert(vault, kopf):",
|
||||
" if False:",
|
||||
["regel | Wurzel-Planordner ohne 00-uebersicht.md"]),
|
||||
("Wurzel-Plandatei zu tief angehaengt",
|
||||
' if teile[1] == "plans" and len(teile) > 4:',
|
||||
" if False:",
|
||||
["GRUNDLINIE"]),
|
||||
("Datei direkt unter docs/ ohne Regel",
|
||||
' if innen == ["CHANGELOG.md"] or (innen[:1] == ["docs"] and len(innen) >= 2):',
|
||||
' if innen == ["CHANGELOG.md"] or (innen[:1] == ["docs"] and len(innen) >= 3):',
|
||||
["GRUNDLINIE"]),
|
||||
]
|
||||
|
||||
|
||||
@@ -905,6 +1111,9 @@ def bewerte(fall: Fall, code: int, out: str, v: Path, vorher: dict, sicherung: P
|
||||
erwartet = sorted(fall.ziele or {})
|
||||
if geaendert != erwartet:
|
||||
probleme.append(f"geaendert {geaendert} statt {erwartet}")
|
||||
liste = sicherung / "GEAENDERT.txt"
|
||||
if not liste.is_file() or liste.read_bytes() != ("\n".join(erwartet) + "\n").encode("utf-8"):
|
||||
probleme.append(f"GEAENDERT.txt fehlt oder nennt nicht genau {erwartet}")
|
||||
for rel in erwartet:
|
||||
kopie = sicherung / rel
|
||||
if not kopie.is_file() or kopie.read_bytes() != vorher.get(rel):
|
||||
@@ -918,6 +1127,13 @@ def bewerte(fall: Fall, code: int, out: str, v: Path, vorher: dict, sicherung: P
|
||||
for rel, soll in fall.nachher.items():
|
||||
if nachher.get(rel) != soll:
|
||||
probleme.append(f"{rel}: {nachher.get(rel)!r} statt {soll!r}")
|
||||
elif fall.modus == "anwenden_fremd":
|
||||
erwartet = sorted(fall.nachher)
|
||||
if geaendert != erwartet:
|
||||
probleme.append(f"geaendert {geaendert} statt {erwartet}")
|
||||
for rel, soll in fall.nachher.items():
|
||||
if nachher.get(rel) != soll:
|
||||
probleme.append(f"{rel}: {nachher.get(rel)!r} statt {soll!r}")
|
||||
elif geaendert:
|
||||
probleme.append(f"hat Dateien geaendert: {geaendert}")
|
||||
if fall.modus == "anwenden_abbruch" and sicherung.exists():
|
||||
@@ -935,7 +1151,7 @@ def lauf_fall(fall: Fall, basis: Path, arbeit: Path, skript: Path) -> tuple:
|
||||
vorher = abbild(v)
|
||||
sicherung = arbeit / "sicherung"
|
||||
argumente = ["--vault", str(v)]
|
||||
if fall.modus in ("anwenden", "zweimal", "anwenden_abbruch"):
|
||||
if fall.modus in ("anwenden", "zweimal", "anwenden_abbruch", "anwenden_fremd"):
|
||||
argumente += ["--anwenden", "--sicherung", str(sicherung)]
|
||||
elif fall.modus == "ohne_sicherung":
|
||||
argumente += ["--anwenden"]
|
||||
@@ -944,7 +1160,12 @@ def lauf_fall(fall: Fall, basis: Path, arbeit: Path, skript: Path) -> tuple:
|
||||
argumente += ["--anwenden", "--sicherung", str(sicherung)]
|
||||
elif fall.modus == "sicherung_im_vault":
|
||||
argumente += ["--anwenden", "--sicherung", str(v / "Sicherung")]
|
||||
code, out, err, dauer = fahre(skript, argumente)
|
||||
ausfuehren = skript
|
||||
if fall.huelle:
|
||||
ausfuehren = arbeit / "huelle.py"
|
||||
ausfuehren.write_bytes(HUELLE.encode("utf-8"))
|
||||
argumente = [str(skript), fall.huelle] + argumente
|
||||
code, out, err, dauer = fahre(ausfuehren, argumente)
|
||||
probleme = bewerte(fall, code, out, v, vorher, sicherung)
|
||||
if fall.modus == "zweimal" and not probleme:
|
||||
erster = abbild(v)
|
||||
@@ -1070,7 +1291,7 @@ Erwartet: `ABBRUCH: D:\Claude\.vault-tools\linkcheck\waisen_bestand.py fehlt` un
|
||||
PYTHONIOENCODING=utf-8 python D:/Claude/.vault-tools/linkcheck/faelle_waisen_bestand.py; echo "exit=$?"
|
||||
```
|
||||
|
||||
Erwartet: erste Zeile `BESTANDEN GRUNDLINIE`, keine Zeile, die mit `FEHLER` beginnt, Schlusszeile `N von N Faellen bestanden.` mit zweimal derselben Zahl, `exit=0`. Der Lauf legt Git-Repos im Temp-Ordner an und dauert deshalb länger als der Treiber aus Task 01.
|
||||
Erwartet: erste Zeile `BESTANDEN GRUNDLINIE`, keine Zeile, die mit `FEHLER` beginnt, Schlusszeile `N von N Faellen bestanden.` mit zweimal derselben Zahl, `exit=0`. Der Lauf legt Git-Repos im Temp-Ordner an und dauert deshalb länger als der Treiber aus Task 01. Meldet der Fall `git | Umbenennung: alter Pfad ist kein eigener Eintrag` die Zeile `ABSTURZ im Treiber: RuntimeError: git meldet keine Umbenennung`, erkennt das installierte git die Umbenennung nicht: nichts anpassen, melden.
|
||||
|
||||
## Schritt 4 — Rotlauf
|
||||
|
||||
|
||||
Reference in new issue
Block a user