Commit Graph

50 Commits

Author SHA1 Message Date
cce88bdcba TP14.4 als in TP41 T4 aufgegangen markiert (zt-svc-Konsolidierung)
Kein eigenständiger claude-mcp-Token mehr: in TP41 T4 (2026-09-01) zu
zt-svc umbenannt+rotiert, mcp/cloudflare/.env trägt jetzt
CF_ACCESS_CLIENT_ID/_SECRET. Quick-Index (🔜→✅), TP-Abschnitt und
Ist-Stand-Block nachgezogen; alte ".env leer"-Notiz als überholt erhalten.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-02 03:01:48 +02:00
c7e173ec5a TP42-Vorarbeit + TP41 zurückgestellt: interne Namen auf bf.emsenhuber.net
- caddy/Caddyfile: nackte *.emsenhuber.net-Aliase entfernt, nur noch
  *.bf.emsenhuber.net (Split-Horizon, zeigt auf 10.40.20.40)
- nautobot/mikrotik_routeros.j2: DNS-Static *.bf.lan → *.bf.emsenhuber.net,
  router.lan entfernt
- docs/teilprojekte.md: TP41 ⏳→⏸️ (User-Entscheid 2026-09-01, offen nur
  Gelis WARP-Client), Ist-Stand-Block mitgezogen

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-02 02:56:30 +02:00
fde9f1535a n8n-mcp SSRF-Fix: permissive + in Portainer-Stack 174 gefaltet
- WEBHOOK_SECURITY_MODE=permissive → n8n-API-Anbindung (http://n8n:5678) wieder verbunden
  (n8n_health_check success:true); Blocker war der app-eigene SSRF-Guard, nicht Netz/Bearer.
- Waisen-Container aus homelab-cline/n8n-mcp-deploy in Portainer-Stack 174 (n8n) gefaltet;
  n8n/redis ohne Downtime, Bearer/Port/Volume erhalten. Orphan-Ordner entfernt.
- SSoT-Mirror docs/macmini-vlan20/stacks/ (gitignored) + Rollback-Backup.
- TP30 Posten #8: N8N_SMTP_PASS beim Stack-Read geleakt (5. Maskierungs-Panne) → Rotation fällig.
- INVENTORY + Handoff aktualisiert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-01 21:04:11 +02:00
46e6a54ecb TP41 abschließen: Google/GitHub ✅, FB abgesagt; Geli CF-seitig fertig (zt-humans-Enrollment + geli-Policy live geprüft)
- T5 durch: GitHub- und Google-Login laufen (User-bestätigt); Google via Consent-Fix External.
- Facebook/Meta für TP41 abgesagt (optional, kein CF-IdP, nichts aufzuräumen).
- Geli in WARP: CF-seitig nichts zu tun — "Warp Login App" → bf-users → zt-humans enthält
  Gelis Mails bereits; Rest = Device-Handgriff (WARP-Client, Team emsenhuber, OTP/Google).
- Permission-Frage beantwortet: keine nötig; /access/seats per Account-Token gesperrt (10405,
  Schema-Grenze, kein Scope-Fix). d47435-Revoke ✅, T3-WARP-Client-Verify ✅.
- Optionaler Security-Hinweis vermerkt: geli-Policy OR-Include CGNAT 94.154.138.0/24.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-01 20:42:41 +02:00
403b4528b2 TP41-Follow-up: App-Launcher D1 (3 Bookmark-Kacheln + Styling), Geli pillepalle670 in zt-humans; TP43 (dw-DNS-Uplink) angelegt; IdP-Kurzanleitungen (Google/Meta)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-01 20:22:27 +02:00
c543819a90 TP41: T5-Anleitung (IdP-Callbacks) + TP30 Posten #7 (Terpene-Keystore-PW-Leak)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-01 19:20:52 +02:00
012397f194 TP41: T4/T3/T2 durch (zt-svc, WARP-intern .36/.37, vw/admin 404 origin); Token-Altlast geklärt; TP42 angelegt
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-01 19:19:52 +02:00
284df839db TP41 angelegt: CF-Access-Reparatur + ZT-Konsolidierung (Kern live, Handoff)
Live via CF-API erledigt: Session 720h, login_method-Loch zu (bf-users
email-only christoph+geli), zt-Gruppen (humans/home/automation), vw voll
Bypass + vw/admin per WAF geblockt (CF-Edge + Mobilfunk verifiziert),
API-Token auf vollstaendiges Token konsolidiert.

Offen (an neue Session uebergeben): T4 zt-svc (kumulatives Service-Token +
Terpene-Migration), T3 WARP-interne Aufloesung, T5 GitHub/Google-Callback in
den Provider-Konsolen (der eigentliche OTP-Fix), T2 404-Variante, T6 Rate-Limit.

Handoff: docs/handoff-20260901-tp41.md

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-01 16:11:12 +02:00
07b595c45a TP25 Fund E: Hebel 1 widerlegt und zurueckgebaut -- Ringpuffer-Messfehler korrigiert
Zwei Sessions haben denselben Fall bewertet und kamen zu entgegengesetzten
Schluessen. Aufgeloest zugunsten der Kollektor-Messung.

Der Widerspruch und sein Beleg:
- Die Nacht-Session las `get_log ... sinceMinutes=1440` -> total 0 und schloss
  auf "Fund E geheilt, Hebel 1 committen". Das ist der FLUECHTIGE Ringpuffer des
  Routers: live nachgemessen 1000 Zeilen, aeltester Eintrag 01.09. 00:38:58 --
  keine 9 h Tiefe. Der Core-Reboot 14:36 hatte ihn geleert, der 31.08. Vormittag
  war darin nicht enthalten. "total 0" hiess "im Puffer nichts", nicht "in 24 h
  nichts" -- genau die Falle, wegen der am 30.08. der Kollektor gebaut wurde.
- Im Kollektor stehen fuer 08:09-14:36 (Hebel 1 ALLEIN, vor dem Upgrade) 124x
  reauthenticating: 09h=1, 11h=2, 12h=20, 13h=31, 14h=70 -- alle vom iPhone
  allein, also Client-Befund nach der eigenen Merkregel. Dazu Christophs zwei
  erlebte Ausfaelle 13:16 und 14:23. Zwischen 09:00 und 14:36 lag kein Reboot.

Daraus gehandelt (User-Entscheid: symmetrisch am Geraet, jetzt):
- Backup pre-tp25-funde-rollback, dann ft-over-ds=yes + remote-cap provision
- Rueckbau-Diff zeigte genau eine Abweichung, kein Kollateral
- Abnahme: CAPs durchgehend Ok, ap2 9/9 und ap3 9/9 running, frische DHCP-Lease
  (~1 min alt), Transaktion "zurueckgebaut", Compliance 140/140
- Der Rueckbau IST das Experiment: bleibt es ruhig, war 7.24.1 die Ursache;
  kehrt das Haemmern zurueck, hatte die Nacht-Session recht. Bis zur Messung
  am 2026-09-02 frueh committet niemand.

Zwei Nebenbefunde:
- gc-configplan.py --refresh-compliance scheitert STILL ohne NAUTOBOT_TOKEN:
  Meldung ausgegeben, aber Exit-Code 0. Gehoert gefixt.
- Compliance ist 140/140, nicht 135/135: es gibt eine 28. ComplianceRule
  `interface-veth`, angelegt 31.08. 20:04, Urheber offen.

Der ap2-Befund der Nacht-Session (2 m Abstand, -80 dBm, 0 Clients auf ap2)
bleibt unberuehrt gueltig und ist weiter der beste Hinweis auf die
23:02-Stoerung. CLAUDE.md enthaelt in diesem Commit auch deren TP16.3-Zeile
(gemeinsame Datei, Hunks nicht trennbar).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 09:21:46 +02:00
724cfd9a98 Stand der Parallelsession eingesammelt (TP39 archiviert, TP41-Backup, TP25 ap2-Verdacht)
Diese Aenderungen stammen NICHT aus dieser Session. Sie lagen seit 01:41 uncommittet
im gemeinsamen Working Tree, in dem parallel mehrere Sessions schreiben -- jedes
read-modify-write haette sie stillschweigend ueberschreiben koennen. Daher hier
unveraendert gesichert, bevor irgendetwas anderes passiert.

Inhalt:
- TP39 (LXC-Hygiene pve) abgeschlossen und nach teilprojekte-archiv.md verschoben
- TP41-Cloudflare-Backup unter docs/cf-backup/tp41-20260901/
- handoff-20260901-tp25-ap2-verdacht.md: Befund, dass ap2 unterperformt
  (iPhone 2 m entfernt, aber -80 dBm; 0 Clients auf ap2 gegen 29 auf ap3).
  Dieser Teil ist wertvoll und unabhaengig -- er erklaert Christophs
  23:02-Stoerung vom 31.08.

WARNUNG zum TP25-Teil: der hier eingesammelte Stand wertet Fund E als "Hebel 1
wirkt DOCH, commit-bereit". Diese Wertung ist ueberholt -- sie beruht auf einer
Messung im fluechtigen Router-Ringpuffer. Korrektur folgt im naechsten Commit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 09:20:03 +02:00
3f95a7adf3 TP16.3 §6 Abbau durch, TP GESCHLOSSEN (User zog §6 vor)
Die 7-Tage-Frist wurde auf User-Entscheid aufgehoben ("es wird nichts mehr
sein"). Reihenfolge Container -> Tunnel eingehalten (umgekehrt gaebe es 530er).

Vorbedingung geprueft: alle vier Namen auf bf-public, kein Name mehr an den
Alttunneln -> Abbau gefahrlos.

7 Container entfernt, per exakter Namensliste (nicht per Filter):
  LXC 400 (pve): cloudflared-bfmm, cloudflared-bfnas
  macmini:       cloudflared-bfpve, cloudflared-bfnas
  NAS ep14:      cloudflared-bfpve, cloudflared-bfmm
  plus terpene-cloudflared -- auf zusaetzlichen User-Entscheid, weil
  420.teilzeitladen.xyz jetzt ueber Caddy/CF laeuft. Kein Stack dahinter, also
  kein Wiederauferstehen.

Beweis VOR der Tunnel-Loeschung: 420.teilzeitladen.xyz lieferte mit bereits
entferntem terpene-cloudflared echten Origin-Inhalt (assetlinks-JSON, 200) --
der Dienst haengt also nicht mehr am Tunnel.

4 Tunnel geloescht: bf-mm, bf-nas, bf-pve, terpene-db -- jede ID gegen die
Behalten-Liste (bf-public, fm) geprueft.

Schlusskontrolle: nur noch bf-public (12) + fm (4) healthy; alle vier BF-Namen
und 420 weiterhin 200.

Der terpene-db-Tunnel-Token stand kurz im docker-inspect-Output; mit der
Tunnel-Loeschung ungueltig, kein Rotationsbedarf.

TP16.3 damit vollstaendig abgeschlossen (Status ✅ 2026-09-01). Quick-Index,
Abschnittsheader, §6-Record, Ist-Stand, Runbook §6 und Handoff nachgezogen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 01:08:34 +02:00
335c562323 TP39 abgeschlossen (skip-name-resolve + Resize), TP40 angelegt (HA-Recorder)
SKIP-NAME-RESOLVE (letzter offener TP39-Punkt, jetzt zu)
mysql.user gelesen (User gab DB-Zugang per /root/.my.cnf): KEIN Grant lautet auf
einen DNS-Hostnamen -- alle % / IP-Literal / localhost. skip-name-resolve kann
also niemanden aussperren; der Reverse-Lookup war reiner Ballast. Gesetzt als
eigenes Drop-in /etc/mysql/mariadb.conf.d/90-skip-name-resolve.cnf (nicht die
#-Zeile in 50-server.cnf, Paket-Update-stabil), @@skip_name_resolve=1 nach
Neustart verifiziert. Wirkung: gitea/vw/hass je 0 von 12 frischen Anfragen
langsam, max 0,25 s -- die Ursache ist damit beseitigt, nicht nur entschaerft.

RESIZE (im selben Fenster aufgetaucht)
LXC 302 war zu 100% voll (62/65 GB). Rootfs +30G online gewachsen -> 95 GB / 69%,
MariaDB lief durch. Puffer, kein Fix: 59 GB davon sind die homeassistant-DB.

TP40 ANGELEGT (User-Okay): HA-Recorder-Retention
states.ibd = 41 GB, unbegrenzt gewachsen (kein purge_keep_days wirksam). Scope:
purge_keep_days setzen (Christophs Policy-Zahl), rauschende Entities excluden,
purge mit repack -- danach TP39-Resize neu bewerten. Kein eigenmaechtiges
Loeschen: purge wirft echte Historie weg.

TP30 um zwei Posten erweitert
#5 Nautobot-Tokens (Leak 08-31, in der Liste bisher nur im Fliesstext).
#6 MariaDB root-Passwort: heute ins Transkript geraten -- die .my.cnf trug
"password <wert>" OHNE =, die Feld-Maskierung ankerte auf = und griff nicht.
Dritte Panne derselben Klasse nach SHELLY_DEVICE_PW und den Nautobot-Tokens;
Merkregel (Schluesselnamen ankern, nie ein evtl. fehlendes Trennzeichen) im
TP30-Text nachgeschaerft. #6 ist zugleich der billigste Posten -- kein externer
Konsument, die Dienste nutzen eigene DB-User.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 00:57:31 +02:00
3ea8d050d2 TP39: networking.service in vier LXCs repariert (Ursache = VLAN1-Altlast)
101 iob-master, 102 mqtt5, 106 influxdb2, 107 redis meldeten networking.service
und ifupdown-wait-online.service dauerhaft als failed, bei funktionierendem Netz.
Folge: alles mit After=network-online.target startet nach einem Reboot nicht --
influxdb2 kam gestern Nacht nicht hoch (Unit enabled, kein Startversuch im
Journal).

URSACHE, und es ist dieselbe Altlast wie beim toten Resolver:
in /etc/network/interfaces standen noch auto-Stanzas aus dem alten VLAN1-Schema
(eth0 -> 10.40.41.x, teils mit gateway 10.40.41.254) sowie aus frueheren
Versuchen (veth16, veth24, ein Tippfehler eth01) -- alle auf Interfaces, die es
im Container gar nicht gibt. ifup -a scheitert daran, waehrend das echte veth20
sauber hochkommt. Der VLAN-Umzug hat die Container umgehaengt, aber die alten
Stanzas nie entfernt.

FIX: nur Stanzas entfernt, deren Interface in ip -br link fehlt; lo, veth20 und
veth20.2 unangetastet. Backup je Container: /etc/network/interfaces.bak-20260901.

ABNAHME war ein echter Reboot, nicht systemctl is-active: 106 neu gestartet,
influxdb kam nach 5 s VON SELBST hoch, networking active, null failed units.
Endstand ueber alle 13 LXC: dns=10.40.20.1 durchgehend, networking ueberall
sauber. Ohne Netzbezug bleiben run-rpc_pipefs.mount (101, 150) und
proxmox-regenerate-snakeoil.service (108), beide vorbestehend.

MESSFALLE, mit in CLAUDE.md aufgenommen: nc -z meldete waehrenddessen neun
Dienste gleichzeitig als "Port zu" -- inklusive des SSH-Ports, ueber den diese
Session gerade arbeitete, waehrend curl vom selben Host HTTP 200 in 24 ms bekam.
Bei "alles gleichzeitig kaputt" zuerst das eigene Werkzeug verdaechtigen. Es
waere um ein Haar die zweite falsche Ausfallmeldung dieser Nacht geworden.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 00:39:19 +02:00
83bcfaabd0 TP39 angelegt: LXC-Hygiene auf pve (User-Okay 2026-09-01)
Fasst die zwei Restpunkte aus dem Wartungsfenster der Nacht zusammen, statt sie
auf zwei TPs zu verteilen -- beides betrifft dieselben pve-LXCs und wird in einem
Fenster erledigt:

1. skip-name-resolve auf der MariaDB. Der Reverse-Lookup ist heute nur schnell
   (21-24 ms statt 10.010 ms), nicht abgeschafft. Vorher mysql.user lesen:
   Hostname-basierte Grants brechen sonst und sperren vw/HA/gitea aus.
   Blocker: DB-Credentials noch nicht lokalisiert (Bezug TP30).
2. networking.service + ifupdown-wait-online.service sind in 101/102/106/107
   dauerhaft failed, bei vorhandenem Netz. Folge: alles mit
   After=network-online.target startet nach einem Reboot nicht -- belegt an
   influxdb2, das nach dem Neustart nicht hochkam (Unit enabled, kein
   Startversuch im Journal). 101 wurde nie angefasst und zeigt dasselbe, es ist
   also vorbestehend.

Dazu der Resolver-Sweep als wiederkehrende Kontrolle statt Einmalaktion: derselbe
Fehlertyp wurde 2026-07-10 (TP14.2a) an NAS und LXC 400 behoben, aber nie im
Bestand gesucht -- deshalb lag er hier noch. Die NAS-Container gehoeren mit
geprueft (DSM-Fallstrick: Interface-DNS != was dockerd liest).

Quick-Index, TP-Abschnitt und Ist-Stand-Block mitgezogen; Handoff verlinkt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 00:29:13 +02:00
73fec72abe TP16.3 §5 durch: vier Namen auf bf-public + 10-Sekunden-DNS-Fund behoben
FLIP (User-Freigabe, vorgezogen)
n8n / gitea / hass / vw laufen jetzt ueber bf-public, der oeffentliche Verkehr
geht damit erstmals ueber Caddy statt an ihm vorbei. Je Name einzeln geflippt und
dazwischen gemessen; Antwortzeiten vorher/nachher unveraendert. Nachweise:
gitea echte Gitea-Antwort, hass WebSocket 101 Switching Protocols (der
Companion-App-Pfad, den das Runbook als "nur vom User pruefbar" fuehrte),
vw /alive + /api/config 200 und WS-Hub 401 von Vaultwarden selbst, n8n vom User
im Browser bestaetigt (von aussen nicht bis zum Origin pruefbar, s. TP14.4).
Die drei Alttunnel bleiben als Rueckfallebene stehen -- §6 ist NICHT Teil davon.

10-SEKUNDEN-ZOLL AUF gitea/vw/hass -- Ursache gefunden und behoben
gitea hing bei ~10% der Anfragen exakt 10,1 s, quer ueber Web-UI, /api/healthz
und den Git-Pfad. MariaDB (LXC 302) hatte skip-name-resolve auskommentiert und
machte bei JEDER NEUEN Verbindung einen Reverse-Lookup, waehrend ihr resolv.conf
auf den toten 10.40.41.254 zeigte: 10.010 ms je Lookup, Pool-Verbindungen
schnell -- daher wirkte es sporadisch. An derselben DB haengen Vaultwarden, Home
Assistant und gitea (per Verbindungstabelle belegt, nicht vermutet; die erste
Annahme "vaultwarden nutzt SQLite" war falsch und wurde vom User korrigiert).
Fix: nameserver 10.40.20.1 + Reboot fuer fuenf LXCs (302, 102, 106, 107, 150).
Nachher 21-24 ms und 0 von 25 Proben langsam.
Offen: skip-name-resolve selbst -- bricht Hostname-basierte Grants, vorher
mysql.user lesen (DB-Zugang fehlt).

LATENT, NICHT VON DIESER SESSION VERURSACHT
networking.service + ifupdown-wait-online.service sind in 101/102/106/107
failed; influxdb2 kam nach dem Reboot nicht hoch (Unit enabled, kein
Startversuch im Journal). 101 wurde nie angefasst und zeigt dasselbe -- die
Container liefen nur 13+ Tage ohne Neustart.

RUNBOOK-KORREKTUREN
§5.3 "Caddy sieht den Request" konnte nie funktionieren: im Caddyfile steht keine
log-Direktive, ein erfolgreicher Request hinterlaesst nichts. Ersetzt durch die
Werkzeuge, die tatsaechlich etwas beweisen -- erzwungener oeffentlicher Weg per
curl --resolve (Pflicht wegen Split-Horizon), Verbindungstabelle am Core statt
Firewall-Zaehler (cloudflared haelt die Origin-Verbindung offen, der Zaehler
steht still obwohl alles laeuft), Antwort-Fingerabdruck, WebSocket mit --http1.1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 00:25:39 +02:00
f6283fd813 TP16.3 §5: die sechs AP-Drifts ins Soll, 28. Regel interface-veth
veth / ip address / ip firewall nat der drei cloudflared-Connectoren standen seit
der Vor-Ort-Session per Direkt-Write am Geraet (Runbook §3.4), waehrend /ip address
und /ip firewall unter GC-Drift-Kontrolle stehen: sechs extra-Drifts, Compliance
128/135. Sie sind inhaltlich richtig und sollen DAUERHAFT gelten -- deshalb ins
Template und nicht in eine gc-transaktion (die ist fuer befristete Versuche).
Kein Re-Baseline, kein Rueckbau, keine Zeile aufs Geraet: nur die SoT nachgezogen.

Neu ist die 28. ComplianceRule interface-veth. Vorher gab es fuer /interface veth
keine Regel -- das tragende Stueck des ganzen Aufbaus haette geloescht werden
koennen, ohne dass irgendetwas meldet.

Zwei Funde:

(a) Der veth-Export traegt zwei geraetevergebene MACs (mac-address,
    container-mac-address), auf jedem AP anders. Eine nackte Regel haette damit
    Dauer-Drift auf allen drei APs erzeugt, also genau die immer-rote Zahl, die
    niemand mehr liest. Zwei eng auf die veth-Zeile verankerte ConfigReplace-Regeln
    normalisieren sie im Backup (Lookbehind haelt container-mac-address heraus,
    [^\n]*? haelt die Regel in der Zeile; Selbsttest mit Negativfaellen im Skript).
    Bewusst mit der vorhandenen Maske <<REDACTED>> statt einer eigenen: sie ist im
    Repo zugleich die Push-Sperre (gc-configplan.py verweigert config_set damit) --
    eine Zeile mac-address=<<...>> darf nie aufs Geraet.
    Kostet Backup-Treue: die veth-MACs stehen in bf-golden-config nicht mehr im
    Klartext. Vertretbar, RouterOS vergibt sie beim Neuanlegen ohnehin neu.
    Verworfene Alternative: MACs je Geraet modellieren -- widerspricht der
    Begruendung, die fuer die VAP-MACs schon im ConfigContext-Skript steht.

(b) Der erste Compliance-Lauf meldete SUCCESS und war trotzdem unvollstaendig:
    139 statt 140 Eintraege, crs326-core/interface-veth fehlte, im Job-Log
    "RENDER COMPLIANCE TASK GROUP failed: Broken pipe". Zweiter Lauf sauber.
    Merkregel im Runbook (Falle 16): Abnahme ist die ANZAHL der Eintraege
    (Regeln x Geraete), nicht die Konformitaetsquote.

Stand danach: 139/140. Uebrig bleibt genau crs326-core/wifi-security -- die offene
Transaktion TP25-fund-e-ft-over-ds einer laufenden Messung, die bleiben muss.

Ausserdem: frischer Ingress-Snapshot von bf-public vor §5 und das geschaerfte
§5.1-Erfolgskriterium (200 mit leerem Body + server: Caddy = Strecke bewiesen,
404 = Ingress-Regel fehlt) -- am Live-System gemessen, nicht angenommen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 20:13:47 +02:00
e474e5e38a Merge main + nervous-williams; Drift-Zuschreibung korrigiert
Der Branch enthaelt jetzt origin/main (0680cca, TP25 Fund E / TP27) und
die Korrektur c8b2a15 aus claude/nervous-williams-acf000.

Inhaltliche Korrektur an meinen eigenen Dateien
- Ich hatte die wifi-security-Drift (ft-over-ds=no auf sec-main) dem
  7.24.1-Upgrade zugeschrieben. Falsch: gc-transaktion.py status fuehrt
  TP25-fund-e-ft-over-ds als OFFEN -- der Hebel wurde 08:09 bewusst
  gesetzt, der Core erst 14:36 gehoben. Sie gehoert einer laufenden
  TP25-Session, braucht keine Entscheidung und darf nicht gruen gemacht
  werden. Korrigiert im §5-Prompt und im §2/§3-Handoff.
- Merkregel in CLAUDE.md: vor jeder Drift-Bewertung gc-transaktion.py
  status lesen. Dazu die Abgrenzung Transaktion (befristeter Versuch)
  vs. Soll/Template (Dauerzustand) -- die sechs AP-Drifts aus TP16.3
  §3.4 sind Dauerzustand und gehoeren deshalb ins Template, nicht in
  eine Transaktion.
- Notiert: gc-transaktion.py findet den Token aus einem Worktree heraus
  nicht (210-nautobot.yml liegt nur im Haupt-Checkout); die
  Transaktionsliste kommt trotzdem, nur die Compliance-Spalte fehlt.

Konflikt in teilprojekte.md (ROS-7.24.1-Zeile) zusammengefuehrt statt
eine Seite zu verwerfen: TP27-Erledigung samt Zeitstempeln aus main plus
die npk-Folge fuer TP16.3 aus diesem Branch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 19:34:40 +02:00
17e8e9f72e Merge remote-tracking branch 'origin/claude/nervous-williams-acf000' into claude/stoic-khayyam-09b644 2026-08-31 19:33:14 +02:00
c8b2a15d5f Korrektur: die wifi-security-Drift ist TP25 Fund E, nicht das Upgrade
Ich hatte die 134/135 dem 7.24.1-Upgrade zugeschrieben. Falsch. Auf main steht
a0a650e "TP25 Fund E Hebel 1: ft-over-ds=no auf sec-main, Messung laeuft" --
der Hebel wurde am 2026-08-31 um 08:09 bewusst gesetzt, der Core erst um 14:36
gehoben. gc-transaktion.py status fuehrt TP25-fund-e-ft-over-ds als OFFEN
(Scope wifi-security, Ablauf 2026-09-03, Drift im Scope).

Die 134/135 sind also Absicht, kein Schaden, und brauchen keine Entscheidung
von Christoph -- sie gehoeren einer anderen, laufenden Session. Gruen machen
wuerde den Versuch unsichtbar machen.

Lehre, in beiden Dateien festgehalten: vor jeder Drift-Bewertung
gc-transaktion.py status lesen. Drift aus einem laufenden Versuch sieht
identisch aus wie ein Versehen -- genau dafuer existiert das Werkzeug, und ich
habe es nicht benutzt.

Handover-Punkt 5.1 von "braucht eine Entscheidung" auf "nicht anfassen"
umgestellt, Abnahme-Checkliste entsprechend.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 19:31:19 +02:00
6f6fa71ffa TP38 bestaetigt + Uebergabeprompt fuer TP16.3 §5 (CNAME-Flip)
- TP38 (OOB-Mgmt, untagged-VLAN99-Port je Switch): Nummer von Christoph
  bestaetigt, Herkunft des Nummernwechsels im TP-Abschnitt vermerkt.
- Neu: docs/tp16.3-paragraph5-session-handoff-prompt.md -- fertiger
  Prompt fuer die Flip-Session, nach der Konvention der drei bereits
  vorhandenen *-session-handoff-prompt.md.
  Enthaelt als erste Auflage die offene Drift-Entscheidung (128/135),
  die vor dem ersten Flip fallen muss.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 16:24:18 +02:00
60360fc3cc TP16.3 §2/§3 durch: cloudflared auf ap1/ap2/ap3, bf-public healthy mit 12 Connectoren
Merge von claude/nervous-williams-acf000 (d5b3ce3) plus Ergebnis der
Vor-Ort-Session vom 2026-08-31.

Ergebnis
- je ein cloudflared 2026.6.1 auf ap1/ap2/ap3, bf-public healthy/12
  (vorher 0 Connectoren), Flash je AP 54-55 MiB frei, WLAN zurueck.

Drei Runbook-Fehler aufgedeckt und korrigiert (§2.2, §3.3, §3.5, §8)
- Flash-Budget war Faktor 2,5 zu optimistisch: cloudflared entpackt
  69,5 MiB (gemessen mit docker export), nicht 28 MB -- das offizielle
  Image passt auf keinen der drei APs. Ersatz: eigenes FROM-scratch-Image
  mit 35,3 MiB aus dem statisch gelinkten Binary, Binary-SHA e93824f6
  gepinnt, Neubau byte-identisch. tools/build-cfd-image.py.
- docker save schreibt seit Docker 25 OCI statt docker-v1 -> RouterOS
  meldet "no config found in manifest". tools/oci2docker.py als Konverter.
- /container/envs nimmt list=, nicht name= (auch MikroMCPs
  manage_container_env ist dadurch fuer dieses Feld unbrauchbar).

Weitere Funde
- Der device-mode-Bestaetigungs-Boot installiert keine Pakete; erst
  Paket-Reboot, dann device-mode.
- "A - AVAILABLE" in /system package print ist ein Download-Katalog,
  kein Paket auf dem Geraet (Gegenprobe am Core: 2,9 MB frei, listet
  10,1 MB wifi-qcom als verfuegbar).
- MikroMCPs export_config exportiert unvollstaendig (301 B statt 6,2 KiB).

Offen und entscheidungsbeduerftig
- Compliance 128/135: §3.4 verlangt Direkt-Writes fuer ip address/nat,
  die unter GC-Kontrolle stehen -> sechs neue extra-Drifts, zwei je AP.
  Inhaltlich richtig, gehoeren ins Soll -- kein Re-Baseline, kein Rueckbau.
- Zwei Nautobot-Tokens sind in dieser Session ins Transkript geraten
  (unzureichende sed-Maskierung) -> Rotation noetig, TP30. Merkregel in
  CLAUDE.md ergaenzt.

Merge-Konflikte aufgeloest
- Nummernkonflikt: beide Branches hatten ein TP37. main behaelt TP37
  (Nautobot als Netzwerkdoku, User-Okay 08-30), OOB-Mgmt wird TP38.
  Braucht noch Christophs Okay.
- Drei CF-Rollback-Snapshots hatten gleichen Namen bei verschiedenem
  Inhalt -> aelterer Stand als *-vor-hostname-schnitt.json erhalten,
  keiner verworfen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 16:15:13 +02:00
0680ccabc8 TP25 Fund E: Hebel 1 gescheitert, TP27 durchgezogen, Fund B entwarnt
Zwei von Christoph gemeldete Ausfaelle (13:16 Terrasse, 14:23 Arbeitszimmer)
stehen im Kollektor und tragen dieselbe Signatur: Reauth-Schwall, dann ein
Loch von 7 bzw. 5,5 Minuten. Beide liegen NACH dem Hebel von 08:09.

- Hebel 1 (ft-over-ds=no) hat nicht gegriffen: 124x reauthenticating nach
  dem Eingriff, Stundenvergleich auf gleicher Firmware 07h=79 vs 14h=70.
  Erfolgskriterium war ~0. Gewertet wird nur 08:09-14:36 (Christoph-Entscheid),
  danach kommt das Upgrade als zweite Variable dazu. Transaktion bleibt OFFEN,
  Compliance bleibt bewusst 134/135.
- TP27 erledigt: Flotte einheitlich auf 7.24.1 (ap2 08:56, core 14:36,
  ap1 14:50, branch 14:52; ap3 kam bereits so). Nach dem Upgrade live geprueft:
  3 CAPs Ok, 4 Provisioning-Regeln, ap2 9x running, 30 Clients, ft-over-ds=no
  hat den Reboot ueberlebt.
- Fund B entwarnt: die 13 CAP-joined / 4 activity timeout waren die
  Upgrade-Reboots, keine CAPWAP-Instabilitaet. Neuer Gotcha: ein Burst ueber
  VIELE MACs ist Infrastruktur, ueber EINE MAC ein Client.
- Zweiter Gotcha: die cap-wifiN-Karte verschiebt sich bei JEDEM Rejoin, nicht
  nur beim Provisionieren -- sie wanderte an einem Tag zweimal, womit die
  Tabelle im Vormittags-Handoff nach sechs Stunden falsch war. Interface-Namen
  in Logzeilen sind ohne zeitnahen Snapshot nicht zuschreibbar.
- Offen fuer die naechste Session: Hebel 2 (ft=no) ODER wpa2-psk,wpa3-psk --
  sec-main ist auch die einzige SSID ohne wpa2-psk, und "association rejected,
  no cached PMK" (157x am 31.08., 0x am 30.08.) ist eine SAE/PMKSA-Meldung.
  Vorher pruefen, ob 7.24.1 das Verhalten schon veraendert hat.
- wifi-p750w-coverage-and-map.md ist vom 2026-07-02 und als Coverage-Beleg
  unbrauchbar (vor CAPsMAN-Cutover, vor ap2-Umzug, vor ap3).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 15:27:57 +02:00
d5b3ce37ff TP37 angelegt: Out-of-Band-Management, ein untagged-VLAN99-Port je Switch
Auslöser (User 2026-08-31): beim Core-Neustart war crs326-branch nicht mehr
erreichbar, weil sein Management ausschliesslich ueber den Core laeuft.

Live nachgemessen: auf dem Branch ist vlan99 tagged=ether1,ether24,bridge mit
untagged="" - es gibt also keinen Weg zu 10.40.99.2, der nicht durch den Core
fuehrt. Wer den Core zerkonfiguriert, verliert den Branch gleich mit und damit
die Moeglichkeit, es vom Branch aus zu reparieren.

Zweiter, unangenehmerer Befund: crs326-branch hat GAR KEINE input-Regeln (Kette
leer). Sein gesamter Schutz besteht heute darin, dass VLAN99 nur ueber den Core
erreichbar ist und dessen forward-Kette deny-by-default faehrt - die
Erreichbarkeitsbeschraenkung IST die Zugangskontrolle. Damit ist ein untagged
MGMT-Port ein physischer Generalschluessel, und das TP traegt eine explizite
Auflage: Port disabled im Normalbetrieb ODER input-Regeln auf beiden Switches
ODER physische Sicherung. Empfehlung im Abschnitt: die input-Regeln, weil sie
eine Luecke schliessen, die unabhaengig von diesem TP besteht.

Kandidat ether23 - auf core und branch beide running=false, also frei, und auf
beiden Geraeten dieselbe Nummer.

Abnahme im Abschnitt so formuliert, dass sie den Zweck prueft: Laptop an
branch ether23, Core-Trunk gezogen, 10.40.99.2 muss antworten. Alles andere
misst nur den Normalfall.

Quick-Index (nach TP36 einsortiert), TP-Abschnitt und Ist-Stand mitgezogen;
Handover 20260831 auf den angelegten TP umgestellt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 15:05:31 +02:00
452ea53576 ROS 7.24.1 auf allen fuenf nachgezogen + Handover fuer TP16.3 §2/§3
Nautobot: ap1 stand als einziges Geraet noch auf SoftwareVersion 7.24 (ap2,
ap3, core, branch waren bereits richtig) -> auf 7.24.1 gesetzt. Danach
Backup/Intended/Compliance.

Folge fuers Runbook: aus zwei container.npk wird EINE. Die Zwei-Dateien-Regel
vom 08-30 war rein versionsbedingt, nicht modellbedingt - cAP ax und hAP ax^2
teilen sich die arm64-Pakete. §0, §2.1, §3.1 und Falle 1 umgeschrieben.
Die Regel dahinter bleibt: npk muss exakt zur ROS-Version passen, sonst ist
das Paket nach dem Reboot inaktiv - ohne Fehlermeldung.

Neue Compliance-Drift, NICHT von dieser Session und bewusst offen gelassen:
crs326-core / wifi-security - sec-main hat am Geraet ft-over-ds=no, Soll ist
yes (ft=yes ist korrekt). Kam mit dem Upgrade. 134/135 compliant. Braucht eine
Entscheidung (Geraet korrigieren oder neuen Wert zum Soll erklaeren) plus
Re-Provisionierung der CAPs; ein Re-Baseline ohne Entscheid wuerde die
Drift-Erkennung wertlos machen.

Handover docs/handoff-20260831-tp16.3-vorort-session.md fuer die Folgesession
(§2/§3: npk, device-mode, Container). Enthaelt u.a. den Hinweis, dass ein
fehlschlagendes /tool fetch vom AP auf Caddy KEIN Fehler ist, sondern die
SNI-Abweisung - und dass der TLS-Alert sogar beweist, dass die Freigabe traegt.

Offen notiert, nicht angelegt: TP-Vorschlag "dedizierter untagged-VLAN99-Port
je Switch" (Out-of-Band-Mgmt) - Auslöser war, dass crs326-branch beim
Core-Neustart nicht erreichbar war. Wartet auf Christophs Okay.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 14:57:35 +02:00
6f8ba8c8b5 sshpass -p repo-weit weg + vier TP15-Cutover-Skripte archiviert
sshpass -p schreibt das Passwort in argv, wo es in ps und jedem argv-Trace
steht -- die Klasse, an der am 2026-08-22 das Core-Passwort verbrannt ist.
Nach gc-transaktion.py (voriger Commit) jetzt auch die fuenf unter routeros/:
SSHPASS-Env + sshpass -e.

Nachweis, gemessen statt gelesen:
- alle 13 subprocess.run mit sshpass tragen env= (per AST geprueft; ohne env
  waere SSHPASS leer und alles still kaputt)
- Signaturen passen zu den Aufrufen (AST-Arity; py_compile findet das NICHT)
- echter Lauf des gepatchten Codes gegen den lebenden Core: backup-core.py
  importiert, IP zur Laufzeit auf 10.40.99.1 -> "name: crs326-core", rc=0
- Passwort in argv? nein. In ps waehrend der Verbindung? nein, 40 Stichproben
- Negativkontrolle: derselbe Test mit einem Dummy-Wert ueber die alte -p-Form
  -> 36 Treffer. Die Probe ist also nicht blind, das "nein" hat Aussagekraft

Mitgefixt, weil es im umgebauten Code lag: apply-core-cutover-l3.py griff in
run_silent auf ein pw zu, das dort gar nicht existierte -- jeder Fehlerfall
endete in einem NameError statt in der gedachten Meldung.

Fuer TP30 aendert das NICHTS: der Weg ist zu, der Wert bleibt verbrannt.
Posten #1 (MikroTik-admin) bleibt faellig. Im TP so hingeschrieben, damit es
niemand als erledigt liest.

--- Archivierung (Christoph-Entscheid) ---

Beim Fixen fiel auf, dass alle vier Cutover-Skripte auf tote Adressen zeigten:
  apply-core-cutover-l3.py  10.40.41.211    tot (VLAN41 seit 2026-08-27 weg)
  backup-core.py            10.40.41.211    tot
  restore-core.py           192.168.88.1    tot (Werks-Temp-Pfad)
  backup-ap1.py             10.40.10.1      ANTWORTET -- ist aber der CORE

backup-ap1.py war der gefaehrliche: er waere nicht gescheitert, er haette den
Core gesichert und die Datei ap1-pre-core-cutover-*.backup genannt. Wer das
spaeter zurueckspielt, spielt Core-Config auf einen AP.

Entscheid war archivieren, nicht reparieren -- der Cutover ist am 2026-08-08
durch, die Skripte haben ihre Aufgabe erfuellt. Sie liegen jetzt unter
routeros/archiv-tp15-cutover/ mit README nach dem Muster von switch/.
Die Pfad-Nebenwirkungen des Verschiebens sind ABSICHTLICH nicht repariert
(backup-core.py schriebe jetzt ins Archivverzeichnis, apply-core-cutover-l3.py
faende seine .rsc nicht mehr) -- sie zu reparieren hiesse, die Skripte wieder
lauffaehig zu machen, und das ist gerade nicht die Absicht.

Der sshpass-Fix wurde trotzdem VOR dem Verschieben gemacht: Archiv-Code wird
abgeschrieben, also soll dort das richtige Muster stehen.

import-core-rsc.py bleibt, wo es ist -- als einziges generisch nuetzlich. Sein
Default-Host ist ebenfalls tot (--host mitgeben), und in --host steckt ein
zweiter latenter Bug: sys.argv[1] wird als RSC-Pfad gelesen, bevor auf --host
geprueft wird. NICHT gefixt, eigene Runde.

Zeiger gesetzt in: CLAUDE.md (sshpass-Gotcha), teilprojekte.md (TP30),
teilprojekte-archiv.md (TP15), Handoff 2026-08-31.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 08:34:08 +02:00
a0a650eb48 TP25 Fund E Hebel 1: ft-over-ds=no auf sec-main, Messung laeuft
Ein Hebel, sonst nichts. 2026-08-31 08:09 am Manager crs326-core:
  /interface wifi security set [find name="sec-main"] ft-over-ds=no
  /interface wifi capsman remote-cap provision [find]
ft=yes bleibt -- FT laeuft weiter over-the-air, nur nicht mehr over-the-DS.
Nimmt exakt die Aenderung vom 2026-08-17 zurueck.

Abnahme (Lease, nicht Registration-Table):
- Manager, alle vier aktiven Master-VAPs cap-wifi3/4/5/6: ft=true ft-over-ds=false
- alle 3 CAPs state=Ok, alle VAPs running=yes AM CAP gelesen
- iPhone nach 71 s zurueck auf dirtyvader-main, frische Lease 10.40.10.196,
  auth-type=ft-wpa3-psk, -54 dBm; 30 Clients gesamt zurueck
- Log 08:13:20 zeigt sauberes "roamed to" zwischen zwei APs -> Roaming intakt
- Geraete-Backup vorher: pre-tp25-funde-ftoverds.backup

Governance: Transaktion TP25-fund-e-ft-over-ds OFFEN (Scope wifi-security,
Ablauf 2026-09-03). Compliance steht deshalb ABSICHTLICH auf 134/135; der Diff
ist exakt ft-over-ds=yes->no, kein Kollateral-Drift durch die Re-Provisionierung.
Das GC-Template wird erst beim COMMIT nachgezogen -- vorher gruen machen wuerde
den laufenden Versuch unsichtbar machen, und gc-transaktion.py verweigert den
Commit ohnehin, solange der Scope driftet. 135/135 kommt nach der Messung zurueck.

Messstand nach 25 min: weiter 93, letzter reauthenticating 07:34:43 (vor dem
Eingriff). Logging nachweislich lebendig (593 wireless-Zeilen heute, beide SSIDs).
Noch kein Ergebnis, nur ein sauberer Schnitt.

Drei Funde:
- cap-wifiN-Karte hat sich beim Re-Provisionieren VERSCHOBEN: ap2 war 1/2 ->
  jetzt 3/5, ap3 war 5/6 -> jetzt 4/6, ap1 hat 1/2 bekommen. Wer die 07:xx-Zeilen
  gegen die neuen liest, ordnet dem falschen AP zu.
- Korrektur am Vormittagsbefund: main unterscheidet sich in ZWEI Attributen, nicht
  einem -- es ist auch die einzige SSID ohne wpa2-psk. Die Kontrollgruppe trennt FT
  und WPA3-only nicht. Wenn Hebel 1 und 2 beide nichts bewegen, ist
  authentication-types der naechste Kandidat, NICHT signal-range.
- gc-transaktion.py rief sshpass -p auf (Passwort in argv, Klasse vom 2026-08-22).
  Auf SSHPASS-Env + -e umgestellt, weil das Skript laufen musste. Fuenf weitere
  Dateien unter routeros/ haben dasselbe Muster und sind bewusst NICHT angefasst
  (Stop-Bedingung; gehoert zu TP30). Entwarnung: /export auf 7.24 gibt Passphrasen
  gar nicht aus (live geprueft), die Transaktionsakte im Git ist sauber.

Nebenbei: .gitignore hatte docs/nas-vlan20/stacks/ MIT Schraegstrich -- im Worktree
liegt dort ein Symlink auf den Haupt-Checkout, der war damit nicht ignoriert.

Doku an allen drei Stellen nachgezogen (Quick-Index, TP25-Abschnitt, Ist-Stand-Block)
plus CLAUDE.md-Pflichtlektuere und neuer Handoff mit Entscheidungstabelle fuer 09-01.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 08:19:31 +02:00
badf715f5a TP16.3 §1: die drei Blocker remote behoben (Ingress, Firewall via GC, ap3-Cred)
A) bf-public-Ingress von http://10.40.20.40:80 auf https://10.40.20.40:443
   umgestellt, originServerName je Regel. Die :80-Variante haette ueber
   Cloudflare eine Redirect-Schleife gebaut (Caddy antwortet dort 308 auf
   https, das Ziel laeuft zurueck in denselben Tunnel).

B) Freigabe vlan99 -> vlan20:443 auf crs326-core angelegt - ueber Nautobot
   Golden Config, NICHT per Direkt-Write: ip-firewall-filter steht seit TP26
   unter Drift-Kontrolle, und die zwei genehmigten Ausnahmen (#2 Bring-up,
   #4 WireGuard-Keys) decken diesen Fall nicht.
   - Backup vorher: core-pre-tp16.3-blockerB-20260831.backup (TP22-Regel 3)
   - gc-manual-plan.py, Change-ID TP16.3-BlockerB, Plan Completed
   - Position verifiziert: direkt vor TP5: log-only / TP5: deny-by-default
   - Re-Baseline ingest-core-firewall.py --apply, dann --refresh-compliance
     => 135/135 compliant, 0 Drifts
   - funktional: /tool fetch von ap3 erreicht Caddy und bekommt einen
     TLS-Alert VON Caddy - ein Alert kann nur vom Server kommen, das Paket
     ist also da. Der Alert ist die SNI-Abweisung (ohne SNI 000, mit
     korrektem SNI 200) und damit genau der Grund fuer originServerName.

C) ROUTER_AP3_USER/_PASS in ~/.secrets/credentials.env nachgetragen (war nur
   in ~/.claude.json), chmod 600, Sicherung .bak-20260831. REST-Auth gegen
   ap3 = HTTP 200.

Vor Ort startet die Arbeit damit bei §2/§3 (container.npk, device-mode,
Container). Quick-Index, TP16.3-Abschnitt und Ist-Stand mitgezogen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 08:06:38 +02:00
40ffab1de8 TP25 Fund E: Befund nach einer Nacht Logging -- Reauth-Schleife haengt an ft=yes, Hebelreihenfolge korrigiert
Das gestern eingeschaltete wireless-Logging hat binnen 16 h geliefert, was der 75-Zeilen-
Ringpuffer nie konnte: 559 Zeilen, davon 439 (79 %) von Christophs iPhone.

Entscheidend ist nicht die Menge, sondern die Trennschaerfe:
- `reauthenticating` tritt 93 von 93 Mal bei GENAU EINEM Client auf (dem iPhone)
- und 93 von 93 Mal auf GENAU EINER SSID (dirtyvader-main)
- was `main` von den anderen fuenf unterscheidet, ist EIN Attribut: ft=yes ft-over-ds=yes

Dieselben APs, dieselben Radios, derselbe Zeitraum, dieselben Clients -- die SSIDs mit
ft=no zeigen null Ereignisse. Das ist eine saubere Kontrollgruppe. Die WPA3+802.11r-
Hypothese, die ich gestern ausdruecklich als "Forenwissen, nicht in der MikroTik-Doku"
gefuehrt habe, ist damit durch eigene Messung gestuetzt.

Verlauf 2026-08-31 auf cap-wifi6: 07:25 (10x) -> 07:34 (21x), eskalierend, teils mehrere
pro Sekunde, endend mit einem Roam auf cap-wifi2 bei -89 dBm -- also der Flucht auf einen
25 dB schlechteren AP. Genau so sieht "Link weg trotz gutem Kontakt, dann Mobilfunk" von
der Infrastrukturseite aus.

KORREKTUR an meiner eigenen Priorisierung von gestern: 2g-probe-delay war als Hebel 1
gesetzt, weil es der ungefaehrlichste ist. Das war vor diesem Befund und ist falsch --
2g-probe-delay adressiert Band-Steering, hier liegt ein Authentifizierungsproblem vor.
Neue Reihenfolge: (1) ft-over-ds=no, (2) ft=no, (3) 2g-probe-delay, (4) signal-range.

Ebenfalls festgehalten: die zwei erfassten "not responding"-Abbruecke liegen bei -80/-76
dBm und sind NICHT dasselbe wie der Schwall -- die Ursprungsmessung vom 08-20 hatte -47.
Nicht zusammenwerfen.

Noch nichts am Funk geaendert. Der Hebel ist beschrieben, das Messrezept steht im Handoff,
und wifi-security ist nicht deploybar (TP22-Regel 1) -- die Aenderung muss am Geraet
erfolgen und das Template danach von Hand nachgezogen werden.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 07:57:36 +02:00
175486221b TP25 Fund E wieder geoeffnet + WLAN-Logging persistent (27. ComplianceRule system-logging)
Auslöser war eine unabhaengige Meldung: seit Tagen/Wochen verliert das iPhone den
WiFi-Link bei gutem Signal und landet auf Mobilfunk. Auf Mobilfunk zu fallen ist KEIN
Roaming-Problem -- bei schlechtem Roaming bliebe das Telefon im WLAN und waere nur
langsam. Es heisst, die Assoziation ist gestorben und die Neuanmeldung gescheitert.

Der Manager-Log zeigt dasselbe iPhone (F2:62:4C:E1:AF:09) mit 16 Bandwechseln in 20
Minuten zwischen ap3s 5-GHz- und 2,4-GHz-Radio, zweimal im Abstand von einer Sekunde,
bei -53..-81 dBm -- kurz darauf dasselbe an ap2. Also nicht ap3-spezifisch.

Das stand schon im Repo: TP25 Fund E beschreibt es seit dem 2026-08-20, mit derselben
MAC und der Zeile "disconnected, not responding, signal strength -47" -- Abbruch bei
ausgezeichnetem Signal. Fund E war zurueckgestellt mit der Auflage "erst wieder
aufgreifen, wenn ein Sticky-Fall erneut gemessen ist". Die ist eingetreten. Das ist
heute der zweite Fall (nach dem TP25-Kanalplan fuer ap3), in dem eine fertige Analyse
im TP-Body stand und ich sie erst nach einer Extrarunde gefunden habe.

Der eigentliche Mangel war aber die Beweislage: `wireless` lief NUR nach action=memory,
nur `firewall` ging in den Kollektor. Der Ringpuffer fasste 75 Zeilen und war von einer
Stunde ap3-Arbeit fast ueberschrieben -- rueckwirkend war nichts diagnostizierbar.

Jetzt: zwei Regeln am Core (topics=wireless und topics=caps) in denselben Kollektor wie
TP5 (10.40.20.18:514). Gegenprobe auf beiden Seiten -- 32 Zeilen liegen bereits im
Tagesfile, inkl. `associated` (debug) und `connected` (info).

Und unter Drift-Kontrolle, denn /system logging stand unter KEINER der 26 Rules und gar
nicht im Template: neue ComplianceFeature/Rule `system-logging` (Muster: TP6 /queue,
TP26 /ip firewall filter), Template-Block [6a2] nur im Core-Zweig -- RouterOS exportiert
Defaults nicht, auf ap1/ap2/ap3/branch sind Soll und Ist beide leer.
Compliance 130/130 -> 135/135, 0 Drifts. Die Zahl MUSS sich bewegen: eine
gleichbleibende Zahl nach dem Hinzufuegen einer Regel waere ein Befund, kein Erfolg.

Zwei RouterOS-Fallen, beide als Gotcha in CLAUDE.md:
- Der Topic heisst `wireless`, NICHT `wifi` -- auch auf dem neuen wifi-qcom-Stack.
  Ein geratenes topics=wifi waere wirkungslos geblieben.
- RouterOS UND-verknuepft Topics innerhalb EINER Regel (`info,!firewall` = info UND
  NICHT firewall). `topics=wireless,caps` haette NICHTS gematcht -> zwei Regeln.

Recherche-Ergebnis gegen die offizielle MikroTik-Doku, das meine eigene erste Hypothese
widerlegt: transition-threshold steht per Default auf -80 dBm (-time 10s,
-request-period 30s, -count 3), und unsere Steering-Objekte setzen davon nichts. Bei
-53..-74 dBm wird das iPhone gar nicht Transition-Kandidat -- unsolicited BTM scheidet
als Treiber weitgehend aus. Die vielzitierte WPA3/802.11r-Inkompatibilitaet steht NICHT
in der Doku (dort nur: FT geht nicht ueber OWE); sie bleibt Hypothese.

BEWUSST NICHT geaendert: kein einziger Funk-Parameter. Drei Hebel sind dokumentiert und
priorisiert -- (1) 2g-probe-delay=yes, kann keinen Client stranden lassen, (2)
ft-over-ds=no, nimmt die Aenderung vom 2026-08-17 zurueck, (3) signal-range-Boden, der
invasivste und einzige, der Clients aussperren kann. Einzeln, je als Transaktion, erst
mit Daten.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 21:11:48 +02:00
b697ffc6fa TP16.3/TP31 Schritt 5: Vor-Ort-Runbook fuer bf-public-Connector (ap1/ap2/ap3)
Runbook docs/tp16.3-bf-public-ap-connector-runbook.md fuer die Vor-Ort-Session
geschrieben; docs/tp31-schritt5-runbook.md abgeloest (read-only-Header).

Live-Befunde 2026-08-30, die den Plan aendern:

- ap3 ist neu und NICHT baugleich: cAP ax (cAPGi-5HaxD2HaxD, 10.40.99.13),
  arm64/96 MB frei, aber ROS 7.24.1 gegen 7.24 auf ap1/ap2 => zwei
  verschiedene container.npk. device-mode=basic statt home (fetch bereits an).
- Blocker A: bf-public-Ingress zeigt auf :80, Caddy antwortet dort mit 308 auf
  https => Redirect-Schleife ueber CF fuer alle vier Namen. Faellt heute nicht
  auf, weil die Alttunnel an Caddy vorbei direkt aufs Backend gehen.
  Fix: https://10.40.20.40:443 + originServerName je Regel (ueber 443 4x 200).
- Blocker B: es gibt KEINE Freigabe vlan99 -> vlan20:443. Die forward-Kette
  wurde vollstaendig gelesen (36 Regeln); die einzige MGMT->INFRA-Regel ist ein
  src-port=8728-Rueckweg. Der Vorgaenger-Runbook behauptet das Gegenteil
  ("Regel 27 deckt vlan99->vlan20:80 ab") - Regel 27 ist IOT->INFRA.
- Blocker C: ROUTER_AP3_PASS fehlt in ~/.secrets/credentials.env (nur in
  ~/.claude.json). Nebenbefund: credentials.env laesst sich in zsh nicht
  sourcen (rohe WireGuard-Zeilen ab ~Z.69) - Variablen bleiben still leer.
- Kein PoE an beiden CRS326 => kein Remote-Power-Cycle, Bestaetigung physisch.
- Die sechs abzubauenden Container auf allen drei Hosts verifiziert;
  terpene-cloudflared und fm.emsenhuber.net bleiben.

CF-Rollback-Snapshots unter docs/cf-backup/*-20260830-vor-tp16.3-schnitt.json
neu angelegt (vier Ingress-Configs + CNAMEs inkl. Record-IDs) - es gab sie
vorher nicht.

Quick-Index, TP16.3-Abschnitt und Ist-Stand-Block mitgezogen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 21:07:17 +02:00
ed005fff2e MCP-Clients repariert: GUI-Env via LaunchAgent (F6) + pve-mcp-URL (F7)
Beide Fehler kamen aus der Session-Startmeldung, keiner von der
F1-Migration.

F7 - pve-mcp ENDPOINT_NOT_FOUND: beide globalen Configs zeigten auf
:3000/mcp, der Server antwortet nur auf dem Root-Pfad (live: / -> 200,
/mcp -> 404). Damit widersprachen sie der eigenen CLAUDE.md, die den
Root-Pfad seit jeher korrekt nennt. Beide korrigiert.

F6 - n8n-mcp 401, und das ist der weitreichende Fund: ~/.zprofile
sourct exports.zsh korrekt, aber .zprofile liest NUR eine Login-Shell.
Claude Desktop und opencode starten gar keine Shell - sie erben die
launchd-Umgebung. Folge: ALLE {env:VAR}-Referenzen loesen zu leer auf.
Live nachgewiesen: in keinem Claude-Helper-, claude- oder
opencode-MCP-Prozess war N8N_MCP_BEARER gesetzt, waehrend dieselbe
Variable in einer Login-Shell len=64 hat.

Das erklaert rueckwirkend die Klartext-Secrets in ~/.claude.json: dort
steht Klartext, WEIL {env:} in einer GUI-App nicht aufloest. Meine
frueher vorgeschlagene Umstellung auf {env:} haette mikromcp und
hostinger stillgelegt - gut, dass sie vertagt wurde. Jetzt ist sie
gefahrlos (Voraussetzung fuer TP30).

Loesung: ~/Library/LaunchAgents/net.emsenhuber.gui-env.plist ruft
~/dev/.bin/gui-env-sync.sh, das exports.zsh zur Laufzeit liest und die
Variablen per launchctl setenv setzt. Kein Secret-Duplikat, die plist
enthaelt keine Werte, SSoT bleibt exports.zsh. 22 von 22 gesetzt.

Die Konvention "niemals launchctl setenv" ist damit zu praezisieren,
nicht gebrochen: verboten war der Handaufruf, weil er in keiner Datei
steht. plist + Skript sind die Datei-Form davon.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 21:00:00 +02:00
1006f91e6a TP28: ap3 (cAP ax) live als CAP, ap1 funkstill, Compliance 130/130 ueber 5 Geraete
Der dritte Access-Point laeuft: 10.40.99.13 auf vlan99, Uplink ether1 -> core ether21,
reiner CAP unter crs326-core, Kanaele 5180/ax/Ce/I und 2437/ax (ch6) -- am Geraet
nachgemessen, nicht aus dem Plan abgeschrieben. Der Kanalplan stammt aus TP25 vom
2026-08-24; mein erster Entwurf hatte ihn neu erfunden und waere bei ch1 statt ch6
gelandet. Lehre: den TP-Body lesen, nicht nur den Quick-Index.

ap1 hat bewusst KEINE Provisioning-Regel mehr: es steht bis zu seinem Umzug ans
Sideboard direkt neben ap3 und wuerde auf 5180 kollidieren. Geraet bleibt erreichbar,
die Objekte ch-*-ap1 / cfg-main-*-ap1 bleiben fuer den Umzug stehen.

Bring-up in zwei Phasen ueber ein Patchkabel ap3 ether2 -> core ether22, weil ueber
ether1 nichts ging (s.u.). Loop-Schutz: ether21 war waehrend Phase 1 abgeschaltet und
wurde im selben Befehl gegen ether22 getauscht. RouterOS 7.20.8 -> 7.24.1 plus
RouterBOOT (zwei Reboots, TP27-Kriterium erfuellt). Die anderen vier stehen auf 7.24 --
die Angleichung ist ein eigener Durchgang, der Core-Reboot ist ein Standort-Ausfall.

Nautobot: DeviceType "cAP ax", Device ap3 mit 16 Interfaces, primary_ip4, secrets_group,
ConfigContext 5g=ch36 2g=ch6 extra_ports=[]. Nebenkorrektur: ap1 stand auf "Wohnzimmer
Sideboard", steht physisch aber in Technik UG (User-Bestaetigung).

Sechs Funde, alle als Gotcha in CLAUDE.md und im Handoff:
- ether1 ist am Werksgeraet WAN: Discovery aus, Input-TCP verworfen, ICMP aber erlaubt.
  Es pingt, und das liest sich wie "erreichbar". MikroMCP hilft nicht -- Port 80 ist zu.
- pvid ist Ingress, tagged/untagged ist Egress. Ein Lease hing ewig auf "offered", weil
  der ACK getaggt rausging und ein Werksgeraet das nicht versteht.
- `cap enabled=yes` reicht nicht: jedes Master-Radio braucht configuration.manager=capsman,
  sonst bietet der CAP seine Radios gar nicht an -- state=Ok, radio-Tabelle leer.
- Ein Geraet ohne secrets_group erzeugt eine LUECKE, keine Fehlermeldung: Backup scheitert
  still, keine Compliance-Eintraege, Zahl bleibt unauffaellig bei 104/104. Eine
  gleichbleibende Compliance-Zahl nach dem Hinzufuegen eines Geraets ist ein BEFUND.
- CAPsMAN verteilt keine Login-Passwoerter, nur WLAN-PSKs. Der Geraete-Login ist eine
  lokale DB pro Geraet; das einheitliche Admin-PW ist eine Konvention von Hand.
- Firewall-Regelnummern aus `print where` sind Handles, keine Positionen. Beweis ist der
  Zaehler, nicht die Zahl.

Abnahme: 3 CAPs state=Ok, VAP-Satz vollstaendig und running, 20 IOT-Clients auf ap3 mit
0 % Ping-Verlust ueber VLAN30 (bewusst nicht ueber die Registration-Table abgenommen),
Compliance 130/130 / 0 Drifts, Core-Temp-Pfad restlos abgeraeumt.

Offen: TP25-Messrunde (braucht Rundgang), PW-Rotation TP30, MikroMCP-Neustart.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 17:54:07 +02:00
70a983eaa3 F4 praezisiert: n8n-mcp blockt private IPs per SSRF-Schutz
Gefunden mit derselben Abnahme-Methode wie der gitea-mcp-Token: ein
echter tools/call statt nur initialize.

n8n_health_check -> "SSRF protection: Private IP addresses not allowed"
fuer apiUrl http://n8n:5678. Damit ist die Container-DNS-Adresse des
laufenden Containers gar nicht funktionsfaehig, und mein urspruenglicher
F4-Vorschlag (genau diese URL im Compose festschreiben) haette den
kaputten Zustand zementiert.

Umgekehrt war https://n8n.emsenhuber.net im Compose vermutlich Absicht -
oeffentliche Adresse passiert den Schutz - nur eben ueber den CF-Umweg,
was TP16.3 gerade abbauen will. F4 ist damit ein Zielkonflikt, kein
reines Datei-Angleichen.

Ausfallumfang: Doku-Tools laufen (search_nodes ok, das ist die
Hauptfunktion), nur die n8n_*-Management-Tools sind tot.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 12:29:35 +02:00
bc0bf316e1 gitea-mcp repariert: Container lief mit veraltetem Gitea-Token (401)
Gefunden beim Versuch, F1 mit einem ECHTEN MCP-Call abzunehmen statt
nur mit dem initialize-Handshake.

Befund:
- Container-Env GITEA_ACCESS_TOKEN = a9317c68... -> Gitea antwortet 401
- ~/.secrets/credentials.env (SSoT)  = bc12ad19... -> Gitea antwortet 200
- Gitea selbst war durchgehend erreichbar (/api/v1/version -> 200)
- NICHT durch den Bind-Umbau verursacht: Token-Hash vor und nach dem
  Recreate identisch. Der MCP war schon vorher funktionsunfaehig.

Fix: Container mit dem Store-Token neu gebaut, Token per stdin (nicht
argv). Abnahme jetzt ein echter tools/call user__get_my_userinfo ->
login=admin id=1.

Lehre (im F1-Eintrag festgehalten): ein initialize-Handshake beweist
nur, dass der MCP-Prozess lebt - er liefert serverInfo auch dann, wenn
jeder echte Aufruf am Backend-Token scheitert. Fuer MCPs mit
Backend-Credential ist die gueltige Abnahme ein tools/call, der das
Backend wirklich anfasst. Gleiches Muster wie "frische DHCP-Lease statt
Registration-Table" bei WLAN.

Verstaerkt F5: Container-Envs driften vom Credential-Store, weil sie
ihn nie lesen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 12:28:10 +02:00
c82fb45f7f TP16.3 F1 DURCH: gitea-mcp/n8n-mcp geschnitten + Doku nachgezogen
Der grosse Schnitt (803a287) hatte diese zwei Namen bewusst ausgelassen,
weil Werkzeug daran hing. F1 hat die Abhaengigkeit aufgeloest, danach
fiel der Schnitt:

  Ingress bf-mm  4 -> 2  (nur noch n8n + Catch-all)
  DNS            beide CNAMEs geloescht
  Gesamt         14 statt 12 Hostnames

Migriert wurden 12 Client-Configs (nicht 10 wie geschaetzt) - zwei
Worktree-Kopien in bf-network-r6{,.opencode} fand erst ein Sweep. Der
opencode.jsonc-Teil steckt bereits in fd05286: ich hatte den
Main-Checkout direkt editiert, damit opencode die IP sofort hat, und
die Parallelsession hat ihn mit eingesammelt.

Doku an vier Stellen nachgezogen (Ist-Stand, "Naechster Schritt",
Quick-Index, Follow-up F1) - die Drei-Stellen-Regel aus CLAUDE.md.

Befunde, jetzt im F1-Eintrag festgehalten:
- Claude Code und opencode haben VERSCHIEDENE Konfigpfade: .mcp.json
  ist pro Projekt (Claude Code), opencode liest EINE globale Datei.
  Deshalb reichte fuer opencode die eine Migration aus TP35 Schicht 1,
  waehrend Claude Code acht Einzeldateien brauchte.
- n8n-mcp laeuft NICHT ohne Bearer (process.exit(1) ohne AUTH_TOKEN);
  er ist der einzige echte Zugriffs-Bearer im Setup.
- gitea-mcp auf 10.40.20.167:3000 gebunden; Nutzen klein, da der
  macmini nur en0 hat.
- Geschnittene Namen antworten NOERROR + leer, nicht NXDOMAIN -
  gegengeprueft an den vier Namen aus dem grossen Schnitt.

Neu angelegt: F4 (n8n-mcp-Compose versoehnen - Container stimmt mit
keiner seiner drei Definitionsquellen ueberein, compose up waere
destruktiv) und F5 (Secret-Verteilung auf Container-Hosts; credentials.env
liegt nur auf dem MacBook, macmini hat kein ~/.secrets).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 12:25:01 +02:00
709cc626bb TP37 angelegt: Nautobot als durchgehende Netzwerkdoku (CF-Connectoren als erster Fall)
User-Okay 2026-08-30. Auslöser ist der TP16.3-Schnitt: um ihn zu planen,
mussten sechs cloudflared-Container über drei Hosts per SSH und Portainer-API
zusammengesucht werden -- die Zuordnung Tunnel->Connector->Host existierte
nirgends als Datensatz, nur in Prosa.

Befund live gegen die Nautobot-API gelesen:
  Devices 8 (4 aktiv, 4 decommissioned), Apps nur golden-config
  ipam.Service 0 · CustomField 0 · Relationship 0 · VirtualMachine 0 · Tag 0
Nautobot kennt heute ausschliesslich die vier MikroTik. Weder Caddy noch
AdGuard noch pve/NAS/macmini noch Nautobot selbst sind erfasst.

Konsequenz fuer den Zuschnitt: TP37 ist zuerst eine Datenmodell-Frage
(Substrat + Dienste), erst danach eine Connector-Frage. Damit liefert es das
Fundament, das TP34 (Caddyfile via GC) und TP36 (SSoT fuer teilprojekte.md)
ebenfalls brauchen -- Reihenfolge TP37 vor TP34, festgehalten in beiden.

Abgrenzung explizit: kein Golden Config fuer Nicht-Netzgeraete (das ist TP34),
keine Cloudflare-Writes aus Nautobot heraus.
Einschraenkung benannt: die GC-Pipeline ist heute schlank und 104/104
compliant; Punkt 1-2 daher als eigener abnehmbarer Schritt mit
Compliance-Gegenprobe, nicht als Nebeneffekt.

Alle drei Stellen nachgezogen: Quick-Index, TP-Abschnitt, Ist-Stand-Block.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 12:19:24 +02:00
fd05286e4b TP28 wieder geoeffnet: ap3 (cAP ax) vorbereitet, core ether21 Trunk, MikroMCP-Registry auf bf-infra
Dritter Access-Point ap3 (MikroTik cAP ax, cAPGi-5HaxD2HaxD) kommt dazu und loest
mittelfristig ap1 in Technik UG ab. Statt eines neuen TP wandert TP28 aus dem Archiv
zurueck -- neue Regel: ein archiviertes TP ist ein geschlossenes, kein versiegeltes
Ticket (Christoph-Direktive 2026-08-30).

Live am Core:
- ether21 ist AP-Trunk (10/20/30/40/50/90/99 tagged, Muster ether15). ⚠️ Erratum: erst
  war ether22 angenommen und getaggt; der Port hat keinen Link. Gegenprobe ueber die
  Bridge-Host-Tabelle: auf ether21 sitzt D0:EA:11:FF:16:9D = E01 vom ap3-Label.
  ether22 wieder leer.
- Backups vorher: pre-ap3-20260830.backup/.rsc auf core und ap1.
- Compliance vor und nach jeder Aenderung 104/104, 0 Drifts.

Golden Config (2 Pushes: e25d654b, 20472cdb):
- Core-L2-Block traegt ether21.
- AP-Zweig rendert die Bridge-Ports jetzt aus ap.extra_ports statt hartkodiert
  ether3/4/5. Das war die stille Annahme "AP == hAP ax2 mit 5 Ports"; der cAP ax hat
  zwei. Default in ap-common = hAP-ax2-Bestand, ap3 ueberschreibt mit [].
  Dass ap1/ap2 danach zeichengleich rendern, beweist die 0-Drift-Messung.

Kanalplan NICHT neu erfunden: TP25 hat ihn am 2026-08-24 fuer genau dieses Geraet
gerechnet (DFS vom User genehmigt). ap3 = 5180/Ce + 2437 (ch6, nicht ch1 -- ch1 bleibt
fuer ap1, damit 1/6/11 erstmals lueckenlos aufgeht). ap1/ap2 gehen beim Umzug auf
5260/Ce bzw. 5300/Ce, 5220/Ce bleibt Ausweichspur.

MikroMCP-Registry (MCP-Lifecycle, User-Freigabe 2026-08-30) -- zwei Drifts:
- MIKROMCP_CONFIG_PATH zeigte auf ~/dev/bf-network-r6 (Archiv-Repo); die identische
  Datei in bf-infra war wirkungslos. Jetzt bf-infra = SSoT.
- In opencode.jsonc fehlte MIKROMCP_CONFIG_PATH ganz, hinterlegt waren nur ap1/ap2 --
  opencode kannte core/branch gar nicht. Beide Clients zeigen jetzt auf dieselbe
  Registry; ap3 aufgenommen, rosVersion von stale 7.23/7.19.5 auf 7.24 korrigiert.
  Neustart des MCP noetig, Registry wird nur beim Start gelesen.

Noch offen: physischer Bring-up (Datei liegt bereit), ap1-Radios aus, CAPsMAN-Objekte
fuer ap3, Nautobot-Adoption, Messrunde -- und die Passwort-Rotation: das gemeinsame
MikroTik-Admin-PW ist in dieser Session durch eine ungefilterte Ausgabe des
mikromcp-env-Blocks ins Transkript geraten und gilt als verbrannt (Posten fuer TP30).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 12:14:21 +02:00
803a28772f TP16.3 grosser Schnitt: 12 Hostnames aus CF-Ingress + DNS entfernt
Public-Strang eingedampft. Entfernt aus Ingress UND DNS:
pve, portainer, pve-mcp, ha-mcp, ds-bf, ccu, iobroker, z2m25, pbs
sowie die drei CF-Access-SSH-Ziele 82unkpb5 / 3k23uow7 / j44d6tua.
Ingress-Bilanz: bf-mm 6->4, bf-nas 6->3, bf-pve 9->2, Catch-all je letzte.
pbs + SSH standen nicht in der Kandidatenliste -- User-Entscheid 2026-08-30
"beide mesh-only".

Abnahme beidseitig gemessen:
- intern traegt weiter: AdGuard loest alle neun Namen auf 10.40.20.40,
  Caddy antwortet HTTPS 200 (pve 0,08s / portainer 0,03s / pbs 0,03s)
- oeffentlich weg: NXDOMAIN gegen 1.1.1.1
- Public-Strang unberuehrt: vw/hass/n8n/gitea weiterhin HTTP 200
Nachweis ist das Zuruecklesen der Ingress-Config, nicht die Frontend-Antwort
(Access antwortet vor dem Tunnel -- TP16.3-Regel).

Bewusst NICHT geschnitten: gitea-mcp + n8n-mcp. Die TP16.3-Vorpruefung
schlaegt an -- gitea-mcp.emsenhuber.net steht in 9 Dateien (8 fremde
Projekte + bf-infra/opencode.jsonc), ~/.claude.json nutzt zusaetzlich
n8n-mcp. TP35 Schicht 1 ist nur global vollzogen, nicht auf Projekt-Ebene.
Erst migrieren, dann schneiden -> Follow-up F1.

Blocker fuer den Abbau der drei Alt-Tunnel: bf-public hat 0 Connectoren.
Er gehoert laut Entscheid auf ap1/ap2, dort fehlen aber container-Paket
UND device-mode container=yes (physische Bestaetigung am Geraet, fetch=no).
Vor-Ort-Session noetig -> Follow-up F2. Bis dahin stehen bf-mm/bf-nas/bf-pve
mit sechs Containern (LXC400, macmini, NAS -- alle lokalisiert).

Doku an allen drei Stellen nachgezogen: Quick-Index, TP16.3-Abschnitt,
Ist-Stand-Block. TP37 (CF-Connectoren in Nautobot) als Vorschlag
eingetragen, Okay steht aus.

Rollback: docs/cf-backup/*-20260830-vor-tp16.3-schnitt.json

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 11:40:31 +02:00
bd1ba5ed13 TP35 Schicht 3: globale Verhaltensregeln konsolidiert (AGENTS.md SSoT + CLAUDE.md Spiegel) 2026-08-29 18:55:12 +02:00
f1a8a4a3e7 TP35 Schicht 1: MCP-Migration FQDN→IP (gitea-mcp .167:3000, n8n-mcp .167:3001) + Ist-Stand/Quick-Index nachgezogen 2026-08-29 18:42:33 +02:00
b8fd42b3fd shelly-mcp: mcp<2 pinnen + TP30 Posten #3 hochstufen
Container crashte beim ersten Deploy mit 'No module named mcp.server.fastmcp':
PyPI hat mcp 2.x als aktuellste Version, FastMCP wurde dort zu MCPServer
umbenannt. Repo-Code (server.py) nutzt noch v1-API.

Fix: requirements.txt 'mcp[cli]>=1.0,<2' — hält den Server auf v1-kompatibel.

Deploy-Ergebnis:
- Container shelly-mcp auf DS923, IP 10.40.20.180 (macvlan vlan20)
- Health /health: 200, psk_configured:true, iot_ssid=dirtyvader-iot
- StreamableHTTP /mcp: serverInfo 'shelly-mcp 1.29.1'
- Live-Sweep 10.40.30.180-250: 23 Shellys erreichbar

TP30 Posten #3 (Shelly-Gerätepasswort) hochgestuft: SHELLY_DEVICE_PW ist im
Zuge dieses Deploys erneut in ein Sitzungstranskript geraten (sed-Pattern
'SHELLY_DEVICE_PW=.*' hat den Wert nicht maskiert, weil der Replacement-
String zu wenig greedy war — neuer Lessons-Block-Eintrag). Reihenfolge:
erst Werkzeug-Härtung (Stream-Filter statt cat+sed), dann Posten #3
rotieren. CLAUDE.md hat den Lessons-Eintrag, TP30 Posten #3 hat die
Hochstufungs-Begründung.
2026-08-28 21:27:05 +02:00
d06d505bc3 TP36 angelegt + Ist-Stand-Block aktualisiert + zwei Lessons-Eintraege
Befund 2026-08-28 nach Skill-Verifikation in opencode:
- Der 'Nächster Schritt (2026-08-26)'-Absatz war zwei Tage veraltet
  (drei Sessions waren parallel offen)
- Manuelle Doku mit Live-Daten verliert gegen die Realitaet, sobald
  die Datei lang wird (1940 Zeilen, drei Stellen pro Edit)

Reaktion:
1. 'Nächster Schritt' umgeschrieben: drei Folge-Sessions A/B/C aus
   dem gestrigen Handoff, klar als 'parallel' markiert. A ist erledigt
   (TP35 Schicht 6), B+C offen.
2. TP36 als Folge-TP neu angelegt: SSoT via Nautobot fuer
   teilprojekte-Live-Daten + Datei-Aufteilung (Index / Snapshot /
   Archiv). Eigene Session, nicht heute.
3. CLAUDE.md: zwei Lessons-Eintraege:
   a) opencode-TUI: fuehrendes Leerzeichen vor /command manchmal
      noetig (Beobachtung, kein Skill-Bug)
   b) Manuell gepflegte Doku verliert gegen Realitaet, Merkregel:
      drei Stellen pro Edit mitlesen (Quick-Index, TP-Abschnitt,
      Ist-Stand); strukturelle Antwort = TP36

Lessons-Block hat jetzt 7 Eintaege (Stand 2026-08-28).
2026-08-28 19:23:28 +02:00
8c1876c1d6 TP35 Schicht 6: /projektstatus-Skill in opencode aktiviert + Doku
- CLAUDE.md: zwei Lessons-Eintraege (opencode-Default-Pfad kopieren,
  nicht symlinken; Kommentar in Code != Verhalten)
- teilprojekte.md: TP35 Quick-Index auf 'Schicht 6 erledigt, Rest offen',
  Schicht-6-Befund im TP-Block, Ist-Stand auf 2026-08-28 mit MCP-Bestand-
  Korrektur
- handoff-20260828-session-a-projektstatus.md: Session-A-Bericht mit
  Drift, Befund, Entscheid, Lehren fuer Session B

Skill selbst liegt in ~/.config/opencode/skills/projektstatus/SKILL.md
(cp aus ~/.claude/skills/projektstatus/, byte-identisch) - opencode
scannt diesen Default-Pfad, kein skills.paths-Eintrag in der JSONC
noetig.
2026-08-28 19:15:02 +02:00
claude-code
5797364e4d drift-korrektur: Auth-Sanierung (Bearer) gehört in TP16.3, nicht als Vorab-Notiz
TP16.3 existiert seit 2026-08-17 (Quick-Index Z. 194, Body Z. 401,
Runbook tp16.3-nautobot-mesh-only-runbook.md) und deckt 'alle Tools
über Caddy oder CF + Caddy (extern)' + Auth-Sanierung bereits ab.

Mein Fehler: ich habe im Index nicht nachgeschaut und einen Vorab-Punkt
formuliert, der TP16.3 doppelt. Anwender hat das in dieser Session
explizit markiert ('das darf dir kein 2. mal passieren').

Fix:
- Session-Anker: Vorab-Notiz entfernt, ersetzt durch Verweis auf TP16.3.
- TP16.3-Body: technische Notiz 'n8n-mcp Accept-Header-Strike +
  Auth-Sanierung' eingepflegt (SSE-Header-Konsequenz für künftiges
  Caddy-Fronting, Reihenfolge TP16.3 → TP35 Schicht 2).

Lehre: vor jeder Aussage 'gibt's noch nicht' oder 'neuer TP nötig':
erst grep auf den Quick-Index in teilprojekte.md.
2026-08-28 17:18:16 +02:00
claude-code
389b146a91 tp35 angelegt + session-anker: MCP-Schichtung global/projekt/user
TP35 = Konzept + Schichtung, nicht die Umsetzung. Ausarbeitung
in eigener Session pro Projekt mit eigenem Handover-Post.

Scope (6 Schichten):
1. MCP-Schichtung global/projekt/user
2. Credentials-Schichtung (alle Secrets in ~/.secrets/exports.zsh)
3. 3-Schicht-CLAUDE.md (öffentlich/gitignored/global)
4. Announcement-Mechanismus (Hybrid)
5. Backup-Guard (3 Tage aktiv, 5 Commits oder 1000 LOC diff)
6. /projektstatus-Skill global (als Erstes)

Begleitend: docs/session-20260828-decisions.md = Mini-Anker mit
F1-F5-Begründungen + 3 Korrekturen unterwegs (Ollama 2 Hosts,
uwe-job-bewerbung doch dabei, Backup-Guard = aktive Tage).

Backups: 12/12 gzip-valid in ~/dev/.pre-opencode-migration-backups/20260828-150335/
2026-08-28 17:04:33 +02:00
218b79188b inventur + tp34: Architektur-Vorschlag Caddyfile-via-Nautobot/GC
- Handoff-Datei docs/handoff-20260827-inventur-und-architektur.md mit Drift-Befund
  (10 Punkte), Asymmetrie (bf-infra lokal-only / bf-golden-config Gitea-only),
  Inventar-Entscheidung, Architektur-Skizze (Nautobot-Datenmodell +
  GC-Workflow), Übergangsplan, Selbstkritik.
- TP34 in docs/teilprojekte.md als Stub mit Verweis auf Handoff-Architektur-
  Abschnitt. Quick-Index-Eintrag (Zeile 207).
- Erster Anwendungsfall: terpene.teilzeitladen.xyz (Mac-mini-Backend
  10.40.20.167:8890, Caddy-Block kommt als Quick-Win).
2026-08-27 21:35:53 +02:00
1d307721ad TP23 Stufe 2 + TP31 Schritt 4: AdGuard split-horizon mit .bf.-Suffix, Caddyfile .bf.-FQDNs
- AGH 110/111: conditional upstream [/bf.emsenhuber.net/]10.40.20.1
- 47 Rewrites: 16 Service->Caddy (inkl. .bf.), 10 Hosts mit .bf., suffixlose parallel
- Caddyfile: interne Sites mit .bf.-Alias (public vw/hass/n8n/gitea ohne)
- DHCP: alle 7 VLANs zeigen auf .36/.37 (domain=emsenhuber.net)
- Firewall-Regeln auf .36/.37 bereits scharf
- nas.emsenhuber.net endgueltig entfernt (war schon in 1d569fa)
- Ist-Stand-Block + Status-Tabelle nachgezogen
2026-08-26 21:22:39 +02:00
1d569fa0f5 TP31: nas.emsenhuber.net entfernt, Standortsuffix als Regel
`nas.emsenhuber.net` war nur als AGH-Rewrite auf 10.40.20.10 vorhanden,
zeigte aber nirgends hin: kein CF-CNAME, kein Caddyfile-Eintrag (der
hatte von Anfang an ds-bf.emsenhuber.net fuer Synology DSM).

Mit dem TP23-Stufe-2-Cutover wandert die DNS-Aufloesung in ein
AdGuard-Paar und der Rewrite-Satz wird neu aufgebaut. Die Regel
ist ab jetzt: Hosts, die es an mehreren Standorten gibt, heissen
immer `<host>.<site>.emsenhuber.net` — kein gemeinsamer Name
ohne Suffix.

Andere namensgleiche Hosts (macmini/mfc/tv/docker/platform-pg/
core/ap1/ap2/branch) bleiben vorerst ohne Suffix in AGH und werden
einzeln in der TP23-Stufe-2-Session bewertet.
2026-08-26 20:57:21 +02:00
9b60bcc43a opencode: Permission + Quick-Index + TP-Management-Regel
- opencode.jsonc: permission=allow + mikromcp/pve-mcp/home-assistant/cloudflare MCPs
- docs/teilprojekte.md: Quick-Index-Tabelle (22 Zeilen) für 1-Read-Statusbaum
- CLAUDE.md: TP-Management-Regel (vorschlagen -> abstimmen -> anlegen)
2026-08-26 13:39:41 +02:00
5ee0716dda Initial import from bf-network-r6.opencode — opencode migration 2026-08-26 12:44:21 +02:00