[Master] Weg zum MCP-Leseserver: Sequenz, getroffene Entscheidungen, gemessene Grundlagen #36

Closed
opened 2026-09-01 21:19:07 +00:00 by torben · 5 comments
Owner

Sammel-Issue für den Weg zum MCP-Leseserver. Es hat nie selbst implementiert — es hielt die
Reihenfolge, die getroffenen Entscheidungen und die Messungen, auf denen der Entwurf steht, damit
eine Sitzung kalt einsteigen kann, ohne die Debatte vom 2026-09-01 zu wiederholen.

Ziel war: chemenu bekommt einen zweiten Konsumenten. CLI und MCP-Server sind zwei Adapter
auf denselben Kern — nicht ein CLI mit angeschraubter Netzwerkschnittstelle. Das ist erreicht.

Geschlossen am 2026-09-04. Die Sequenz ist abgearbeitet, der Server läuft, alle zehn Befunde
sind adressiert. Das letzte offene Kriterium — der Nachweis über ein Deployment — ist nach #37
übernommen, wo es hingehört: es hängt vollständig am Container-Image und an keiner Frage, die
dieses Issue noch beantworten könnte. #37 ist damit das einzige verbleibende Issue auf diesem
Weg.
Was hier stehen bleibt, ist das Entscheidungsprotokoll und die gemessene Grundlage; beides
ist ausdrücklich nicht neu aufzumachen.


Sequenz — abgeschlossen am 2026-09-02

# Issue Version Status
0 #34 — Publish-Remote-Gate scharf stellen 2.2.3 geschlossen
1 #33 — Härtung des Lesepfads 2.2.4 geschlossen
2 #31 — Root-Auflösung + Bibliotheksgrenze 2.3.0 geschlossen
3 #19 — MCP-Leseserver 2.4.0 geschlossen

Der Server liegt in tools/chemenu/mcp/ und läuft auf beiden Transports (stdio,
streamable-http) gegen den echten Korpus. Menschendoku: INSTALL-MCP.md (2.4.1, wird von
dist export ausgeliefert), Betriebsablauf in instructions/mcp-read-server.md. Einzelheiten je
Issue in dessen Abschlusskommentar.

Nicht mehr auf dem kritischen Pfad, unverändert offen: #32 (Ingest-Queue, hing an #19, dessen
Vorbedingung erfüllt ist; teilt sich die Mechanik mit #16) · #35 (semantisches Backend, Auslöser
ist ein Korpus, an dem rg nicht mehr trägt) · #6 (Backlink-Ranking, läuft durch dieselbe Fusion
wie #35 und ist seit 2026-09-04 als status/blocked an #35 gehängt).


Entschieden — nicht neu aufmachen

Frage Entscheidung In einem Satz
Plattform Python. Kein Go, auch nicht als Option Die drei Go-Argumente lösen sich am eigenen Vorhaben auf; Herleitung im Kommentar zu #19
Authentifizierung Traefik-Middleware Nicht sauber authentifizierte Zugriffe erreichen den Python-Prozess nicht. Umgesetzt: https://gitea.nehmer.net/torben/gitea-mcp-forward-auth
Rate Limiting ebenfalls Traefik Vor den Prozess, nicht in den Iteration Budget Gate
Aufrufweg Direktimport, nicht Subprocess Subprocess läuft nach 60 lint/types-Aufrufen in den Budget-Gate; eine argv-Allowlist kostet so viel wie der Direktimport
Wire-Contract die --json-Formen der CLI Ein Contract statt zwei; die CLI wird zur ausführbaren Spezifikation, Golden-Test hält beide zusammen
Budget-Gate im Server nein Er begrenzt Agenten-Sessions, nicht Nutzer. Ihn als Rate Limiter zu benutzen verwässert ihn
Session-Scoping erst mit #32 Eine Suchanfrage ist nicht zurechenbar, eine Einreichung schon
Staleness Commit-SHA in jeder Antwort Macht aus einer stillen veralteten Antwort eine sichtbare; derselbe SHA ist der Cache-Key
Sync Polling (git fetch && git reset --hard) Kein eingehender Endpunkt, keine Signaturprüfung. Webhook ist spätere Optimierung
Retrieval hinter der vorhandenen Backend-Registry search/registry.py: „a new module plus one line here"
Deployment gehört nicht in dieses Repo Private Infrastruktur, öffentlicher Tracker

Gemessene Grundlage — Prognose hat gehalten

Ausgangsmessung 2026-09-01, Nachmessung nach #33/#31 am 2026-09-02:

Prognose gemessen
Korpus-Parse (176 Seiten, CSafeLoader + Cache) 246 → 82 ms 265 → 54 ms
wikitool search end-to-end 593 ms 593 → 347 ms

