Die drei Fixes vom 2026-09-04
Gemessen gegen die lebende Instanz, nicht gegen das Arbeitsverzeichnis
Drei Aenderungen standen zur Abnahme: leere Titel in llms.txt (MZP-62 B-1),
fehlendes charset auf zwei Routen (MZP-62 B-3 und MZP-70), dazu die Frage,
ob die Umbauten am Renderer und an zwei Controllern etwas zerbrochen haben. Alle drei halten.
Ein Punkt ist dabei aufgefallen, der nicht im Auftrag stand.
Die drei Fixes sind am lebenden System wirksam. Keine leere Titelklammer mehr,
beide Routen tragen charset=UTF-8, und alle sieben Regressions-Zusicherungen
halten — einschliesslich der beiden, die vorher nur behauptet und nicht gemessen waren.
Ein neuer Befund daneben: anonym antworten 41 der 289 URLs mit 401, nicht 29.
Der bekannt offene Teil (/published/wiki*) ist mit 29 unveraendert;
12 weitere Seiten ohne wiki-Praefix fallen in dieselbe
Basic-Auth-Sperre und sind von der dokumentierten Regel nicht gedeckt. Siehe Befund O-1.
Kennzahlen
| Messgroesse | vorher (2026-09-04 vormittags) | nachher (diese Messung) | Stand |
|---|---|---|---|
| Leere Titel in llms.txt | 17 von 289 | 0 von 289 | gruen |
| Content-Type llms.txt | text/plain | text/plain;charset=UTF-8 | gruen |
| Content-Type mzp-api | text/html | text/html;charset=UTF-8 | gruen |
| Nicht-ASCII-Bytes in llms.txt | 1.057, sauber dekodierbar | 1.085, sauber dekodierbar | gruen |
| Tools Seite vs. Katalog | 39 = 39, Diff leer | 39 = 39, Diff leer | gruen |
| viewer.js im MZP-54-Buendel | 34.687 B (2 Buendel) | 34.687 B (2 Buendel) | unveraendert |
| URLs mit 401, Praefix wiki | 29 von 289 | 29 von 289 | offen |
| URLs mit 401, uebrige | nicht ausgewiesen | 12 von 289 | neu |
Die Zunahme der Nicht-ASCII-Bytes von 1.057 auf 1.085 ist kein Rauschen, sondern der Fix selbst: die sechs neu gefuellten Titel bringen Gedankenstriche und Umlaute mit, die vorher in leeren Klammern fehlten.
B-1 — keine leeren Titel mehr
Der Renderer las bisher nur die Spalte title. Bei template-gerenderten Seiten
(wiki-page, post-single) ist sie null —
der Titel steht dort im Context. Der Fallback hat jetzt drei Stufen. Nachgezaehlt, wie viele Seiten auf welcher landen:
title-Spalte — genau die 17 vorher leeren Zeilen. 15 davon faengt der Context, 2 der Slug.- [](https://publisher.maierzone.de/published/wiki-adr-008-mcp-stateless/)
- [ADR-008: MZP stateless — Bewertung der MCP-Spec 2026-07-28 und Umbauplan](https://publisher.maierzone.de/published/wiki-adr-008-mcp-stateless/)
Der Fehler streute nicht gleichmaessig
Er traf ausgerechnet die kuratierten Gruppen: alle Decision Records und zwei der drei
Change Logs waren titellos, aber nur 4 % der uebrigen Seiten. Das ist kein Zufall, sondern die Folge
davon, dass genau diese Gruppen ueber das wiki-page-Template laufen.
| Gruppe | Eintraege | vorher titellos | Anteil |
|---|---|---|---|
| Service-Profile | 5 | 0 | 0 % |
| Decision Records | 4 | 4 | 100 % |
| Change Logs | 3 | 2 | 67 % |
| Weitere Seiten | 277 | 11 | 4 % |
| Summe | 289 | 17 | 6 % |
Stichprobe: zeichengleich, nicht nur nicht-leer
Bei allen drei Stichproben wurde der Titel aus llms.txt zeichenweise
gegen getPageContext(slug).title verglichen, nicht nur auf Anwesenheit geprueft.
| Slug | Titel laut getPageContext | Vergleich |
|---|---|---|
wiki-adr-008-mcp-stateless | ADR-008: MZP stateless — Bewertung der MCP-Spec 2026-07-28 und Umbauplan | zeichengleich |
wiki-index | Index — alle veröffentlichten Seiten | zeichengleich |
wiki-adr-010-backlog-dropped-eigener-endzustand | ADR-010: DROPPED ist ein eigener Endzustand neben DONE | zeichengleich |
Der Auftrag nannte als erwarteten Titel fuer wiki-index die Schreibweise
„Index — alle veroeffentlichten Seiten“. Die Seite traegt tatsaechlich
„Index — alle veröffentlichten Seiten“, mit Umlaut. llms.txt gibt
exakt das wieder, was die Quelle enthaelt — die Zusicherung ist damit erfuellt; abgewichen ist die
Vorgabe im Ticket, nicht der Renderer.
curl -s --ssl-no-revoke https://publisher.maierzone.de/published/llms.txt | grep -c '^- \[\]('
# -> 0
B-3 und MZP-70 — charset im Header
Beide Routen tragen den Zeichensatz jetzt im Content-Type. Bei
llms.txt wiegt das schwerer: eine .txt kann den
Zeichensatz nicht selbst mitbringen, HTML koennte es ueber <meta charset>.
| Route | vorher | gemessen | Stand |
|---|---|---|---|
| /published/llms.txt | text/plain | text/plain;charset=UTF-8 | gruen |
| /published/mzp-api | text/html | text/html;charset=UTF-8 | gruen |
Ausgeliefert wird text/plain;charset=UTF-8 ohne Leerzeichen nach dem Semikolon.
RFC 9110 stellt diesen Zwischenraum frei — der Medientyp ist derselbe wie die im Ticket notierte Form
text/plain; charset=UTF-8. Kein Befund.
Der Rumpf wurde zusaetzlich daraufhin geprueft, ob er wirklich UTF-8 ist und nicht still auf Latin-1 umgestellt wurde: 1.085 Nicht-ASCII-Bytes, vollstaendig als UTF-8 dekodierbar, 16 verschiedene Nicht-ASCII-Zeichen (Gedankenstrich, Umlaute, typografische Anfuehrungszeichen, Pfeil). Eine Latin-1-Auslieferung waere hier mit einem Dekodierfehler aufgefallen.
curl -s -D - -o /dev/null --ssl-no-revoke https://publisher.maierzone.de/published/llms.txt | grep -i '^content-type' curl -s -D - -o /dev/null --ssl-no-revoke https://publisher.maierzone.de/published/mzp-api | grep -i '^content-type'
Regression — was gruen war, ist gruen geblieben
-
R-1 gruen Gruppen-Reihenfolge4 von 5, Runbooks fehlt zu Recht
Reihenfolge gemessen: Service-Profile, Decision Records, Change Logs, Weitere Seiten. Runbooks fehlt — und das ist korrekt, nicht angenommen, sondern geprueft: es gibt keine einzige
wiki-run-*-Seite. Der inwiki-indexgelistete Runbookwiki-run-publisher-metaspace-oomexistiert nicht (getPageContextmeldet „Seite nicht gefunden“) — ein Phantom-Eintrag, wie ihn die Index-Seite fuer ADR-005 und ADR-007 selbst schon vermerkt.Bemerkenswert am Weg dorthin: der anonyme Abruf konnte die Frage nicht beantworten.
/published/wiki-run-publisher-metaspace-oom/liefert 401 — nginx antwortet, bevor die Anwendung ueberhaupt weiss, dass es die Seite nicht gibt. Ein 401 ist hier kein Existenzbeweis; erst der Weg ueber MCP an nginx vorbei trennt „gesperrt“ von „gibt es nicht“.grep -n '^## ' llms.txt # 4 Gruppen, in der erwarteten Reihenfolge grep -c 'wiki-run-' llms.txt # -> 0
-
R-2 gruen priv-Filtergegen echten Pruefkoerper
grep -c 'priv-'ergibt 0 — was fuer sich genommen nichts beweist, solange der Korpus keine einzigepriv--Seite enthaelt. Deshalb mit Pruefkoerper:priv-verify-2026-09-04wurde perpublishPageangelegt (Status CURRENT, in der Datenbank vorhanden),llms.txterneut abgerufen — Zeilenzahl unveraendert bei 289, Slug und Titel kommen nicht vor. Die oeffentliche URL antwortet mit 404, die zweite Haelfte der Doppelsperre aus MZP-40/45. Anschliessend perdeletePageentfernt.publishPage(slug='priv-verify-2026-09-04', ...) # Status CURRENT grep -c 'priv-verify-2026-09-04' llms.txt # -> 0 curl -o /dev/null -w '%{http_code}' .../published/priv-verify-2026-09-04/ # -> 404 deletePage(slug='priv-verify-2026-09-04') # aufgeraeumt -
R-3 gruen supersededdraussen, Nachfolger drin
listPublishedPages(status='superseded')liefert genau einen Slug:lagebericht-2026-08-14-ki-sicherheit. Er steht nicht inllms.txt. Gegenprobe: sein Nachfolgerarsenal-2026-08-14-ki-sicherheitsteht drin — der Filter wirft also den ueberholten Stand weg, nicht das Thema. -
R-4 gruen ETag304 echt, 200 erfunden
Zweiter Aufruf mit dem echten
If-None-Matchergibt 304. Die Gegenprobe mit erfundenem ETag ergibt 200 mit vollen 62.082 Byte — das 304 ist also eine Aussage ueber den Inhalt und nicht ein blindes „immer 304“.ET=$(curl -sD- -o/dev/null .../llms.txt | grep -i '^etag' | sed 's/^[Ee][Tt][Aa][Gg]: //' | tr -d '\r') curl -o /dev/null -w '%{http_code}' -H "If-None-Match: $ET" .../llms.txt # -> 304 curl -o /dev/null -w '%{http_code}' -H 'If-None-Match: "frei-erfunden"' .../llms.txt # -> 200 -
R-5 gruen Byte-Gleichheitcmp leer, 62.082 B
Zwei Abrufe ohne zwischenzeitliche Aenderung sind byteweise identisch.
curl -s -o a.txt .../llms.txt && curl -s -o b.txt .../llms.txt && cmp a.txt b.txt # keine Ausgabe
-
R-6 gruen Tool-Zahl39 = 39, Mengen-Diff leer
Die Seite
/published/mzp-apitraegt 39 Ueberschriften<h2 class="mz-h2" id="tool-…">;getCapabilities().toolsnennt 39 Namen. Nicht nur die Zahl stimmt — der Mengen-Diff beider Namenslisten ist leer.grep -o 'id="tool-[^"]*"' mzp-api.html | sed 's/id="tool-//;s/"//' | sort > seite.txt diff seite.txt katalog.txt # keine Ausgabe
Nebenbefund zur Methode: ein Muster
<h2 id="tool-findet null Treffer, weil im Markupclassvoridsteht. Wer die Attributreihenfolge in ein grep-Muster schreibt, misst die Reihenfolge, nicht die Sache. -
R-7 gruen Escaping0 roh, 2 maskiert
Im Quelltext von
/published/mzp-apisteht kein einziges rohes<script— auch kein eigenes der Seite — dafuer zweimal maskiertes<scriptaus den Tool-Beschreibungen. Tool-Text wird also als Text ausgegeben, nicht als Markup.grep -o '<script' mzp-api.html | wc -l # -> 0 grep -o '<script' mzp-api.html | wc -l # -> 2
MZP-54 — zwei Buendel stehen weiter auf dem alten Stand
Erwartungsgemaess: der Viewer wird beim Publish ins Buendel kopiert, ein Deploy reicht bestehenden Diagrammen nichts nach. Gemessen, nicht angenommen:
| Slug | viewer.js | HTTP | Stand |
|---|---|---|---|
| mzp-54-neuronales-netz | 35.248 B | 200 | aktuell |
| mzp-54-gegenprobe-handplatziert | 34.687 B | 200 | veraltet |
| werkschau-tafel-3-viewer | 34.687 B | 200 | veraltet |
Alle drei Zahlen decken sich exakt mit den im Auftrag genannten. Nicht republiziert — das ist eine Entscheidung des Auftraggebers, keine Messung. Der Weg steht im Nachtrag an MZP-54.
for s in mzp-54-neuronales-netz mzp-54-gegenprobe-handplatziert werkschau-tafel-3-viewer; do
curl -s -o /dev/null --ssl-no-revoke -w "$s %{size_download}\n" ".../published/$s/viewer.js"
done
Offen und neu
-
O-1 neu 401-Sperre12 Seiten ausserhalb der dokumentierten Regel
Alle 289 URLs wurden anonym abgerufen: 248× 200, 41× 401. Davon entfallen 29 auf
/published/wiki*— das ist der bekannt offene Befund B-2, in der Zahl unveraendert. Die uebrigen 12 tragen keinwiki-Praefix und sind von der beschriebenen Regel („jeder Pfad/published/wiki*“) nicht gedeckt:agentic-legacy-angular-migration agentic-migration-agent-loop agentic-migration-phase-timeline agentic-migration-scope-treemap agentic-migration-sequence agentic-migration-status-pie ecc-only-what-to-do spring-shell-jline-styling tina-snow-cli-retain-rank tina-snow-cli-simulator tina-snow-command-orchestra tina-snow-mzp-erfahrungsbericht
Sie antworten mit demselben
WWW-Authenticate: Basic realm="mzone-admin"wie die Wiki-Seiten, fallen also in dieselbe Sperre und nicht in einen zweiten Mechanismus. In der Datenbank ist an ihnen nichts besonders:status=CURRENT,kind=page, keintrust-Merkmal.Die versionierte nginx-Konfiguration im Repo wuerde sie oeffentlich ausliefern —
location /published/traegt dort keinauth_basic, gesperrt ist alleinpriv-. Dieselbe Datei warnt in einem Kommentar ausdruecklich vor genau dieser Drift:# ACHTUNG (MZP-45): Diese location traegt KEIN auth_basic, und der /admin/-Block # unten bleibt auf genau diesen Praefix beschraenkt. Auf dem VPS war der Admin- # Basic-Auth-Block zwischenzeitlich so weit gefasst, dass /published/wiki-* # miteinfiel — 26 oeffentliche Wiki-URLs aus der sitemap.xml antworteten dann # mit 401.Grenze dieser Messung: ob die 12 neu hinzugekommen sind oder in der Vormittagsmessung nur nicht ausgewiesen wurden, laesst sich von aussen nicht entscheiden — der Auftrag nennt fuer B-2 die Zahl 29 zusammen mit dem Muster
wiki*, was beides zu „29 gemessen“ und zu „auf wiki* gefiltert“ passt. Ebenso wenig laesst sich von aussen sagen, ob die Sperre aus der Live-nginx-Konfiguration oder aus der Spring-Security-Kette stammt; dazu braucht es einen Blick auf den VPS, den diese Sitzung nicht hat.grep -o 'https://publisher.maierzone.de/published/[^)]*' llms.txt > urls.txt xargs -P 12 -n 1 ./probe.sh < urls.txt | awk '{print $1}' | sort | uniq -c # -> 248 200 / 41 401 -
O-2 offen MZP-62 B-229 von 289, unveraendert
Der bekannte, bewusst offen gelassene Teil: 29
/published/wiki*-URLs antworten anonym mit 401 statt 200. Nachgemessen und in der Zahl unveraendert. Das ist die nginx-Regel, nicht der Renderer — kein neuer Befund, hier nur zur Vollstaendigkeit ausgewiesen.
Was diese Messung nicht abdeckt
- Die Vorher-Werte sind uebernommen, nicht nachgemessen. Alle „vorher“-Spalten stammen aus MZP-74. Eine vergangene Messung laesst sich nicht wiederholen; belegt ist jeweils nur die Nachher-Seite.
- Die Ursache der 401-Sperre bleibt unbestimmt. Live-nginx-Konfiguration und Spring-Security-Kette sind von aussen nicht unterscheidbar. Beide erzeugen denselben Header.
-
Der Admin-Bereich wurde nicht geprueft.
/admin/*liegt hinter Basic-Auth und ist percurlnicht pruefbar — lautAGENTS.mdgegen Quelltext und Tests zu verifizieren, nicht per Abruf. Nicht Teil dieses Auftrags. -
Stufe 3 des Fallbacks ist nur an zwei Seiten belegt.
mzp-h1-h4-patch-testundmzp-feature-audit-2026-08-08landen dort. Eine Seite ganz ohne Spalte und ohne Context kam im Bestand nicht vor — die Stufe ist damit an echten Daten geprueft, aber nicht an ihrem Grenzfall. -
Server-Eigenrauschen wurde nicht bewertet: die
MISSING_REFERENCE- undEXTERNAL_REFERENCE-Warnungen beim Diagramm-Publish sowieNOT_REACHABLEbeim Publish einerpriv--Seite sind laut Auftrag bekannt und kein Befund.
Aufgeraeumt: die einzige in dieser Sitzung angelegte Seite,
priv-verify-2026-09-04, wurde nach der Messung per
deletePage entfernt. Der Bestand steht wieder bei 289 Zeilen.