diff --git a/CHATLOG.md b/CHATLOG.md index 10b3192..4667da3 100644 --- a/CHATLOG.md +++ b/CHATLOG.md @@ -790,3 +790,10 @@ Test, WLAN/Bonding/PPPoE-Live-Tests). Merksatz für künftige neue Dateien notiert. Nach `xcodegen generate` 58 Unit-Tests grün (inkl. `ExpertViewModelTests` jetzt tatsächlich ausgeführt). HANDOFF.md aktualisiert, Commit + Push. +- "neuer fehler: no such item (4)... /ip/route/set" → Nutzer bestätigte + auf Nachfrage per `/ip route print detail`: Route ist dynamisch + (`D`-Flag, `distance=0`, automatisch durch die Bridge-IP angelegt). + Bug 28: dynamische Routen bieten jetzt gar kein "Bearbeiten" mehr an + (`distance=0` als verlässliches Signal, da RouterOS' "dynamic"-Flag + nicht in `print terse` steht). 59 Unit-Tests grün, HANDOFF.md + aktualisiert, Commit + Push. diff --git a/HANDOFF.md b/HANDOFF.md index b4bc45a..c531ed9 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -567,6 +567,19 @@ lief — Xcodegen erzeugt die `sources`-Dateiliste einmalig beim Generieren, eine neu angelegte Datei taucht im generierten `.xcodeproj` nicht automatisch auf. **Merksatz: nach jeder neu angelegten Datei `xcodegen generate` erneut laufen lassen, nicht nur nach Datei-Edits.** +**Auch nach dem Bug-27-Fix scheiterte dieselbe Route noch, jetzt mit +"no such item (4)"** (Bug 28) — der `/ip route print detail`-Gegencheck +bestätigte: die Route ist dynamisch (`D`-Flag, `distance=0`, automatisch +angelegt durch die IP-Adresse auf `bridge`). RouterOS' eigenes +"dynamic"-Flag steht nicht zuverlässig in `print terse` (dasselbe +Problem schon bei DHCP-Leases dokumentiert, siehe `LanDevice.swift`), +aber `distance=0` ist ein verlässliches Signal — keine echte statische +Route kann das haben (RouterOS erzwingt 1–255 bei `set`). Fix: +Übersicht-Tab bietet für Routen mit `distance=0` gar kein "Bearbeiten" +mehr an (`editTarget=nil`) — die `.id` einer dynamischen Route ist +ohnehin nicht stabil, RouterOS kann sie jederzeit neu anlegen. 59 +Unit-Tests grün (neuer Test `OverviewGraphTests. +testDynamicRouteHasNoEditTarget`). ## `xcodebuild test` hängt — Gatekeeper, kein Code-Bug @@ -850,16 +863,19 @@ Bezug zu einem Router-Item). **Live gegen Hardware verifiziert** — Nutzer bestätigte Kommentar- Änderung an einer Firewall-Regel über den neuen Bearbeiten-Weg -("funktioniert"). Direkt danach beim Weitertesten drei echte Bugs in der -gemeinsamen Bearbeiten-Logik gefunden (Bug 25, 26, 27 — siehe Bug-Liste -oben): geleertes Textfeld blieb bestehen, Route-Bearbeiten scheiterte -erst an einem nur-lesbaren Feld (`immediate-gw`), dann am unveränderten -`distance=0` einer dynamischen Route. Alle drei betreffen `ExpertViewModel. -pendingCommand` und damit **auch den Experte-Tab direkt**, nicht nur den -neuen Übersicht-Weg — gefixt (vereinheitlicht: nur geänderte Felder -werden beim Bearbeiten gesendet, kuratiert wie unkuratiert), alle 58 -Unit-Tests grün (inkl. neuer `ExpertViewModelTests` und `OverviewGraphTests. -testEditableNodesCarryTheirRouterOSMenuAndItemID`). +("funktioniert"). Direkt danach beim Weitertesten vier echte Bugs +gefunden (Bug 25–28 — siehe Bug-Liste oben): geleertes Textfeld blieb +bestehen, Route-Bearbeiten scheiterte erst an einem nur-lesbaren Feld +(`immediate-gw`), dann am unveränderten `distance=0` einer dynamischen +Route, schließlich an deren instabiler `.id` ("no such item"). Bug +25–27 betreffen `ExpertViewModel.pendingCommand` und damit **auch den +Experte-Tab direkt**, nicht nur den neuen Übersicht-Weg — gefixt +(vereinheitlicht: nur geänderte Felder werden beim Bearbeiten gesendet, +kuratiert wie unkuratiert). Bug 28 gefixt in `OverviewViewModel`: Routen +mit `distance=0` (dynamisch) bieten gar kein "Bearbeiten" mehr an. 59 +Unit-Tests grün (inkl. neuer `ExpertViewModelTests` und +`OverviewGraphTests.testEditableNodesCarryTheirRouterOSMenuAndItemID`/ +`testDynamicRouteHasNoEditTarget`). ## Stand der Milestones @@ -960,13 +976,15 @@ testEditableNodesCarryTheirRouterOSMenuAndItemID`). verdrängt) plus neue Fähigkeit: Knoten (IP-Adresse, Pool, DHCP-Server/ -Netzwerk/-Client, Route, Firewall-Filter-/NAT-Regel, WireGuard-Peer) direkt über dieselbe Sheet wie im Experte-Tab bearbeiten und - zurückschreiben. Dabei drei Bugs in der gemeinsamen Bearbeiten-Logik - gefunden+gefixt (Bug 25, 26, 27 — betreffen auch den Experte-Tab - direkt): geleertes Feld blieb bestehen statt geleert zu werden, - Route-Bearbeiten scheiterte erst an einem nur-lesbaren Feld - (`immediate-gw`), dann am unveränderten `distance=0` einer dynamischen - Route. **Live gegen Hardware verifiziert** — Nutzer bestätigte - Kommentar-Änderung an einer Firewall-Regel über den neuen Weg + zurückschreiben. Dabei vier Bugs gefunden+gefixt (Bug 25–28): geleertes + Feld blieb bestehen statt geleert zu werden, Route-Bearbeiten + scheiterte an einem nur-lesbaren Feld (`immediate-gw`), dann am + unveränderten `distance=0` einer dynamischen Route, schließlich an + deren instabiler `.id`. Bug 25–27 betreffen auch den Experte-Tab + direkt, Bug 28 ist Übersicht-spezifisch (dynamische Routen bieten kein + "Bearbeiten" mehr an). **Live gegen Hardware verifiziert** — Nutzer + bestätigte Kommentar-Änderung an einer Firewall-Regel über den neuen + Weg ("funktioniert"). ## Nächste Schritte diff --git a/RouterOSAssistant/Features/Overview/OverviewViewModel.swift b/RouterOSAssistant/Features/Overview/OverviewViewModel.swift index 4e8e1d5..3e160e6 100644 --- a/RouterOSAssistant/Features/Overview/OverviewViewModel.swift +++ b/RouterOSAssistant/Features/Overview/OverviewViewModel.swift @@ -213,11 +213,20 @@ final class OverviewViewModel: ObservableObject { guard let dst = item.fields["dst-address"] else { continue } let gateway = item.fields["gateway"] ?? "?" let id = "route:\(index)" + // Dynamic/connected routes (auto-created by an IP address on an interface) always + // report distance=0 — no static route can ever have that (RouterOS enforces 1-255 on + // `set`). RouterOS' own "dynamic" flag isn't reliably present in `print terse` output + // (confirmed live for DHCP leases too, see `LanDevice.swift`), so distance=0 is the + // one dependable signal available here. Editing such a route failed live two ways: + // resending its own distance=0 was rejected outright, and its `.id` isn't stable + // (RouterOS can recreate/renumber a dynamic route at any time), so even a + // comment-only edit could hit "no such item" if the id had since changed underneath. + let isDynamic = item.fields["distance"] == "0" nodes.append(OverviewNode( id: id, category: .route, kind: "route", title: dst, subtitle: "über \(gateway)", detail: sortedDetail(item.fields), - editTarget: .init(menuPath: "/ip route", restPath: "ip/route", itemID: item.id) + editTarget: isDynamic ? nil : .init(menuPath: "/ip route", restPath: "ip/route", itemID: item.id) )) if knownInterfaceNames.contains(gateway) { edges.append(OverviewEdge(from: nodeID(.interface, gateway), to: id, label: nil, kind: .route)) diff --git a/RouterOSAssistantTests/OverviewGraphTests.swift b/RouterOSAssistantTests/OverviewGraphTests.swift index 4acd9ed..f985b6d 100644 --- a/RouterOSAssistantTests/OverviewGraphTests.swift +++ b/RouterOSAssistantTests/OverviewGraphTests.swift @@ -135,4 +135,19 @@ final class OverviewGraphTests: XCTestCase { let addressList = graph.nodes.first { $0.id == "Firewall & NAT:addrlist:gesperrt" } XCTAssertNil(addressList?.editTarget) } + + /// A dynamic/connected route (distance=0, auto-created by an interface address) must not be + /// offered for editing — confirmed live: RouterOS rejects resending its own distance=0 + /// ("value of distance out of range (1...255)"), and its .id isn't stable either. + func testDynamicRouteHasNoEditTarget() { + let graph = OverviewViewModel.buildGraph( + interfaces: [], bridgePorts: [], vlans: [], wireguardPeers: [], addresses: [], + pools: [], dhcpServers: [], dhcpNetworks: [], dhcpClients: [], + routes: [item(["dst-address": "192.168.88.0/24", "gateway": "bridge", "distance": "0"], id: "*201C5060")], + filterRules: [], natRules: [], addressLists: [] + ) + + let route = graph.nodes.first { $0.id == "route:0" } + XCTAssertNil(route?.editTarget) + } }