[Docgen] Guest-Doku unvollständig: Updates (0/78) und HTTP-Services (0/78) werden nie gerendert, Ports aus nur einer von zwei Quellen #213

Open
opened 2026-07-20 22:36:02 +00:00 by chinux · 1 comment
Owner

Folgeissue zu #212. Waehrend der Fehleranalyse an den Agent-Daten ist aufgefallen, dass die Guest-Dokumentation mehrere vorhandene Datenquellen gar nicht rendert. Kein Bug im engeren Sinn — die Doku ist schlicht unvollstaendig, und zwar an den Stellen, die den Betrieb am meisten interessieren.

Bestandsaufnahme (78 generierte VM-Dateien, _BEISPIEL ausgenommen)

Sektion vorhanden Quelle
Belegter Speicher 49 vm_scans[vmid].disk
Docker 37 vm_scans[vmid].docker
Offene Ports 10 Tabelle VMPortSnapshot
Notizen 1 VMNote
Updates 0 vm_scans[vmid].updateswird nie gerendert
HTTP-Services 0 vm_scans[vmid].http_serviceswird nie gerendert

Zum Vergleich: die 7 Node-Dateien sind vollstaendig (PVE-Version, CPU, RAM, Kernel, Temp, Uptime, IP, Updates, Storage, Netzwerk — durchgaengig gefuellt). Das Problem sitzt ausschliesslich auf Guest-Ebene.

1. Updates fehlen vollstaendig

