Automatischer Push: 46 Datei(en) geändert

- .claude/agents/planer.md
- .claude/skills/plan-executer-pruefung/SKILL.md
- .claude/workflows/plankritik.js
- .claude/workflows/planung.js
- .claude/workflows/pruefung.js
- .claude/workflows/verbrauch.js
- .claude/workflows/welle-mit-pruefung.js
- .vault-tools/plan-kopie/LIESMICH.md
- .vault-tools/plan-kopie/plan_zeichen.py
- .vault-tools/plan-kopie/rot_nachweis.py
- .vault-tools/trading-plattform-pruefung/LIESMICH.md
- .vault-tools/trading-plattform-pruefung/abendkontrolle.py
- … und 34 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:
Pascal MichelandClaude Opus 5 committed 2026-09-25 04:00:02 +02:00
1 parent 67d674cd0b
commit ea278dc24f
46 files changed
+8403 -80

No files matched your search

@@ -0,0 +1,236 @@
"""Rueckweg des Paper-Runners von zehn Aktien auf AAPL, einmal, nach Pascals Vorgabe.
Koordinator-Werkzeug, nicht fuers Repo. Pascal am 2026-09-24: zehn Aktien "bis Mittwoch" -- gelesen als
bis einschliesslich Mittwoch 2026-09-30; ab Donnerstag 2026-10-01 handelt der Runner wieder AAPL mit der
Registerversion. Der Rueckweg ist der aus Paket M: config/paper-aapl-register.toml wird config/paper.toml.
Geplante Aufgabe "Trading Plattform - Rueckweg AAPL" (rueckweg_aapl_einrichten.ps1): 2026-09-30 22:50,
zweiter Versuch 2026-10-01 22:10, verpasste Termine beim naechsten Start (StartWhenAvailable).
Schritte, jeder mit seinem Grund:
1. Nicht vor FRUEHESTENS (nach Boersenschluss des letzten Tages mit zehn Aktien).
2. Ergebnisdatei ABLAGE/rueckweg.json da -> schon erledigt, nichts tun.
3. Laeuft der Runner (systemctl is-active trading-paper.service in WSL), wird nichts getauscht: Er hat
seine Konfiguration beim Start gelesen, und ein Tausch mitten am Tag wirkte erst beim naechsten Start.
Befund, der zweite Termin versucht es erneut.
Stand er, wird nach WARTEN_S noch einmal gefragt: Hat erst dieser Aufruf WSL geweckt, startet der
Zeitgeber den Runner 60 s danach (OnStartupSec=60) und liest dabei die Konfiguration.
4. Im Projektordner muss ZWEIG ausgecheckt sein, sonst Befund.
5. config/paper.toml gleich der Rueckweg-Datei: sauberer Ordner -> schon getauscht (Ergebnisdatei,
Ende); nur config/paper.toml geaendert -> halb erledigt (ein gescheiterter Commit), weiter mit 8;
sonst Befund.
6. Sonst muss der Ordner sauber sein (git status --porcelain leer), sonst Befund: Ein Commit ueber
fremde Aenderungen waere schlimmer als ein Tag mehr mit zehn Aktien. Und config/paper.toml muss die
Konfiguration mit mehreren Aktien sein (Zeile 'quelle = "folge"'), sonst Befund.
7. Jeder Schluessel aus config/paper.toml ausser den erwarteten Unterschieden (ERWARTET_ANDERS) muss
in der Rueckweg-Datei mit demselben Wert stehen, sonst Befund: Der Tausch verloere ihn still oder
schaltete ihn still um (etwa [auto_fortsetzen] aktiv = false, von Pascal gesetzt).
8. Bytes kopieren, git add, git commit (lokal; gepusht wird von der naechsten Sitzung -- ein Push aus
einer Aufgabe ohne Fenster koennte an einer Anmeldeabfrage haengen).
9. Eine Zeile in Inbox/<heute>.md unter "## Agentenprotokoll"; bei einem Befund zusaetzlich eine Meldung
mit hoher Prioritaet ueber abendkontrolle_wsl.py --meldung.
Aufruf von Hand: python rueckweg_aapl.py [--jetzt ISO] [--projekt PFAD] [--vault PFAD] [--ohne-wsl]
"""
import argparse
import json
import subprocess
import sys
import time
import tomllib
import traceback
from datetime import datetime
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from abendkontrolle import KEIN_FENSTER # noqa: E402
from abendkontrolle import WSL # noqa: E402
from abendkontrolle import WSL_PY # noqa: E402
from abendkontrolle import WSL_SKRIPT # noqa: E402
from abendkontrolle import schreibe_notiz # noqa: E402
VAULT = Path(r"D:\Claude")
PROJEKT = VAULT / "Code Projekte" / "active - Trading Plattform"
GIT = r"C:\Program Files\Git\cmd\git.exe"
FRUEHESTENS = datetime(2026, 9, 30, 22, 5)
ZIEL = Path("config") / "paper.toml"
RUECKWEG = Path("config") / "paper-aapl-register.toml"
MEHRERE = 'quelle = "folge"'
ZWEIG = "master"
ERWARTET_ANDERS = ("agent.", "umgebung.instrumente", "umgebung.instrument", "grenzen.max_tagesverlust_anteil")
WARTEN_S = 90
NOCHMAL = "Steht noch ein Termin der Aufgabe aus, versucht er es erneut; sonst entscheidet die naechste Sitzung."
NACHRICHT = (
"Rueckweg auf AAPL: config/paper.toml aus config/paper-aapl-register.toml\n\n"
"Pascal am 2026-09-24: zehn Aktien bis Mittwoch 2026-09-30. Ab 2026-10-01 handelt der Runner wieder\n"
"AAPL mit der Registerversion (Rueckweg aus Paket M). Automatisch durch die geplante Aufgabe\n"
"'Trading Plattform - Rueckweg AAPL' (.vault-tools/trading-plattform-pruefung/rueckweg_aapl.py).\n\n"
"Co-Authored-By: Claude Opus 5.5 <[email protected]>\n"
)
def git(projekt: Path, *argumente: str) -> subprocess.CompletedProcess:
return subprocess.run(
[GIT, "-C", str(projekt), *argumente], capture_output=True, text=True, encoding="utf-8",
errors="replace", timeout=120, creationflags=KEIN_FENSTER,
env={**__import__("os").environ, "GIT_TERMINAL_PROMPT": "0", "GCM_INTERACTIVE": "never"},
)
def runner_aktiv(vorgabe: str | None) -> bool:
if vorgabe is not None:
zustand = vorgabe # Angriffsfaelle: die Ausgabe von systemctl is-active, ohne WSL
else:
lauf = subprocess.run(
[WSL, "-d", "Debian", "-u", "claude", "--", "systemctl", "is-active", "trading-paper.service"],
capture_output=True, timeout=60, creationflags=KEIN_FENSTER,
)
zustand = lauf.stdout.decode("utf-8", errors="replace").strip()
if zustand in ("active", "activating", "deactivating", "reloading"):
return True
if zustand in ("inactive", "failed"):
return False
raise RuntimeError(f"Zustand des Runners nicht lesbar: {zustand!r}")
def melde(titel: str, text: str, ohne_wsl: bool) -> str:
if ohne_wsl:
return "ohne WSL, nicht gesendet"
lauf = subprocess.run(
[WSL, "-d", "Debian", "-u", "claude", "--", WSL_PY, WSL_SKRIPT, "--meldung", titel, text],
capture_output=True, timeout=120, creationflags=KEIN_FENSTER,
)
return lauf.stdout.decode("utf-8", errors="replace").strip()[-200:]
def blaetter(datei: Path) -> dict:
"""Alle Blattschluessel einer TOML-Datei als Punktpfad mit ihrem Wert."""
def ablaufen(tabelle: dict, pfad: str):
for name, wert in tabelle.items():
voll = f"{pfad}.{name}" if pfad else name
if isinstance(wert, dict):
yield from ablaufen(wert, voll)
else:
yield voll, wert
with datei.open("rb") as f:
return dict(ablaufen(tomllib.load(f), ""))
def fehlende_schluessel(ziel: Path, quelle: Path) -> list[str]:
"""Was der Tausch ausser den erwarteten Unterschieden aendern wuerde.
Projektvorgabe (Paket M, Rueckweg): Die beiden Dateien unterscheiden sich nur in [agent],
umgebung.instrumente (zehn Aktien) gegen umgebung.instrument (AAPL) und im Wert von
grenzen.max_tagesverlust_anteil (1 % gegen 0,2 %); verglichen am 2026-09-24 im Arbeitsbaum M.
Jeder andere Schluessel, der nur in config/paper.toml steht, ginge beim Tausch still verloren
(etwa [auto_fortsetzen] aus Paket AF oder etwas aus Z2), und jeder andere Wert, der sich
unterscheidet, sprang still um -- etwa auto_fortsetzen.aktiv, das Pascal in config/paper.toml
abgeschaltet hat (Befund der Plankritik AF, 2026-09-24).
"""
alt, neu = blaetter(ziel), blaetter(quelle)
befunde = []
for name in sorted(alt.keys() | neu.keys()):
if name.startswith(ERWARTET_ANDERS):
continue
if name not in neu:
befunde.append(f"{name} fehlt in der Rueckweg-Datei")
elif name not in alt:
# Die Gegenrichtung (Nachkritik AF, 2026-09-24): Hat Pascal [auto_fortsetzen] in
# config/paper.toml geloescht -- laut Task 421 ein gueltiges Abschalten --, brachte der
# Tausch aktiv = true aus der Rueckweg-Datei still zurueck.
befunde.append(f"{name} steht nur in der Rueckweg-Datei")
elif neu[name] != alt[name]:
befunde.append(f"{name} anderer Wert")
return befunde
def rueckweg(jetzt: datetime, projekt: Path, ablage: Path, runner_vorgabe: str | None) -> tuple[str, str | None]:
"""(Ergebnis fuer die Notiz, Befund oder None)."""
if jetzt < FRUEHESTENS:
return f"zu frueh ({jetzt:%Y-%m-%d %H:%M}), nichts getan", None
if (ablage / "rueckweg.json").exists():
return "schon erledigt", None
if runner_aktiv(runner_vorgabe):
return "", f"Der Runner laeuft; config/paper.toml nicht getauscht. {NOCHMAL}"
if runner_vorgabe is None:
# Hat erst dieser Aufruf WSL geweckt, startet der Zeitgeber den Runner 60 s danach
# (OnStartupSec=60) mit der Konfiguration, die er dann liest. Also warten und noch einmal fragen.
time.sleep(WARTEN_S)
if runner_aktiv(None):
return "", f"Der Runner ist eben gestartet; config/paper.toml nicht getauscht. {NOCHMAL}"
zweig = git(projekt, "rev-parse", "--abbrev-ref", "HEAD").stdout.strip()
if zweig != ZWEIG:
return "", f"Im Projektordner ist {zweig!r} ausgecheckt, nicht {ZWEIG}; nicht getauscht"
ziel, quelle = projekt / ZIEL, projekt / RUECKWEG
if not quelle.is_file():
return "", f"{RUECKWEG.as_posix()} fehlt; nicht getauscht"
status = git(projekt, "status", "--porcelain")
if status.returncode != 0:
return "", f"git status scheiterte ({status.returncode}); nicht getauscht"
geaendert = [z for z in status.stdout.splitlines() if z.strip()]
if ziel.is_file() and ziel.read_bytes() == quelle.read_bytes():
if not geaendert:
return "config/paper.toml ist schon die AAPL-Konfiguration", None
if geaendert != [f" M {ZIEL.as_posix()}"] and geaendert != [f"M {ZIEL.as_posix()}"]:
return "", f"Projektordner nicht sauber (git status: {' | '.join(geaendert)[:200]}); nicht getauscht"
# Halb erledigt: getauscht, aber nicht committet (etwa ein gescheiterter Commit beim ersten Termin).
else:
if geaendert:
return "", f"Projektordner nicht sauber (git status: {' | '.join(geaendert)[:200]}); nicht getauscht"
if MEHRERE not in ziel.read_text(encoding="utf-8"):
return "", "config/paper.toml ist nicht die Konfiguration mit mehreren Aktien; nicht getauscht, Pascal entscheidet"
fehlend = fehlende_schluessel(ziel, quelle)
if fehlend:
return "", (
f"config/paper-aapl-register.toml weicht ausserhalb der erwarteten Stellen von config/paper.toml ab "
f"({', '.join(fehlend)[:200]}); nicht getauscht, Pascal entscheidet"
)
ziel.write_bytes(quelle.read_bytes())
for schritt in (("add", ZIEL.as_posix()), ("commit", "-m", NACHRICHT)):
lauf = git(projekt, *schritt)
if lauf.returncode != 0:
return "", (
f"git {schritt[0]} scheiterte ({lauf.returncode}: {(lauf.stderr or lauf.stdout).strip()[:200]}); "
f"Datei ist getauscht, aber nicht committet. {NOCHMAL}"
)
kopf = git(projekt, "rev-parse", "--short", "HEAD").stdout.strip()
return f"config/paper.toml auf AAPL (Register) zurueckgestellt, Commit {kopf} (nicht gepusht)", None
def main(argv=None) -> int:
zerleger = argparse.ArgumentParser(allow_abbrev=False)
zerleger.add_argument("--jetzt")
zerleger.add_argument("--projekt", default=str(PROJEKT))
zerleger.add_argument("--vault", default=str(VAULT))
zerleger.add_argument("--ohne-wsl", action="store_true", help="Angriffsfaelle: keine Meldung, Runner laut --runner-zustand")
zerleger.add_argument("--runner-zustand", help="Angriffsfaelle: Ausgabe von systemctl is-active statt WSL")
argumente = zerleger.parse_args(argv)
if argumente.ohne_wsl and argumente.runner_zustand is None:
argumente.runner_zustand = "inactive"
jetzt = datetime.fromisoformat(argumente.jetzt) if argumente.jetzt else datetime.now()
projekt, vault = Path(argumente.projekt), Path(argumente.vault)
ablage = projekt / "data" / "paper" / "abendkontrollen"
ablage.mkdir(parents=True, exist_ok=True)
try:
ergebnis, befund = rueckweg(jetzt, projekt, ablage, argumente.runner_zustand)
except Exception as ausnahme:
ergebnis, befund = "", f"abgebrochen: {type(ausnahme).__name__}: {str(ausnahme)[:200]}"
with (ablage / "lauf.log").open("a", encoding="utf-8", newline="\n") as log:
log.write(traceback.format_exc())
with (ablage / "lauf.log").open("a", encoding="utf-8", newline="\n") as log:
log.write(f"{datetime.now().isoformat(timespec='seconds')} rueckweg: {ergebnis or befund}\n")
if ergebnis in ("schon erledigt",) or ergebnis.startswith("zu frueh"):
return 0
kopf = f"- {jetzt:%H:%M} Uhr — Rückweg auf AAPL (automatisch, Pascals Vorgabe: zehn Aktien bis 30.09.)"
if befund is None:
(ablage / "rueckweg.json").write_text(
json.dumps({"zeit": jetzt.isoformat(), "ergebnis": ergebnis}, ensure_ascii=False), encoding="utf-8"
)
schreibe_notiz(vault, jetzt.date().isoformat(), f"{kopf}: {ergebnis}.")
return 0
gemeldet = melde("Rueckweg AAPL nicht ausgefuehrt", befund, argumente.ohne_wsl)
schreibe_notiz(vault, jetzt.date().isoformat(), f"{kopf}: **nicht ausgeführt** — {befund} #needs-review (Meldung: {gemeldet})")
return 1
if __name__ == "__main__":
sys.exit(main())