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>
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>
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>
CLAUDE.md und README.md behaupteten beide noch den Inventur-Stand vom
2026-08-27: "lokal, kein Gitea-Remote (Working-Copy). Verloren bei
Festplattencrash." bzw. "kein Gitea-Remote (Sicherheitsluecke, offen)".
Live geprueft: origin = https://gitea.emsenhuber.net/admin/bf-infra.git,
main lokal und remote identisch. Die Luecke ist zu.
Dazu der Hinweis, der die Aussage traegt: ein Remote ist nur so viel wert wie
der letzte Push - der Backup-Guard (TP35 Schicht 5) ist genau diese
Erinnerung und wird nicht mit --no-verify umgangen.
docs/handoff-20260827-inventur-und-architektur.md bleibt unveraendert - der
Handoff ist ein historischer Snapshot und war an dem Tag korrekt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
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>
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>
Das Skript endete bisher mit `vlan-filtering=yes` und einer Log-Zeile -- ohne
jede Pruefung, ob der CAP wirklich CAP geworden ist.
Neu, Punkt (6) VOR dem Scharfschalten: das Skript zaehlt seine eigenen
wifi-Objekte und schreibt das Ergebnis per `:log info`. Bewusst nicht `:put`
und bewusst nicht danach -- nach `vlan-filtering=yes` kann die Sitzung
abreissen, eine Konsolenausgabe waere dann verloren. Das Log ueberlebt und
ist ueber `/log print where message~"tp28-ap3"` nachlesbar.
Sollwerte am Geraet gemessen, nicht angenommen (ap3 live, 2026-08-30):
security=0 configuration=0 channel=0 datapath=1 radios-mit-manager=2
🔴 Erwartet ist ausdruecklich NICHT "alles 0": datapath MUSS 1 sein
(dp-caps-slaves). Ein CAP mit 0 Datapaths ist der 14-Stunden-Ausfall vom
2026-08-18 -- Clients assoziieren und bekommen nie DHCP.
security/configuration/channel=0 ist der harte Beleg, dass die Werks-Inline-
Overrides weg sind: CAPsMAN haelt die Credentials, das Geraet haelt nichts.
Gegenprobe am Bestand: ap2 zeigt dieselben 0/0.
Dazu ein Abnahmeblock am Dateiende mit dem Schritt, der sich nicht im Skript
pruefen laesst: `/interface wifi radio print` AM MANAGER muss zwei Zeilen mit
CAP ap3@... zeigen (live: cap-wifi5 + cap-wifi6). Ohne diesen Schritt ist die
Abnahme wertlos, denn `remote-cap print` meldet state=Ok schon beim blossen
Verbinden -- ap1 steht seit 2026-08-30 genau so da: verbunden, gelistet, und
trotzdem funkstill, weil keine Provisioning-Regel matcht.
Am Geraet gegengeprueft: RouterOS kennt KEINEN ternaeren Operator, `a ? b : c`
ist ein syntax error. Verdikt laeuft deshalb ueber :if/:set. Der komplette
Block wurde am ap3 mit :put durchlaufen und meldet "=> OK".
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
tp28-ap3-bringup.rsc + tp28-ap3-lifeline-abbau.rsc ersetzt durch
tp28-ap3-phase1-erreichbar.rsc + tp28-ap3-phase2-cap.rsc.
Der Schnitt liegt dort, wo der Zugangsweg wechselt:
- Phase 1 laeuft ueber das Werks-WLAN MikroTik-FF169F und fasst das WLAN
bewusst NICHT an -- wer dort WLAN-Objekte abraeumt, saegt den Ast ab, auf
dem die Sitzung sitzt. Sie macht ap3 auf 10.40.99.13/24 (vlan99) erreichbar.
- Phase 2 laeuft ueber vlan99, weil dort das Werks-WLAN stirbt. Sie macht aus
dem Standalone-Werksgeraet einen reinen CAP und schaltet vlan-filtering
ZULETZT scharf.
Grund fuer die Teilung, live gemessen ueber crs326-core ether21: am Werks-
cAP-ax steht ether1 in der Interface-Liste WAN. Folge -- Discovery aus (kein
MNDP/CDP/LLDP, unsichtbar in /ip neighbor), Input-TCP zu (22/80/8291/8728),
aber ICMP erlaubt. Das Geraet PINGT also und wird leicht als "erreichbar"
fehlgelesen. Die WAN-Listen-Mitgliedschaft faellt deshalb als erste Zeile.
Nebenbefund im Kopf festgehalten: ein DHCP-Lease blieb auf `offered` und ARP
auf `failed`, weil der Port in der TAGGED-Liste von VLAN99 stand -- pvid=99
regelt nur den Eingang, die Antwort ging getaggt raus, und das versteht ein
Werksgeraet nicht. Merkregel: pvid ist Ingress, tagged/untagged ist Egress.
Der Lifeline-Abbau braucht keine eigene Datei mehr: ether2 (PoE-out, haengt
nichts) wird in Phase 2 aus der Bridge genommen und abgeschaltet, wie ap1/ap2
es mit ihrem PoE-Port halten.
Kein Secret in den Dateien: das admin-Passwort steht als Platzhalter
__ADMIN_PW__ und wird zur Laufzeit aus ~/.secrets/ap3-factory.env gezogen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
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>
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>
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>
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>
CLAUDE.md behauptete "lokal, kein Gitea-Remote (Working-Copy). Verloren bei
Festplattencrash." Live geprueft 2026-08-30:
origin = https://gitea.emsenhuber.net/admin/bf-infra.git
origin/main = b917691 (Handoff 2026-08-28)
Das Remote existiert also seit spaetestens 2026-08-28. Die Aussage war bei
der Inventur am 08-27 richtig und ist seither ueberholt -- nicht falsch
erhoben, sondern nicht mitgezogen.
Anlass: eine Session hat die Zeile uebernommen und "lokaler Master ohne
Gitea-Remote" behauptet, statt `git remote -v` zu tippen. Genau der Fall aus
dem Lessons-Block "Kommentar in Code != Verhalten". Merkregel deshalb an der
korrigierten Zeile verankert.
CLAUDE.md: Zeile direkt korrigiert (lebende Anweisungsdatei).
Handoff 2026-08-27: Originalzeile bewusst erhalten, Korrekturvermerk
darunter -- historische Fassungen werden hier nicht umgeschrieben.
Die Backup-Luecke bleibt real, hat aber eine andere Ursache als notiert:
nicht fehlende Struktur, sondern ungepushte Commits (am 08-30 waren es vier).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
Christophs Kontext explodiert am Sessionende. Handoff bündelt:
- CF-Token-Audit-Befund: CF_DNS_API_TOKEN ungültig (Code 1000 'Invalid API Token'),
Christophs Verdacht 'falscher Token extrahiert' bestätigt.
- Globale MCP-Migration FQDN → IP für gitea-mcp + n8n-mcp; cloudflare bleibt
extern (User-Direktive explizit). WARP-Pfad statt Bearer-Header wenn der
Connector intern ohne Token lebt.
- terpene W5: n8n-mcp in blaueblueten-n8n/.mcp.json (User-Zustimmung).
- Domain-Korrektur: 420.teilzeitladen.xyz ist die echte terpene-Domain
(NICHT terpene.teilzeitladen.xyz) — User-Direktive, gilt für alle.
- W1/W6 bleiben User-blocked, W7 wartet auf TP31-Schritt 5/6.
Dringend beim Nachfolger: CF-Token-Validität zuerst klären, dann erst
MCP-Migration. STATUS.md im terpene-Repo ist auf die falsche Domain
korrigieren.
Container shelly-mcp läuft seit dem mcp<2-Pin-Fix auf DS923 (10.40.20.180,
macvlan vlan20). Eintrag in der projekt-spezifischen Config analog zu pve-mcp:
type=remote, kein Bearer (Container nimmt keine Auth entgegen, lebt im
BF-LAN hinter deny-by-default — s. TP5).
Abnahme: mcp list 11/11, shelly-mcp connected, /health antwortet
200 mit psk_configured:true.
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.
Portainer-Server (pve LXC 400): 2.40.0 → 2.42.0 via Image-Swap mit Volume-Erhalt.
Pre-Upgrade-Snapshot: docker commit :2.40.0-preupgrade-20260828 (Rollback 7 d
verfügbar) + Settings/Stacks/Endpoints-JSON-Dump (40 KB, 31 Stacks, 4 Endpoints).
Instance-ID + API-Token nach Bump identisch — kein Re-Auth, kein Settings-Verlust.
portainer-mcp: offizielles PyPI-Paket mcp-portainer~=2.42.0 (193 Tools), nur
in bf-infra/opencode.jsonc, via uvx-stdio. Tool-Gate: get_guidance() einmal pro
Session zwingend vor erstem Read. Andere Projekte unberührt.
Korrekturen ggü. Handoff 2026-08-28 README:
- mcp-portainer PyPI bis 2.42.6, Docker-Hub portainer/portainer-ce nur bis 2.42.0
(unterschiedliche Versionierungspfade).
- mcp/portainer/README.md ist auf 2.42.6 formuliert und sollte nachgezogen werden.
Bestand: mcp/INVENTORY.md portainer-mcp ⛔→🟢 + Header MCP-WARP-Direktive ergänzt.
.mcp.json (war getrackt aus Commit 3426366) entfernt: opencode nutzt opencode.jsonc,
nicht .mcp.json — Claude-Code-Konvention hier irrelevant.
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).
- 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.
cloudflared-Konfigurationsmaterialien fuer TP16.3 (BFF-public-Tunnel
auf dem Edge statt cloudflared-QUIC-Workaround). Enthaelt:
- ap-bootstrap.rsc: RouterOS-Script fuer ap1/ap2 (veth, srcnat,
container-mounts, env-Vars). Token kommt aus ~/.secrets, wird per
SFTP auf den Router kopiert — kein Klartext im Script.
- cloudflared-bf-public-config.yml: tunnel-UUID + credentials-Pfad
(KEIN Secret). Ingress wird CF-Dashboard-gemanagt (config_src=cloudflare).
- .gitignore: credentials.json mit dem Tunnel-Secretbase64
(PrivateKey des Tunnels, niemals committen).
Status: vorbereitet, nicht ausgefuehrt. credentials.json bleibt lokal.
Vorbereitetes Runbook für TP31.5 (cloudflared-Container auf hAPs statt
TUN-Device-Workaround, da WARP-Connector auf ROS nicht möglich). Inhalt:
- Image-Build (RouterOS 7.x container, 70 MB Budget je AP)
- Pro AP: veth, interface-list-Mitgliedschaft, container-env
- CNAME-Flip von CF-Tunnel auf ap1/ap2 (DNS-Propagation, Rollback)
- Voraussetzungen: WAN-Healthcheck, Tunnel-Secret aus credentials.json
(siehe routeros/cloudflared/.gitignore im Folge-Commit)
Status: vorbereitet, nicht ausgeführt. Stand 2026-08-27.
Vorbereitung für Session B (Deploy auf DS923). Datei-Set reicht für
Image-Build ohne weitere Quellen aus dem Repo:
- Dockerfile: python:3.12-slim, mountbares /config ohne .env-COPY
- requirements.txt: mcp[cli]>=1.0, starlette>=0.36 (StreamableHTTP)
- BUILD.md: rsync → docker build → Portainer-Container-Deploy
- .gitignore: .env (Schema-Vorlage lokal) + __pycache__ ausklammern
Die Live-Instanz .env und der Container selbst werden in Session B
gebaut, nicht hier. Kein Secret in Git.
Eine Seite, die eine frische Session in 30 Sekunden auf Stand bringt:
TL;DR, Lese-Reihenfolge (Handoff → Anker → TP35), sofort-tun-Liste,
Übergabe-Mechanik, Mid-Action-Checkpoint, Commit-Hinweis-Regel, Was-offen.
Löst das 'Bahnhof'-Problem, das Christoph beim Session-Neustart
beobachtet hat.
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.
n8n-mcp-Accept-Header-Strike wird mit dem noch kommenden CF-Tunnel-Punkt
gelöst, nicht heute. Bearer-Authentifizierung soll einmal sauber per
Caddy/CF-Access zentralisiert werden — TP35-Schicht-2 Endform hängt davon.
Inhalt: nur Doku, keine Migration, kein neuer TP, keine Config-Änderung.
Diagnose: n8n-mcp verlangt 'Accept: application/json, text/event-stream'
(StreamableHTTP-Modus). opencode mcp list schickt nur 'application/json',
kriegt 406, wertet als failed. Echter Tool-Aufruf nutzt richtigen Header,
deshalb Sidebar grün. Bearer-Token + Server sind gesund (200 OK mit
richtigem Accept-Header, serverInfo: n8n-documentation-mcp 2.57.1).
Konsequenz: 'failed' in mcp list ist nicht 'kaputt' sondern 'Probing-Header
zu strikt'. Sidebar-Status bleibt Wahrheit.
- Neue Handoff-Datei für den konkreten nächsten Schritt (im Gegensatz zur
Inventur-Handoff, die den Master-Plan zeigt).
- Dokumentiert: cannaleo/terpene-pg entfernt, n8n-mcp repariert,
shelly-mcp-Tote entdeckt, CLAUDE.md-Erweiterung.
- Liste der offenen Aktionen für die nächste Session: bf-network-r6
archivieren, terpene-Caddyfile-Block, STATUS.md Z.47 korrigieren,
n8n-mcp auch in ~/.claude.json, gitea-mcp-Init-Problem.
- shelly-mcp läuft auf keinem Host (kein Mac-Prozess, kein Container auf
NAS/pve). INVENTORY-Handoff hatte den Stand nicht aktualisiert.
Config jetzt enabled=false, neuer Punkt im Ist-Stand-Block.
- 3 neue Lessons-for-Sessions-Regeln: MCP-Änderungen aktiv melden,
Host vor Edit verifizieren, tote MCPs ins Projekt-Repo.
- 'Was du sofort wissen musst' um shelly-mcp-Tote ergänzt.
Die Datei war bereits im Working Tree, aber ohne klaren Zweck -- jetzt
umbenannt auf .snapshot.yaml und mit Marker-Kommentar versehen, der sagt:
- das ist KEINE Transaktions-Akte (kein .json)
- das ist auch KEIN Vor-Zustand zum heutigen nas.emsenhuber.net-Edit
- das ist die AGH-Komplett-Config mit bereits angewandtem Standortsuffix
(*.bf.emsenhuber.net), die beim Bau des AGH-Paars (110/111) in der
naechsten Session als Soll-Zustand gilt.
upstream_dns ist auf /bf.emsenhuber.net/ bedingt (Suffix-Form), 26 von
30 Rewrites haben .bf.-Suffix, 4 Public (vw/hass/n8n/gitea) bleiben ohne
Suffix.
Baut auf handoff-20260825 auf (AdGuard-Paar + Split-Horizon) und ergaenzt
den Auftrag um den heute eingefuehrten Standortsuffix-Sweep: alle BF-Hosts
in AGH heissen kuenftig <host>.bf.emsenhuber.net statt ohne Suffix.
nas.emsenhuber.net ist seit 1d569fa weg (Commit direkt vorher).