_vm_md() hat keine Update-Sektion. gscan["updates"] mit available / security / checked liegt vor und wird von admin_router.py:226 und update_router.py ausgewertet. Die Doku zeigt damit "Host: 90 Updates verfuegbar (Security: 3)" auf Node-Ebene und schweigt zu allen Gaesten darunter. Bei VM-Updates als Kernfeature (#123) ist das die groesste Luecke.

Fallstrick — Display-Gating fuer gestoppte Guests. admin_router.py:221 dokumentiert die verbindliche Regel (#30):

only count updates for currently RUNNING guests — a stopped VM keeps its last scan (agent_available + cached updates) and would otherwise keep the banner up forever. Display-time gating, no data loss.

Docgen muss dasselbe tun, sonst stehen in der Doku dauerhaft Phantom-Updates fuer gestoppte VMs. Nicht die Daten filtern — die Darstellung gaten, und den Zustand benennen:

| Updates | 12 verfuegbar (3 Security), geprueft 2026-07-19 |   # running
| Updates | Guest gestoppt — Stand vom 2026-06-02 |             # stopped
| Updates | nicht geprueft |                                    # checked=false
| Updates | kein Agent |                                        # kein vm_scans

Genau diese Regel ist ein Musterbeispiel dafuer, warum die Anreicherung nach services/guest_view.py gehoert (#212): sie steht heute als Kommentar in einem Router und wird beim Nachbauen zuverlaessig uebersehen.

2. HTTP-Services werden nicht genutzt

vm_scans[vmid].http_services wird vom Agent gemeldet und vom Dashboard zu Service-Links verarbeitet (deploy_router.py:336). In der Doku taucht es nicht auf.

Das ist die direkteste verfuegbare Quelle fuer die Funktion eines Guests — relevant fuer die role-Ableitung in #209, die bisher nur Docker-Images und Ports auswertet. Ein Guest ohne Docker, aber mit erkanntem HTTP-Service auf 8080, ist heute "unbekannt".

Neue Sektion ## Dienste mit Port, erkanntem Dienst/Titel und Pfad. Keine Links in die Live-Umgebung erzeugen — die Doku ist ein Snapshot, kein Dashboard.

3. Ports kommen aus zwei Quellen

Docgen liest ausschliesslich die Tabelle VMPortSnapshot (10 von 78 Dateien). Parallel liefert der Agent vm_scans[vmid].ports, das deploy_router.py:337 verwendet. Dieselbe Quellen-Spaltung wie beim Agent-Feld in #212.

Zusammenfuehren in guest_view.build_guest_view(), mit klarer Herkunftskennzeichnung in der Ausgabe — ein Port aus dem aktiven Port-Scan (mit exposure-Bewertung) ist eine andere Aussage als ein vom Agent gemeldeter Listener.

4. Belegter Speicher: Node-Storage vs. Guest-Disk

_vm_md rendert gscan["disk"] (Gast-df, also tatsaechliche Belegung im Dateisystem). Die Kopftabelle zeigt daneben maxdisk aus Proxmox (zugewiesene Groesse). Beides ist richtig, steht aber unkommentiert nebeneinander und laedt zu Fehlschluessen ein. Spaltenueberschriften eindeutig benennen ("zugewiesen" vs. "belegt im Gast").


Prompt fuer Claude Code

Erweitere die Guest-Dokumentation im Docgen von theProx um die vorhandenen,
aber nicht gerenderten Datenquellen. SETZT #212 VORAUS — die Felder kommen
aus services/guest_view.build_guest_view(), NICHT aus direkten Zugriffen auf
ld["vm_scans"] / ld["vm_qemu_scans"].

--- 1. GUEST_VIEW ERWEITERN (in #212 angelegt) ---
build_guest_view() liefert zusaetzlich:

    updates:        {"available": int, "security": int, "checked": bool,
                     "scanned_at": iso, "stale": bool}
    http_services:  [{"port": int, "scheme": "...", "title": "...", "path": "..."}]
    ports:          [{"port": int, "protocol": "...", "process": "...",
                      "exposure": "...", "source": "portscan"|"agent"}]

"stale" ist True, wenn der Guest NICHT running ist, aber ein Scan vorliegt.
Die Regel steht als Kommentar in admin_router.py:221 (#30) — dorthin
verweisen, damit sie nicht ein drittes Mal nachgebaut wird.

Ports zusammenfuehren: VMPortSnapshot (Tabelle) und vm_scans[vmid].ports
(Agent). Bei gleichem Port/Protokoll gewinnt der Port-Scan-Eintrag, weil er
die exposure-Bewertung traegt; source entsprechend setzen. Reihenfolge:
nach Portnummer.

--- 2. _vm_md() ERWEITERN ---
a) Neue Kopfzeile "Updates" mit den vier Zustaenden:
       "12 verfuegbar (3 Security), geprueft <datum>"   # running + checked
       "Guest gestoppt — Stand vom <datum>"             # stale
       "nicht geprueft"                                 # checked=false
       "kein Agent"                                     # kein vm_scans-Eintrag
   Bei stale KEINE Zahlen nennen — sonst wandern veraltete Werte in die
   Matrix und werden dort als aktuell gelesen.

b) Neue Sektion "## Dienste" aus http_services:
       | Port | Schema | Titel | Pfad |
   Nur rendern wenn nicht leer. KEINE klickbaren Links erzeugen — die Doku
   ist ein Snapshot, kein Dashboard.

c) Sektion "## Offene Ports" um die Spalte "Quelle" ergaenzen
   (Port-Scan | Agent).

d) Sektion "## Belegter Speicher": Spalten eindeutig benennen. In der
   Kopftabelle "Disk (zugewiesen)" beibehalten, in der Sektion
   "belegt im Gast" ergaenzen, damit maxdisk und df nicht verwechselt werden.

--- 3. FRONTMATTER (#209) ERGAENZEN ---
    updates_available: <int>    # nur wenn running + checked, sonst weglassen
    updates_security: <int>     # dito
    updates_stale: true         # nur wenn stale
    services: <int>
Weglassen statt 0 schreiben, wenn der Wert nicht belastbar ist — ein
fehlendes Property ist in Obsidian filterbar, eine falsche 0 nicht
erkennbar.

--- 4. MATRIX + MOC (#209) ---
Matrix-Spalte "Updates" ergaenzen (leer bei stale/kein Agent).
_MOC.md um zwei Arbeitslisten erweitern:
  - "Guests mit Security-Updates" (nur running + checked)
  - "Guests ohne Update-Pruefung" (Agent vorhanden, checked=false)
Zusammen mit "Guests ohne Agent" aus #212 ergibt das eine belastbare
Handlungsliste statt einer reinen Bestandsaufnahme.

--- 5. ROLE-ABLEITUNG (#209) NACHSCHAERFEN ---
_derive_role() bekommt http_services als zusaetzliche Quelle, eingeordnet
zwischen Docker-Images und Port-Heuristik. Ein erkannter HTTP-Titel ist
aussagekraeftiger als eine nackte Portnummer.

--- 6. TESTS ---
server/tests/test_docgen_guest_sections.py:
  - running + checked -> Zahlen erscheinen
  - stopped + Scan vorhanden -> "gestoppt", KEINE Zahlen, updates_stale im
    Frontmatter, keine Zahlen in der Matrix
  - checked=false -> "nicht geprueft"
  - kein vm_scans -> "kein Agent"
  - Port-Merge: gleicher Port aus beiden Quellen erscheint EINMAL mit
    source=portscan
  - http_services leer -> Sektion fehlt ganz (kein leerer Tabellenkopf)
  - _derive_role nutzt http_services, wenn kein Docker vorliegt

--- 7. VERIFIKATION ---
Nach einem echten Lauf gegen den Bestand in die Task-Summary schreiben:
"Guests: 78 · mit Agent: N · mit Updates-Daten: N · mit Diensten: N".
Die Zahlen muessen zu #212 passen — wenn "mit Agent" und "mit Updates-Daten"
stark auseinanderlaufen, stimmt etwas mit dem Scan-Intervall nicht.

Definition of Done

  • Update-Status in jeder Guest-Datei, mit korrektem Gating fuer gestoppte Guests
  • Keine Zahlen bei veralteten Scans — weder in der Datei noch im Frontmatter noch in der Matrix
  • ## Dienste-Sektion aus http_services
  • Ports aus beiden Quellen zusammengefuehrt, Herkunft sichtbar
  • zugewiesen vs. belegt im Gast nicht mehr verwechselbar
  • MOC enthaelt die drei Arbeitslisten (ohne Agent / Security-Updates / ohne Pruefung)
  • role-Ableitung nutzt HTTP-Services

Nachtrag: Updates entfallen — Doku ist strukturell, nicht zustandsbezogen

Der Update-Teil dieses Issues wird ersatzlos gestrichen. Punkt 1 ("Updates fehlen vollstaendig") und alle davon abhaengigen Anteile im CC-Prompt (Update-Kopfzeile, updates_*-Frontmatter, Matrix-Spalte "Updates", MOC-Arbeitslisten zu Security-Updates und fehlender Pruefung) sind hinfaellig.

Begruendung: derselbe Massstab, mit dem CVEs aus #209 geflogen sind. Updates sind Zustand, kein Strukturmerkmal — hochfrequent, beim Lesen bereits veraltet, und in einer taeglich committeten Snapshot-Doku erzeugen sie Diff-Rauschen, das echte Infrastruktur-Aenderungen ueberdeckt. Updates gehoeren ins Dashboard (#123) und ins Task-Center, nicht ins Vault. Die ganze Diskussion um Display-Gating fuer gestoppte Guests (#30) entfaellt damit ebenfalls — sie war nur noetig, weil die Zahlen ueberhaupt in die Doku sollten.

Was von diesem Issue bleibt:

  • ## Dienste aus http_services (Punkt 2)
  • Ports aus beiden Quellen zusammenfuehren (Punkt 3)
  • zugewiesen vs. belegt im Gast eindeutig benennen (Punkt 4)

Was hinzukommt: Die Docker-Erfassung ist jetzt der wichtigste Baustein, weil sie zusammen mit dem Dienste-Inventar (#215) die Funktionserkennung traegt. Docker-Sektionen erscheinen aktuell in 37 von 78 Dateien; nach #212 ist zu pruefen, ob diese Zahl zur Realitaet passt oder ob dort dieselbe Fehlerklasse steckt wie beim Agent-Feld.

Die Funktions-/Rollenerkennung selbst wandert vollstaendig nach #216.

Folgeissue zu #212. Waehrend der Fehleranalyse an den Agent-Daten ist aufgefallen, dass die Guest-Dokumentation mehrere vorhandene Datenquellen gar nicht rendert. Kein Bug im engeren Sinn — die Doku ist schlicht unvollstaendig, und zwar an den Stellen, die den Betrieb am meisten interessieren. ## Bestandsaufnahme (78 generierte VM-Dateien, `_BEISPIEL` ausgenommen) | Sektion | vorhanden | Quelle | |---|---|---| | Belegter Speicher | 49 | `vm_scans[vmid].disk` | | Docker | 37 | `vm_scans[vmid].docker` | | Offene Ports | 10 | Tabelle `VMPortSnapshot` | | Notizen | 1 | `VMNote` | | **Updates** | **0** | `vm_scans[vmid].updates` — **wird nie gerendert** | | **HTTP-Services** | **0** | `vm_scans[vmid].http_services` — **wird nie gerendert** | Zum Vergleich: die 7 Node-Dateien sind vollstaendig (PVE-Version, CPU, RAM, Kernel, Temp, Uptime, IP, Updates, Storage, Netzwerk — durchgaengig gefuellt). Das Problem sitzt ausschliesslich auf Guest-Ebene. ## 1. Updates fehlen vollstaendig `_vm_md()` hat keine Update-Sektion. `gscan["updates"]` mit `available` / `security` / `checked` liegt vor und wird von `admin_router.py:226` und `update_router.py` ausgewertet. Die Doku zeigt damit "Host: 90 Updates verfuegbar (Security: 3)" auf Node-Ebene und schweigt zu allen Gaesten darunter. Bei VM-Updates als Kernfeature (#123) ist das die groesste Luecke. **Fallstrick — Display-Gating fuer gestoppte Guests.** `admin_router.py:221` dokumentiert die verbindliche Regel (#30): > only count updates for currently RUNNING guests — a stopped VM keeps its last scan (agent_available + cached updates) and would otherwise keep the banner up forever. Display-time gating, no data loss. Docgen muss dasselbe tun, sonst stehen in der Doku dauerhaft Phantom-Updates fuer gestoppte VMs. Nicht die Daten filtern — die Darstellung gaten, und den Zustand benennen: | Updates | 12 verfuegbar (3 Security), geprueft 2026-07-19 | # running | Updates | Guest gestoppt — Stand vom 2026-06-02 | # stopped | Updates | nicht geprueft | # checked=false | Updates | kein Agent | # kein vm_scans Genau diese Regel ist ein Musterbeispiel dafuer, warum die Anreicherung nach `services/guest_view.py` gehoert (#212): sie steht heute als Kommentar in einem Router und wird beim Nachbauen zuverlaessig uebersehen. ## 2. HTTP-Services werden nicht genutzt `vm_scans[vmid].http_services` wird vom Agent gemeldet und vom Dashboard zu Service-Links verarbeitet (`deploy_router.py:336`). In der Doku taucht es nicht auf. Das ist die direkteste verfuegbare Quelle fuer die **Funktion** eines Guests — relevant fuer die `role`-Ableitung in #209, die bisher nur Docker-Images und Ports auswertet. Ein Guest ohne Docker, aber mit erkanntem HTTP-Service auf 8080, ist heute "unbekannt". Neue Sektion `## Dienste` mit Port, erkanntem Dienst/Titel und Pfad. Keine Links in die Live-Umgebung erzeugen — die Doku ist ein Snapshot, kein Dashboard. ## 3. Ports kommen aus zwei Quellen Docgen liest ausschliesslich die Tabelle `VMPortSnapshot` (10 von 78 Dateien). Parallel liefert der Agent `vm_scans[vmid].ports`, das `deploy_router.py:337` verwendet. Dieselbe Quellen-Spaltung wie beim Agent-Feld in #212. Zusammenfuehren in `guest_view.build_guest_view()`, mit klarer Herkunftskennzeichnung in der Ausgabe — ein Port aus dem aktiven Port-Scan (mit `exposure`-Bewertung) ist eine andere Aussage als ein vom Agent gemeldeter Listener. ## 4. Belegter Speicher: Node-Storage vs. Guest-Disk `_vm_md` rendert `gscan["disk"]` (Gast-`df`, also tatsaechliche Belegung im Dateisystem). Die Kopftabelle zeigt daneben `maxdisk` aus Proxmox (zugewiesene Groesse). Beides ist richtig, steht aber unkommentiert nebeneinander und laedt zu Fehlschluessen ein. Spaltenueberschriften eindeutig benennen ("zugewiesen" vs. "belegt im Gast"). --- ## Prompt fuer Claude Code ``` Erweitere die Guest-Dokumentation im Docgen von theProx um die vorhandenen, aber nicht gerenderten Datenquellen. SETZT #212 VORAUS — die Felder kommen aus services/guest_view.build_guest_view(), NICHT aus direkten Zugriffen auf ld["vm_scans"] / ld["vm_qemu_scans"]. --- 1. GUEST_VIEW ERWEITERN (in #212 angelegt) --- build_guest_view() liefert zusaetzlich: updates: {"available": int, "security": int, "checked": bool, "scanned_at": iso, "stale": bool} http_services: [{"port": int, "scheme": "...", "title": "...", "path": "..."}] ports: [{"port": int, "protocol": "...", "process": "...", "exposure": "...", "source": "portscan"|"agent"}] "stale" ist True, wenn der Guest NICHT running ist, aber ein Scan vorliegt. Die Regel steht als Kommentar in admin_router.py:221 (#30) — dorthin verweisen, damit sie nicht ein drittes Mal nachgebaut wird. Ports zusammenfuehren: VMPortSnapshot (Tabelle) und vm_scans[vmid].ports (Agent). Bei gleichem Port/Protokoll gewinnt der Port-Scan-Eintrag, weil er die exposure-Bewertung traegt; source entsprechend setzen. Reihenfolge: nach Portnummer. --- 2. _vm_md() ERWEITERN --- a) Neue Kopfzeile "Updates" mit den vier Zustaenden: "12 verfuegbar (3 Security), geprueft <datum>" # running + checked "Guest gestoppt — Stand vom <datum>" # stale "nicht geprueft" # checked=false "kein Agent" # kein vm_scans-Eintrag Bei stale KEINE Zahlen nennen — sonst wandern veraltete Werte in die Matrix und werden dort als aktuell gelesen. b) Neue Sektion "## Dienste" aus http_services: | Port | Schema | Titel | Pfad | Nur rendern wenn nicht leer. KEINE klickbaren Links erzeugen — die Doku ist ein Snapshot, kein Dashboard. c) Sektion "## Offene Ports" um die Spalte "Quelle" ergaenzen (Port-Scan | Agent). d) Sektion "## Belegter Speicher": Spalten eindeutig benennen. In der Kopftabelle "Disk (zugewiesen)" beibehalten, in der Sektion "belegt im Gast" ergaenzen, damit maxdisk und df nicht verwechselt werden. --- 3. FRONTMATTER (#209) ERGAENZEN --- updates_available: <int> # nur wenn running + checked, sonst weglassen updates_security: <int> # dito updates_stale: true # nur wenn stale services: <int> Weglassen statt 0 schreiben, wenn der Wert nicht belastbar ist — ein fehlendes Property ist in Obsidian filterbar, eine falsche 0 nicht erkennbar. --- 4. MATRIX + MOC (#209) --- Matrix-Spalte "Updates" ergaenzen (leer bei stale/kein Agent). _MOC.md um zwei Arbeitslisten erweitern: - "Guests mit Security-Updates" (nur running + checked) - "Guests ohne Update-Pruefung" (Agent vorhanden, checked=false) Zusammen mit "Guests ohne Agent" aus #212 ergibt das eine belastbare Handlungsliste statt einer reinen Bestandsaufnahme. --- 5. ROLE-ABLEITUNG (#209) NACHSCHAERFEN --- _derive_role() bekommt http_services als zusaetzliche Quelle, eingeordnet zwischen Docker-Images und Port-Heuristik. Ein erkannter HTTP-Titel ist aussagekraeftiger als eine nackte Portnummer. --- 6. TESTS --- server/tests/test_docgen_guest_sections.py: - running + checked -> Zahlen erscheinen - stopped + Scan vorhanden -> "gestoppt", KEINE Zahlen, updates_stale im Frontmatter, keine Zahlen in der Matrix - checked=false -> "nicht geprueft" - kein vm_scans -> "kein Agent" - Port-Merge: gleicher Port aus beiden Quellen erscheint EINMAL mit source=portscan - http_services leer -> Sektion fehlt ganz (kein leerer Tabellenkopf) - _derive_role nutzt http_services, wenn kein Docker vorliegt --- 7. VERIFIKATION --- Nach einem echten Lauf gegen den Bestand in die Task-Summary schreiben: "Guests: 78 · mit Agent: N · mit Updates-Daten: N · mit Diensten: N". Die Zahlen muessen zu #212 passen — wenn "mit Agent" und "mit Updates-Daten" stark auseinanderlaufen, stimmt etwas mit dem Scan-Intervall nicht. ``` ## Definition of Done - [ ] Update-Status in jeder Guest-Datei, mit korrektem Gating fuer gestoppte Guests - [ ] Keine Zahlen bei veralteten Scans — weder in der Datei noch im Frontmatter noch in der Matrix - [ ] `## Dienste`-Sektion aus `http_services` - [ ] Ports aus beiden Quellen zusammengefuehrt, Herkunft sichtbar - [ ] `zugewiesen` vs. `belegt im Gast` nicht mehr verwechselbar - [ ] MOC enthaelt die drei Arbeitslisten (ohne Agent / Security-Updates / ohne Pruefung) - [ ] `role`-Ableitung nutzt HTTP-Services --- ## Nachtrag: Updates entfallen — Doku ist strukturell, nicht zustandsbezogen Der Update-Teil dieses Issues wird **ersatzlos gestrichen**. Punkt 1 ("Updates fehlen vollstaendig") und alle davon abhaengigen Anteile im CC-Prompt (Update-Kopfzeile, `updates_*`-Frontmatter, Matrix-Spalte "Updates", MOC-Arbeitslisten zu Security-Updates und fehlender Pruefung) sind hinfaellig. Begruendung: derselbe Massstab, mit dem CVEs aus #209 geflogen sind. Updates sind Zustand, kein Strukturmerkmal — hochfrequent, beim Lesen bereits veraltet, und in einer taeglich committeten Snapshot-Doku erzeugen sie Diff-Rauschen, das echte Infrastruktur-Aenderungen ueberdeckt. Updates gehoeren ins Dashboard (#123) und ins Task-Center, nicht ins Vault. Die ganze Diskussion um Display-Gating fuer gestoppte Guests (#30) entfaellt damit ebenfalls — sie war nur noetig, weil die Zahlen ueberhaupt in die Doku sollten. **Was von diesem Issue bleibt:** - `## Dienste` aus `http_services` (Punkt 2) - Ports aus beiden Quellen zusammenfuehren (Punkt 3) - `zugewiesen` vs. `belegt im Gast` eindeutig benennen (Punkt 4) **Was hinzukommt:** Die Docker-Erfassung ist jetzt der wichtigste Baustein, weil sie zusammen mit dem Dienste-Inventar (#215) die Funktionserkennung traegt. Docker-Sektionen erscheinen aktuell in 37 von 78 Dateien; nach #212 ist zu pruefen, ob diese Zahl zur Realitaet passt oder ob dort dieselbe Fehlerklasse steckt wie beim Agent-Feld. Die Funktions-/Rollenerkennung selbst wandert vollstaendig nach #216.
Author
Owner

Updates raus — gleiche Begruendung wie bei den CVEs: vergaenglicher Zustand, gehoert nicht in eine strukturelle Doku. Nachtrag am Issue-Ende, Punkt 1 des CC-Prompts ist hinfaellig.

Schwerpunkt verschiebt sich damit auf Docker + Dienste als Grundlage der Funktionserkennung. Die Ableitung selbst liegt jetzt in #216.

Updates raus — gleiche Begruendung wie bei den CVEs: vergaenglicher Zustand, gehoert nicht in eine strukturelle Doku. Nachtrag am Issue-Ende, Punkt 1 des CC-Prompts ist hinfaellig. Schwerpunkt verschiebt sich damit auf Docker + Dienste als Grundlage der Funktionserkennung. Die Ableitung selbst liegt jetzt in #216.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
chinux/theProx#213
No description provided.