Die verbleibenden ~262 ms sind Modulimport (typer, rich, jsonschema, yaml); im residenten
Prozess entfallen sie, womit die ursprüngliche Schätzung „grob 100 ms" steht. Der
Korpus-Parse skaliert linear mit der Korpusgröße; Zielgröße der privaten Instanz sind wenige
Tausend Seiten.

Korrektur zum Alias-Befund: das Regressionsdokument ist 267 Byte → 672.603 Knoten (9ⁿ), nicht
322 Byte → 797.161 (3ⁿ) — dieselbe Eigenschaft, eigene Messung.

Weitere belastbare Zahlen: Lese-Kern importiert an Fremdcode genau zwei Pakete (yaml,
jsonschema) — die „~14 transitiven Pakete" sind ein pip list-Artefakt des CLI-Kopfs.
Lese-Slice 2.442 von 11.895 Zeilen Produktivcode. git_publish.py (1.140 Zeilen) liegt
strukturell außerhalb.


Die zehn Befunde — alle adressiert

Alle in der Sitzung vom 2026-09-01 reproduziert, keiner vermutet; Stand nach 2.4.0:

  1. ReDoSsearch/ripgrep.py:147 gab nutzergesteuerten Regex an Pythons
    Backtracking-Engine. → #33, behoben
  2. Kein Subprozess-Timeoutsearch/ripgrep.py:102. → #33, behoben
  3. YAML ohne Alias-Budget — 267 B → 672.603 Knoten. → #33, behoben
  4. CSafeLoader ungenutzt — Faktor 3 lag brach. → #33, behoben (265 → 54 ms)
  5. Stiller Frontmatter-Verlust — kaputtes YAML wurde {}. → #33, behoben
  6. Korpus-Reparse pro Aufrufcommands/search.py:199. → #33, behoben (Cache am
    Commit-SHA)
  7. Publish-Remote-Gate inert.wikitool-remotes.json fehlte. → #34, behoben
  8. lint liest raw/-Dateinamenlint.py:230. In #19 entschieden: bleibt exponiert,
    weil er ohne mehrere Einreicher nichts zu schützen hat. Die Entscheidung gehört zu #32 und
    wird dort wieder aufgenommen, sobald es Fremdeinreichungen gibt.
  9. Bibliotheksgrenze fehltrun_search/run_lint in Modulen mit typer-Import auf
    Modulebene. → #31, behoben
  10. ripgrep-Aufruf ist sauber — kein shell=True, --fixed-strings, ---Terminator. Kein
    Befund, sondern eine zu erhaltende Eigenschaft: steht seit dem Umbau als dritte tragende
    Zusage im Modul-Docstring.

Zusätzlich vom Umbau aufgedeckt und in #31 behoben: die Testsuite hing an zwei
Abhängigkeiten, die nur hielten, weil TYPES_DIR und TypeResolver.repo_root beim Import
gebunden waren; und resolve() reichte den Root nicht ans Suchbackend durch — die Anfrage aus
dem einen Baum beantwortet, die Seiten aus dem anderen gelesen.


Ausdrücklich nicht Gegenstand

  • Go. Entschieden und geschlossen.
  • Deployment-Details (Cluster, Ingress-Hosts, Secret-Store) — private Infrastruktur, gehört
    nicht in einen öffentlichen Tracker.
  • Schreibpfad nach kb/. Der Server exponiert keine Schreib-Tools, und zwar weil die
    Funktionen dort nicht existieren, nicht weil sie gefiltert werden. #32 legt ausschließlich in
    eine Quarantäne ab und ruft nie den Compiler.
  • Recherche-Fähigkeit (#15). Läuft in die Gegenrichtung, bewusst nicht dieselbe Oberfläche.

Lose Enden — beide erledigt

  1. kb/entities/tools/qmd.md sagt „wahrscheinlich Go oder Rust" bei confidence: 0.85.
    Korrigiert am 2026-09-02: direkt gegen tobi/qmd auf GitHub geprüft — TypeScript,
    Laufzeit Node.js/Bun, sqlite-vec + node-llama-cpp. Neue Quelle
    Source - qmd - GitHub Repository, confidence_base auf 0.80 neu begründet.
  2. Es gibt keinen dauerhaften Ort für Architekturentscheidungen. Wurde #38, geschlossen
    am 2026-09-03 mit 4.3.0: docs/ als ausgelieferter, inerter Hintergrundort, Decision-Seiten
    bleiben in kb/, Decay-Ausnahme für concept_type: decision.

Nicht mitgelöst und weiterhin offen: #23 — nichts erzwingt, dass eine neue Env-Var in
_WIKITOOL_ENV landet. CHEMENU_ROOT steht dort inzwischen drin, aber von Hand eingetragen:
genau der Weg, den #23 als unzuverlässig beschreibt. Der Befund ist damit belegt statt vermutet.

Abschluss

  • #34, #33, #31, #19 geschlossen — die Sequenz ist vollständig abgearbeitet
  • Alle zehn Befunde adressiert; Befund 8 mit begründeter Entscheidung (bleibt exponiert,
    wird in #32 wieder aufgenommen)
  • Prognose gegen Messung gehalten, Zahlen oben festgehalten
  • Menschendoku steht: INSTALL-MCP.md, instructions/mcp-read-server.md
  • [→] Ein Konsument führt über die Traefik-Middleware nachweislich search gegen den Server aus
    nach #37 übernommen. Nicht gestrichen und nicht erledigt: der Nachweis braucht ein
    Deployment und dafür ein Container-Image, und dort liegen auch die neun Entscheidungen, an
    denen er hängt (Korpus im Image oder als Volume, Sync-Mechanismus, Basis-Image,
    Healthcheck, Registry-Pfad). Im Repo existiert weiterhin kein Dockerfile und kein
    Image-Workflow; .gitea/workflows/ hat ci.yml, nightly.yml, release.yml.

Warum dieses Issue trotzdem schließt: ein Master-Issue, dessen einzige verbleibende Zeile in
einem anderen Issue steht, hält nur noch sich selbst offen. Der Wert des Bodies — Entscheidungen
und Messungen — ist unabhängig von seinem Zustand lesbar, und ein geschlossenes Protokoll ist
ehrlicher über den Stand als ein offener Sammelposten, der nichts mehr steuert.

Sammel-Issue für den Weg zum MCP-Leseserver. Es hat nie selbst implementiert — es hielt die Reihenfolge, die getroffenen Entscheidungen und die Messungen, auf denen der Entwurf steht, damit eine Sitzung kalt einsteigen kann, ohne die Debatte vom 2026-09-01 zu wiederholen. **Ziel war:** `chemenu` bekommt einen zweiten Konsumenten. CLI und MCP-Server sind zwei Adapter auf denselben Kern — nicht ein CLI mit angeschraubter Netzwerkschnittstelle. Das ist erreicht. **Geschlossen am 2026-09-04.** Die Sequenz ist abgearbeitet, der Server läuft, alle zehn Befunde sind adressiert. Das letzte offene Kriterium — der Nachweis über ein Deployment — ist nach **#37** übernommen, wo es hingehört: es hängt vollständig am Container-Image und an keiner Frage, die dieses Issue noch beantworten könnte. **#37 ist damit das einzige verbleibende Issue auf diesem Weg.** Was hier stehen bleibt, ist das Entscheidungsprotokoll und die gemessene Grundlage; beides ist ausdrücklich nicht neu aufzumachen. --- ## Sequenz — abgeschlossen am 2026-09-02 | # | Issue | Version | Status | |---|---|---|---| | 0 | #34 — Publish-Remote-Gate scharf stellen | 2.2.3 | **geschlossen** | | 1 | #33 — Härtung des Lesepfads | 2.2.4 | **geschlossen** | | 2 | #31 — Root-Auflösung + Bibliotheksgrenze | 2.3.0 | **geschlossen** | | 3 | #19 — MCP-Leseserver | 2.4.0 | **geschlossen** | Der Server liegt in `tools/chemenu/mcp/` und läuft auf beiden Transports (`stdio`, `streamable-http`) gegen den echten Korpus. Menschendoku: `INSTALL-MCP.md` (2.4.1, wird von `dist export` ausgeliefert), Betriebsablauf in `instructions/mcp-read-server.md`. Einzelheiten je Issue in dessen Abschlusskommentar. **Nicht mehr auf dem kritischen Pfad, unverändert offen:** #32 (Ingest-Queue, hing an #19, dessen Vorbedingung erfüllt ist; teilt sich die Mechanik mit #16) · #35 (semantisches Backend, Auslöser ist ein Korpus, an dem `rg` nicht mehr trägt) · #6 (Backlink-Ranking, läuft durch dieselbe Fusion wie #35 und ist seit 2026-09-04 als `status/blocked` an #35 gehängt). --- ## Entschieden — nicht neu aufmachen | Frage | Entscheidung | In einem Satz | |---|---|---| | **Plattform** | **Python. Kein Go, auch nicht als Option** | Die drei Go-Argumente lösen sich am eigenen Vorhaben auf; Herleitung im Kommentar zu #19 | | **Authentifizierung** | **Traefik-Middleware** | Nicht sauber authentifizierte Zugriffe erreichen den Python-Prozess nicht. Umgesetzt: <https://gitea.nehmer.net/torben/gitea-mcp-forward-auth> | | **Rate Limiting** | ebenfalls Traefik | Vor den Prozess, **nicht** in den Iteration Budget Gate | | **Aufrufweg** | Direktimport, nicht Subprocess | Subprocess läuft nach 60 `lint`/`types`-Aufrufen in den Budget-Gate; eine argv-Allowlist kostet so viel wie der Direktimport | | **Wire-Contract** | die `--json`-Formen der CLI | Ein Contract statt zwei; die CLI wird zur ausführbaren Spezifikation, Golden-Test hält beide zusammen | | **Budget-Gate im Server** | nein | Er begrenzt Agenten-Sessions, nicht Nutzer. Ihn als Rate Limiter zu benutzen verwässert ihn | | **Session-Scoping** | erst mit #32 | Eine Suchanfrage ist nicht zurechenbar, eine Einreichung schon | | **Staleness** | Commit-SHA in jeder Antwort | Macht aus einer stillen veralteten Antwort eine sichtbare; derselbe SHA ist der Cache-Key | | **Sync** | Polling (`git fetch && git reset --hard`) | Kein eingehender Endpunkt, keine Signaturprüfung. Webhook ist spätere Optimierung | | **Retrieval** | hinter der vorhandenen Backend-Registry | `search/registry.py`: „a new module plus one line here" | | **Deployment** | gehört **nicht** in dieses Repo | Private Infrastruktur, öffentlicher Tracker | --- ## Gemessene Grundlage — Prognose hat gehalten Ausgangsmessung 2026-09-01, Nachmessung nach #33/#31 am 2026-09-02: | | Prognose | gemessen | |---|---|---| | Korpus-Parse (176 Seiten, `CSafeLoader` + Cache) | 246 → 82 ms | **265 → 54 ms** | | `wikitool search` end-to-end | 593 ms | **593 → 347 ms** | Die verbleibenden ~262 ms sind Modulimport (typer, rich, jsonschema, yaml); im residenten Prozess entfallen sie, womit die ursprüngliche Schätzung **„grob 100 ms"** steht. Der Korpus-Parse skaliert linear mit der Korpusgröße; Zielgröße der privaten Instanz sind wenige Tausend Seiten. Korrektur zum Alias-Befund: das Regressionsdokument ist 267 Byte → 672.603 Knoten (9ⁿ), nicht 322 Byte → 797.161 (3ⁿ) — dieselbe Eigenschaft, eigene Messung. Weitere belastbare Zahlen: Lese-Kern importiert an Fremdcode genau zwei Pakete (`yaml`, `jsonschema`) — die „~14 transitiven Pakete" sind ein `pip list`-Artefakt des CLI-Kopfs. Lese-Slice 2.442 von 11.895 Zeilen Produktivcode. `git_publish.py` (1.140 Zeilen) liegt strukturell außerhalb. --- ## Die zehn Befunde — alle adressiert Alle in der Sitzung vom 2026-09-01 reproduziert, keiner vermutet; Stand nach 2.4.0: 1. **ReDoS** — `search/ripgrep.py:147` gab nutzergesteuerten Regex an Pythons Backtracking-Engine. → #33, **behoben** 2. **Kein Subprozess-Timeout** — `search/ripgrep.py:102`. → #33, **behoben** 3. **YAML ohne Alias-Budget** — 267 B → 672.603 Knoten. → #33, **behoben** 4. **`CSafeLoader` ungenutzt** — Faktor 3 lag brach. → #33, **behoben** (265 → 54 ms) 5. **Stiller Frontmatter-Verlust** — kaputtes YAML wurde `{}`. → #33, **behoben** 6. **Korpus-Reparse pro Aufruf** — `commands/search.py:199`. → #33, **behoben** (Cache am Commit-SHA) 7. **Publish-Remote-Gate inert** — `.wikitool-remotes.json` fehlte. → #34, **behoben** 8. **`lint` liest `raw/`-Dateinamen** — `lint.py:230`. In #19 **entschieden: bleibt exponiert**, weil er ohne mehrere Einreicher nichts zu schützen hat. Die Entscheidung gehört zu #32 und wird dort wieder aufgenommen, sobald es Fremdeinreichungen gibt. 9. **Bibliotheksgrenze fehlt** — `run_search`/`run_lint` in Modulen mit `typer`-Import auf Modulebene. → #31, **behoben** 10. **ripgrep-Aufruf ist sauber** — kein `shell=True`, `--fixed-strings`, `--`-Terminator. Kein Befund, sondern eine zu erhaltende Eigenschaft: steht seit dem Umbau als dritte tragende Zusage im Modul-Docstring. **Zusätzlich vom Umbau aufgedeckt und in #31 behoben:** die Testsuite hing an zwei Abhängigkeiten, die nur hielten, weil `TYPES_DIR` und `TypeResolver.repo_root` beim Import gebunden waren; und `resolve()` reichte den Root nicht ans Suchbackend durch — die Anfrage aus dem einen Baum beantwortet, die Seiten aus dem anderen gelesen. --- ## Ausdrücklich nicht Gegenstand - **Go.** Entschieden und geschlossen. - **Deployment-Details** (Cluster, Ingress-Hosts, Secret-Store) — private Infrastruktur, gehört nicht in einen öffentlichen Tracker. - **Schreibpfad nach `kb/`.** Der Server exponiert keine Schreib-Tools, und zwar weil die Funktionen dort nicht existieren, nicht weil sie gefiltert werden. #32 legt ausschließlich in eine Quarantäne ab und ruft nie den Compiler. - **Recherche-Fähigkeit (#15).** Läuft in die Gegenrichtung, bewusst nicht dieselbe Oberfläche. --- ## Lose Enden — beide erledigt 1. ~~`kb/entities/tools/qmd.md` sagt „wahrscheinlich Go oder Rust" bei `confidence: 0.85`.~~ **Korrigiert am 2026-09-02**: direkt gegen `tobi/qmd` auf GitHub geprüft — TypeScript, Laufzeit Node.js/Bun, `sqlite-vec` + `node-llama-cpp`. Neue Quelle `Source - qmd - GitHub Repository`, `confidence_base` auf 0.80 neu begründet. 2. ~~Es gibt keinen dauerhaften Ort für Architekturentscheidungen.~~ Wurde **#38**, geschlossen am 2026-09-03 mit 4.3.0: `docs/` als ausgelieferter, inerter Hintergrundort, Decision-Seiten bleiben in `kb/`, Decay-Ausnahme für `concept_type: decision`. **Nicht mitgelöst und weiterhin offen: #23** — nichts erzwingt, dass eine neue Env-Var in `_WIKITOOL_ENV` landet. `CHEMENU_ROOT` steht dort inzwischen drin, aber von Hand eingetragen: genau der Weg, den #23 als unzuverlässig beschreibt. Der Befund ist damit belegt statt vermutet. ## Abschluss - [x] #34, #33, #31, #19 geschlossen — die Sequenz ist vollständig abgearbeitet - [x] Alle zehn Befunde adressiert; Befund 8 mit begründeter Entscheidung (bleibt exponiert, wird in #32 wieder aufgenommen) - [x] Prognose gegen Messung gehalten, Zahlen oben festgehalten - [x] Menschendoku steht: `INSTALL-MCP.md`, `instructions/mcp-read-server.md` - [→] Ein Konsument führt über die Traefik-Middleware nachweislich `search` gegen den Server aus — **nach #37 übernommen.** Nicht gestrichen und nicht erledigt: der Nachweis braucht ein Deployment und dafür ein Container-Image, und dort liegen auch die neun Entscheidungen, an denen er hängt (Korpus im Image oder als Volume, Sync-Mechanismus, Basis-Image, Healthcheck, Registry-Pfad). Im Repo existiert weiterhin kein Dockerfile und kein Image-Workflow; `.gitea/workflows/` hat `ci.yml`, `nightly.yml`, `release.yml`. **Warum dieses Issue trotzdem schließt:** ein Master-Issue, dessen einzige verbleibende Zeile in einem anderen Issue steht, hält nur noch sich selbst offen. Der Wert des Bodies — Entscheidungen und Messungen — ist unabhängig von seinem Zustand lesbar, und ein geschlossenes Protokoll ist ehrlicher über den Stand als ein offener Sammelposten, der nichts mehr steuert.
torben added the prio/plannedsize/L labels 2026-09-01 21:19:07 +00:00
Author
Owner

Sequenz abgearbeitet (2026-09-02)

# Issue Version Status
0 #34 Publish-Remote-Gate 2.2.3 geschlossen
1 #33 Härtung des Lesepfads 2.2.4 geschlossen
2 #31 Root-Auflösung + Bibliotheksgrenze 2.3.0 geschlossen
3 #19 MCP-Leseserver 2.4.0 geschlossen

Einzelheiten je Issue in dessen Abschlusskommentar; hier nur, was die Sequenz als Ganzes
betrifft.

Die gemessene Grundlage hat gehalten, mit einer Korrektur nach unten und einer Präzisierung:

Prognose im Master gemessen
Korpus-Parse (176 Seiten) 246 → 82 ms 265 → 54 ms
wikitool search end-to-end 593 ms 593 → 347 ms

Die verbleibenden ~262 ms sind Modulimport; im residenten Prozess entfallen sie, womit die
Schätzung „grob 100 ms" steht. Der Alias-Befund: mein Regressionsdokument ist 267 Byte →
672.603 Knoten (9ⁿ) statt 322 Byte → 797.161 (3ⁿ) — dieselbe Eigenschaft, eigene Messung.

Alle zehn Befunde adressiert. 1–7 und 9 behoben. Befund 10 (sauberer rg-Aufruf) ist
erhalten und steht jetzt als dritte tragende Zusage im Modul-Docstring. Befund 8 (lint liest
raw/-Dateinamen) wurde wie vorgesehen in #19 entschieden: bleibt exponiert, weil er ohne
mehrere Einreicher nichts zu schützen hat; die Entscheidung gehört zu #32.

Was der Umbau zusätzlich aufgedeckt hat — beides in #31 dokumentiert und behoben: die
Testsuite hing an zwei Abhängigkeiten, die nur deshalb hielten, weil TYPES_DIR und
TypeResolver.repo_root beim Import gebunden waren. Und resolve() reichte den Root nicht ans
Suchbackend durch: die Anfrage aus dem einen Baum beantwortet, die Seiten aus dem anderen
gelesen.


Abschluss dieses Issues

Das genannte Kriterium — „ein Konsument führt über die Traefik-Middleware nachweislich search
gegen den Server aus" — ist noch nicht erfüllt. Der Server läuft auf beiden Transports gegen
den echten Korpus, die Middleware existiert
(https://gitea.nehmer.net/torben/gitea-mcp-forward-auth), aber das Zusammenspiel braucht ein
Deployment. Dafür fehlt ein Container-Image: #37, mit den Entscheidungen, die dort noch
anstehen.

Vorschlag: dieses Issue offen lassen, bis #37 durch ist und der Nachweis vorliegt. Es hat
nur noch diesen einen Punkt.

Nicht mehr auf dem kritischen Pfad, unverändert offen: #32 (Ingest-Queue), #35 (semantisches
Backend), #6 (Backlink-Ranking).

Zwei lose Enden aus dem Master-Text sind es geblieben:

  1. kb/entities/tools/qmd.md sagt weiterhin „wahrscheinlich Go oder Rust" bei
    confidence: 0.85; verifiziert falsch (TypeScript/Bun). Korpusarbeit über wiki-manage, kein
    Stack-Issue — bislang nicht gemacht.
  2. Es gibt weiterhin keinen dauerhaften Ort für Architekturentscheidungen. Diese Sitzung hat
    das Problem eher vergrößert: die Transport- und Ablage-Entscheidung zu #19 liegt jetzt
    ebenfalls in einem Issue-Kommentar, und CHANGES.md sagt, was ausgeliefert wurde, nicht,
    wogegen entschieden wurde. Braucht eine Entscheidung des Betreibers, ob eine ADR-Ebene
    dazukommt.

Nicht mitgelöst: #23 (nichts erzwingt, dass eine neue Env-Var in _WIKITOOL_ENV landet).
CHEMENU_ROOT ist von Hand eingetragen — genau der Weg, den #23 als unzuverlässig beschreibt.

## Sequenz abgearbeitet (2026-09-02) | # | Issue | Version | Status | |---|---|---|---| | 0 | #34 Publish-Remote-Gate | 2.2.3 | **geschlossen** | | 1 | #33 Härtung des Lesepfads | 2.2.4 | **geschlossen** | | 2 | #31 Root-Auflösung + Bibliotheksgrenze | 2.3.0 | **geschlossen** | | 3 | #19 MCP-Leseserver | 2.4.0 | **geschlossen** | Einzelheiten je Issue in dessen Abschlusskommentar; hier nur, was die Sequenz als Ganzes betrifft. **Die gemessene Grundlage hat gehalten**, mit einer Korrektur nach unten und einer Präzisierung: | | Prognose im Master | gemessen | |---|---|---| | Korpus-Parse (176 Seiten) | 246 → 82 ms | **265 → 54 ms** | | `wikitool search` end-to-end | 593 ms | **593 → 347 ms** | Die verbleibenden ~262 ms sind Modulimport; im residenten Prozess entfallen sie, womit die Schätzung „grob 100 ms" steht. Der Alias-Befund: mein Regressionsdokument ist 267 Byte → 672.603 Knoten (9ⁿ) statt 322 Byte → 797.161 (3ⁿ) — dieselbe Eigenschaft, eigene Messung. **Alle zehn Befunde adressiert.** 1–7 und 9 behoben. Befund 10 (sauberer `rg`-Aufruf) ist erhalten und steht jetzt als dritte tragende Zusage im Modul-Docstring. Befund 8 (`lint` liest `raw/`-Dateinamen) wurde wie vorgesehen in #19 entschieden: bleibt exponiert, weil er ohne mehrere Einreicher nichts zu schützen hat; die Entscheidung gehört zu #32. **Was der Umbau zusätzlich aufgedeckt hat** — beides in #31 dokumentiert und behoben: die Testsuite hing an zwei Abhängigkeiten, die nur deshalb hielten, weil `TYPES_DIR` und `TypeResolver.repo_root` beim Import gebunden waren. Und `resolve()` reichte den Root nicht ans Suchbackend durch: die Anfrage aus dem einen Baum beantwortet, die Seiten aus dem anderen gelesen. --- ## Abschluss dieses Issues Das genannte Kriterium — „ein Konsument führt über die Traefik-Middleware nachweislich `search` gegen den Server aus" — ist **noch nicht erfüllt**. Der Server läuft auf beiden Transports gegen den echten Korpus, die Middleware existiert (<https://gitea.nehmer.net/torben/gitea-mcp-forward-auth>), aber das Zusammenspiel braucht ein Deployment. Dafür fehlt ein Container-Image: **#37**, mit den Entscheidungen, die dort noch anstehen. Vorschlag: dieses Issue **offen lassen**, bis #37 durch ist und der Nachweis vorliegt. Es hat nur noch diesen einen Punkt. **Nicht mehr auf dem kritischen Pfad, unverändert offen:** #32 (Ingest-Queue), #35 (semantisches Backend), #6 (Backlink-Ranking). **Zwei lose Enden aus dem Master-Text sind es geblieben:** 1. `kb/entities/tools/qmd.md` sagt weiterhin „wahrscheinlich Go oder Rust" bei `confidence: 0.85`; verifiziert falsch (TypeScript/Bun). Korpusarbeit über `wiki-manage`, kein Stack-Issue — bislang nicht gemacht. 2. **Es gibt weiterhin keinen dauerhaften Ort für Architekturentscheidungen.** Diese Sitzung hat das Problem eher vergrößert: die Transport- und Ablage-Entscheidung zu #19 liegt jetzt ebenfalls in einem Issue-Kommentar, und `CHANGES.md` sagt, *was* ausgeliefert wurde, nicht, *wogegen* entschieden wurde. Braucht eine Entscheidung des Betreibers, ob eine ADR-Ebene dazukommt. **Nicht mitgelöst:** #23 (nichts erzwingt, dass eine neue Env-Var in `_WIKITOOL_ENV` landet). `CHEMENU_ROOT` ist von Hand eingetragen — genau der Weg, den #23 als unzuverlässig beschreibt.
Author
Owner

Nachtrag zum ersten losen Ende: kb/entities/tools/qmd.md ist korrigiert. Direkt gegen
tobi/qmd auf GitHub geprüft (Repo-Metadaten, package.json, README) - TypeScript, Laufzeit
Node.js/Bun, sqlite-vec + node-llama-cpp statt der geratenen „Go oder Rust"-Angabe bei einer
dafür zu hohen confidence: 0.85. Neue Quelle Source - qmd - GitHub Repository,
confidence_base auf 0.80 neu begründet. Verbleibt: die ADR-Frage.

Nachtrag zum ersten losen Ende: `kb/entities/tools/qmd.md` ist korrigiert. Direkt gegen `tobi/qmd` auf GitHub geprüft (Repo-Metadaten, `package.json`, README) - TypeScript, Laufzeit Node.js/Bun, `sqlite-vec` + `node-llama-cpp` statt der geratenen „Go oder Rust"-Angabe bei einer dafür zu hohen `confidence: 0.85`. Neue Quelle `Source - qmd - GitHub Repository`, `confidence_base` auf 0.80 neu begründet. Verbleibt: die ADR-Frage.
Author
Owner

Zweites loses Ende (die fehlende ADR-Ebene) ist jetzt #38 - mit Befund statt nur Beobachtung:
die adr-NNN--Konvention aus kb/concepts/COLLECTION.md existiert auf Papier und wird nirgends
benutzt, und confidence decay läuft blind über die sieben existierenden Decision-Seiten, was
in dieser Sitzung konkret gegen die direkte Nutzung des Stack-Tooling sprach. Enthält eine
Interims-Lösung (Decay-Ausnahme) und eine Roadmap-Frage (wo Entscheidungsseiten leben) für den
Betreiber.

Zweites loses Ende (die fehlende ADR-Ebene) ist jetzt #38 - mit Befund statt nur Beobachtung: die `adr-NNN-`-Konvention aus `kb/concepts/COLLECTION.md` existiert auf Papier und wird nirgends benutzt, und `confidence decay` läuft blind über die sieben existierenden Decision-Seiten, was in dieser Sitzung konkret gegen die direkte Nutzung des Stack-Tooling sprach. Enthält eine Interims-Lösung (Decay-Ausnahme) und eine Roadmap-Frage (wo Entscheidungsseiten leben) für den Betreiber.
torben added the area/kbkind/build labels 2026-09-02 21:24:43 +00:00
Author
Owner

Changelog: Body auf den Ist-Stand nachgezogen — er stand seit dem 2026-09-02 auf dem
Planungsstand vom 2026-09-01. Sequenztabelle jetzt „geschlossen + Version" statt viermal
„offen"; gemessene Grundlage auf die Nachmessung (265 → 54 ms, 593 → 347 ms) und die
Alias-Korrektur (267 B → 672.603 Knoten, 9ⁿ) umgestellt; die zehn Befunde tragen ihren
Erledigungsstand, Befund 8 als getroffene Entscheidung statt als offene Frage. Beide losen Enden
als erledigt markiert (qmd korrigiert; ADR-Frage → #38, geschlossen mit 4.3.0), #23 als weiterhin
offen ausgewiesen. Abschlussabschnitt auf die eine verbliebene Bedingung reduziert: Nachweis über
ein Deployment, das an #37 hängt (im Repo weiterhin kein Dockerfile, kein Image-Workflow).
Inhaltlich nichts Neues entschieden — die Information stand bereits im Abschlusskommentar vom
2026-09-02 und in #38/#37.

**Changelog:** Body auf den Ist-Stand nachgezogen — er stand seit dem 2026-09-02 auf dem Planungsstand vom 2026-09-01. Sequenztabelle jetzt „geschlossen + Version" statt viermal „offen"; gemessene Grundlage auf die Nachmessung (265 → 54 ms, 593 → 347 ms) und die Alias-Korrektur (267 B → 672.603 Knoten, 9ⁿ) umgestellt; die zehn Befunde tragen ihren Erledigungsstand, Befund 8 als getroffene Entscheidung statt als offene Frage. Beide losen Enden als erledigt markiert (qmd korrigiert; ADR-Frage → #38, geschlossen mit 4.3.0), #23 als weiterhin offen ausgewiesen. Abschlussabschnitt auf die eine verbliebene Bedingung reduziert: Nachweis über ein Deployment, das an #37 hängt (im Repo weiterhin kein Dockerfile, kein Image-Workflow). Inhaltlich nichts Neues entschieden — die Information stand bereits im Abschlusskommentar vom 2026-09-02 und in #38/#37.
Author
Owner

Changelog: Body auf den Endstand umgeschrieben und geschlossen (Betreiberentscheidung, Triage-Sitzung 2026-09-04).

Geändert gegenüber dem vorherigen Stand:

  • Der Abschlussblock ist von einer offenen Kriterienliste zu einem gehakten Protokoll geworden. Vier Punkte abgehakt; das fünfte — der search-Nachweis über die Traefik-Middleware — ist als [→] nach #37 übernommen und dort als eigenes Akzeptanzkriterium eingetragen, mit der Begründung, warum es dorthin und nicht hierher gehört.
  • Der Kopf sagt jetzt „geschlossen am 2026-09-04" statt „Stand: die Sequenz ist abgearbeitet", und benennt #37 als das einzige verbleibende Issue auf diesem Weg.
  • Loses Ende zu #23 korrigiert: CHEMENU_ROOT steht inzwischen in _WIKITOOL_ENV — von Hand eingetragen, also ist der Befund von #23 jetzt belegt statt vermutet. Vorher las sich die Zeile, als fehle der Eintrag noch.
  • #32-Zeile nachgezogen (Vorbedingung #19 erfüllt, teilt Mechanik mit #16), #6-Zeile um die neue status/blocked-Kopplung an #35 ergänzt.
  • Neuer Schlussabsatz, der begründet, warum ein Master-Issue schließt, dessen letzte Zeile in einem anderen Issue steht.

Nicht geändert: Entscheidungstabelle, Messungen und die zehn Befunde. Das ist der Teil, dessentwegen der Body erhalten bleibt, und er ist ausdrücklich nicht neu aufzumachen.

**Changelog:** Body auf den Endstand umgeschrieben und geschlossen (Betreiberentscheidung, Triage-Sitzung 2026-09-04). Geändert gegenüber dem vorherigen Stand: - Der Abschlussblock ist von einer offenen Kriterienliste zu einem gehakten Protokoll geworden. Vier Punkte abgehakt; das fünfte — der `search`-Nachweis über die Traefik-Middleware — ist als `[→]` nach **#37** übernommen und dort als eigenes Akzeptanzkriterium eingetragen, mit der Begründung, warum es dorthin und nicht hierher gehört. - Der Kopf sagt jetzt „geschlossen am 2026-09-04" statt „Stand: die Sequenz ist abgearbeitet", und benennt #37 als das einzige verbleibende Issue auf diesem Weg. - Loses Ende zu #23 korrigiert: `CHEMENU_ROOT` steht inzwischen in `_WIKITOOL_ENV` — von Hand eingetragen, also ist der Befund von #23 jetzt belegt statt vermutet. Vorher las sich die Zeile, als fehle der Eintrag noch. - #32-Zeile nachgezogen (Vorbedingung #19 erfüllt, teilt Mechanik mit #16), #6-Zeile um die neue `status/blocked`-Kopplung an #35 ergänzt. - Neuer Schlussabsatz, der begründet, warum ein Master-Issue schließt, dessen letzte Zeile in einem anderen Issue steht. **Nicht geändert:** Entscheidungstabelle, Messungen und die zehn Befunde. Das ist der Teil, dessentwegen der Body erhalten bleibt, und er ist ausdrücklich nicht neu aufzumachen.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: torben/chemenu#36