Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 31662dc3ff | |||
| 7fbb9a99df | |||
| 778764de4d | |||
| f7597b209c |
+51
@@ -20,6 +20,57 @@ their date-only headings.
|
||||
|
||||
---
|
||||
|
||||
## 2.5.0 - 2026-09-02 - Versionsstelle: Kompatibilitaet statt Inhaltsmigration, Breaking-Change-Vermerk erzwungen
|
||||
|
||||
**Author:** Torben Nehmer
|
||||
|
||||
Die Doku des Stacks führte für die Wahl der Versionsstelle zwei Fragen zusammen, die nicht
|
||||
dieselbe sind: *muss der Korpus migriert werden?* und *ist die neue Version ein
|
||||
Drop-in-Ersatz?* An allen drei Stellen, die einer Session vor dem Bump begegnen - die Tabelle
|
||||
in `stack-dev`, der Modul-Docstring in `version.py`, `INSTALL.md` § Version und Updates -
|
||||
stand nur die erste. Nur `version bump --help` formulierte es richtig, also ausgerechnet die
|
||||
Stelle, die man erst liest, wenn die Entscheidung gefallen ist. Bei `2.0.0` hat genau diese
|
||||
Lücke zu `1.9.0` geführt (Gitea #26; der Eintrag zu `2.0.0` trägt den Fall im Volltext).
|
||||
|
||||
**Die Regel, jetzt an einer Stelle.** Neu ist
|
||||
`instructions/dev/version-parts.md`: der Drop-in-Test in zwei Hälften - vorwärts (kopieren,
|
||||
fertig, keine Handarbeit durch Nutzer oder Migrationsskript) und rückwärts (die alte Version
|
||||
lässt sich noch zurückinstallieren) -, der Katalog der Brüche, die die Grenze bei völlig
|
||||
unangetastetem `kb/` überschreiten (Update-Pfad, Artefaktname, Import-Name, Flags, Envvars,
|
||||
Shape maschinengelesener Dateien), und der Fall `2.0.0` als Fallbeispiel. `instructions/dev/`,
|
||||
also nicht in einer ausgelieferten Instanz - die Datei entscheidet, wer den Stack entwickelt.
|
||||
Die ausgelieferten Artefakte tragen deshalb die Kurzform der Regel, aber keinen Verweis auf
|
||||
sie: `instructions verify` meldet einen solchen Verweis, weil er nach `dist export` ins Leere
|
||||
zeigen würde.
|
||||
|
||||
**Breaking Changes sind teuer, also genehmigungspflichtig.** `stack-dev` hat einen
|
||||
Entscheidungspunkt bekommen: stellt sich eine Änderung als nicht drop-in heraus, wird nicht
|
||||
aus eigener Initiative über die Grenze gebumpt. Vorgelegt werden der konkrete Bruch, was jede
|
||||
bestehende Instanz von Hand tun muss, und die Alternativen - Bruch per Shim vermeiden,
|
||||
aufschieben und mit dem nächsten bündeln, oder in einen kompatiblen und einen brechenden Teil
|
||||
mit Deprecation-Fenster spalten -, dazu eine Empfehlung. Dann Freigabe abwarten.
|
||||
|
||||
**`--breaking` ist neu und bei jedem Grenzübertritt Pflicht.** Es schreibt eine
|
||||
`**Breaking Change:**`-Zeile in den Eintrag, vor die Migrationszeile: das ist, was der Operator
|
||||
einer bestehenden Instanz beim Lesen der Release-Notes zuerst braucht. `docs verify` prüft den
|
||||
neuesten grenzüberschreitenden Eintrag darauf, analog zu `**Migration:** none required` und aus
|
||||
demselben Grund - eine Prosa-Regel driftet, ein Marker nicht. Auf einem kompatiblen Bump wird
|
||||
`--breaking` verweigert, damit es keine Gewohnheit wird. Beide Prüfungen bleiben getrennt:
|
||||
`check_migration_for_boundary` fragt, ob der Inhalt sich bewegt, `check_breaking_change_for_boundary`,
|
||||
ob dem Operator gesagt wurde, dass der Tausch keiner zum Drüberkopieren ist. Ein Rebranding
|
||||
besteht die erste und fällt durch die zweite.
|
||||
|
||||
**Was ausdrücklich nicht passiert:** `docs verify` prüft weiterhin nicht, *ob die Stelle
|
||||
richtig gewählt* wurde. Kein Validator unterscheidet ein umbenanntes Flag von einem neuen; das
|
||||
bleibt Urteil, und dieser Eintrag existiert, weil das Urteil eine Anleitung braucht, keinen
|
||||
Automaten.
|
||||
|
||||
Berührt: `instructions/dev/version-parts.md` (neu), `instructions/dev/stack-dev/SKILL.md`,
|
||||
`tools/chemenu/version.py`, `tools/chemenu/commands/version_cmd.py`,
|
||||
`tools/chemenu/commands/docs_verify.py`, `tools/CONTRACT.md`, `INSTALL.md`. Sechs neue Tests.
|
||||
|
||||
---
|
||||
|
||||
## 2.4.1 - 2026-09-02 - INSTALL-MCP.md: Menschendoku fuer den Leseserver, und sie wird mit ausgeliefert
|
||||
|
||||
**Author:** Torben Nehmer
|
||||
|
||||
+15
-2
@@ -146,8 +146,21 @@ nicht erreichbarer Feed wird als Fehler gemeldet - **nie** als „aktuell".
|
||||
|
||||
**Was die Versionsnummer aussagt:** kompatibel ist, was in der *linkesten von Null
|
||||
verschiedenen Stelle* übereinstimmt. `0.1.3 → 0.1.4` ist ein sicheres Update, `0.1.3 → 0.2.0`
|
||||
verlangt eine Migration, und ab `1.0.0` liest sich dieselbe Regel als das gewohnte „MAJOR heißt
|
||||
Migration". `version check` sagt das direkt (`state: update` vs. `state: migration`).
|
||||
nicht, und ab `1.0.0` liest sich dieselbe Regel als das gewohnte „MAJOR bricht". `version check`
|
||||
sagt das direkt (`state: update` vs. `state: migration`).
|
||||
|
||||
Was diese Stelle beantwortet, ist **ob die neue Version ein Drop-in-Ersatz ist** - ob sich die
|
||||
Maschinerie einfach darüberkopieren lässt und ob die alte danach noch zurückkann. Ob *Inhalt*
|
||||
migriert werden muss, ist eine **zweite, unabhängige Frage**. Ein MAJOR-Sprung kann eine leere
|
||||
Migrationskette haben und trotzdem Handarbeit verlangen: umbenannter Release-Feed, umbenanntes
|
||||
Artefakt, umbenannter Import- oder Kommandoname, geänderte Envvar - `kb/` bleibt dabei
|
||||
unangetastet, das Update ist trotzdem keins zum Drüberkopieren. Der Abschnitt „Sonderfall:
|
||||
Update von 1.x auf 2.0.0" unten ist genau dieser Fall.
|
||||
|
||||
Deshalb stehen in den Release-Notes eines MAJOR zwei getrennte Zeilen, und beide sind vor dem
|
||||
Update zu lesen: **Breaking Change:** sagt, was aufhört zu funktionieren und was diese Instanz
|
||||
dagegen tun muss; **Migration:** sagt, ob und wie der Korpus umgeschrieben wird (`none required`,
|
||||
wenn nicht). `tools/wikitool version notes` druckt den Eintrag.
|
||||
|
||||
### Eine Instanz aktualisieren
|
||||
|
||||
|
||||
@@ -48,6 +48,9 @@ stack development happens in the origin repo instead (see AGENTS.md's routing li
|
||||
[testing-conventions.md](../testing-conventions.md) - the suite runs against a deliberately
|
||||
empty machine; what the autouse fixture already neutralizes, and what a test still has to
|
||||
establish itself. Read it before adding or changing a test.
|
||||
[version-parts.md](../version-parts.md) - which part a change bumps: the drop-in test, the
|
||||
catalogue of breaks that cross the compatibility boundary with `kb/` untouched, and what to
|
||||
put in front of the user before a breaking bump. Read it before step 3.
|
||||
More instructions are added here incrementally as stack-development needs come up - this
|
||||
list grows without needing this skill file to change shape.
|
||||
3. **Raise the version, if the change ships.** A change under `tools/`, `types/`,
|
||||
@@ -59,18 +62,27 @@ stack development happens in the origin repo instead (see AGENTS.md's routing li
|
||||
```
|
||||
|
||||
Never edit `VERSION` or the entry's heading by hand - `bump` writes both, and `docs verify`
|
||||
fails a tree where they disagree. Pick the part by what an existing instance would have to do:
|
||||
fails a tree where they disagree. Pick the part by whether the new version is a **drop-in
|
||||
replacement** for the old one - not by whether content has to be migrated:
|
||||
|
||||
| Change | Part |
|
||||
|--------|------|
|
||||
| Fix, no interface change | `--patch` |
|
||||
| New capability, backwards compatible | `--minor` |
|
||||
| **Existing content must be migrated** | `--major` |
|
||||
| New capability, still drop-in in both directions | `--minor` |
|
||||
| **Not a drop-in replacement** - any hand-work by the user or a migration script, or a downgrade that no longer works | `--major` |
|
||||
|
||||
A `--major` bump additionally needs a migration document for the new version - written per
|
||||
[migrate-corpus.md](../../migrate-corpus.md) - or `--no-migration "<reason>"` when no content
|
||||
actually has to change. `bump` refuses otherwise, and so does `docs verify`: an instance
|
||||
learning that it must migrate, with nothing telling it how, is a dead end.
|
||||
Content migration is one way to land in the last row, not the definition of it: a rename of
|
||||
the update path, the artefact, an import name, a flag or an envvar breaks a swap with `kb/`
|
||||
entirely untouched. The full test, the catalogue of such breaks, and what to put in front of
|
||||
the user first are in [version-parts.md](../version-parts.md) - **read it before choosing
|
||||
`--major`.**
|
||||
|
||||
A `--major` bump therefore needs two things recorded. `--breaking "<what stops working>"`
|
||||
is required on every boundary-crossing bump; on top of it, a migration document for the new
|
||||
version - written per [migrate-corpus.md](../../migrate-corpus.md) - or
|
||||
`--no-migration "<reason>"` when no content actually has to change. `bump` refuses without
|
||||
either, and so does `docs verify`: an instance learning that it must migrate, with nothing
|
||||
telling it how, is a dead end.
|
||||
|
||||
Then write the entry's body - `bump` deliberately leaves it empty, the same way `new` leaves
|
||||
the prose.
|
||||
@@ -90,6 +102,12 @@ stack development happens in the origin repo instead (see AGENTS.md's routing li
|
||||
- **Touches both stack code and wiki content in one session?** Apply this skill's rules to the
|
||||
code changes and the normal content skills' rules to the content changes - they are not
|
||||
mutually exclusive within a session, only per change.
|
||||
- **The change turns out not to be a drop-in replacement?** Do not bump across the boundary on
|
||||
your own initiative. Every existing instance pays for a breaking change once, by hand, so the
|
||||
user decides whether it is worth that: show them what breaks, what an instance has to do about
|
||||
it, and the alternatives (avoid the break with a shim, defer and batch it with the next one,
|
||||
or split it behind a deprecation window), then recommend one and wait for a go-ahead.
|
||||
[version-parts.md](../version-parts.md) step 4 has the full shape.
|
||||
|
||||
## Scope
|
||||
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
---
|
||||
type: types/instruction.md
|
||||
name: version-parts
|
||||
description: Which part of the stack version a change bumps - the compatibility question (is the new version a drop-in replacement?) separated from the migration question (must existing content change?), plus what to do before a breaking bump.
|
||||
---
|
||||
# Pick the version part for a stack change
|
||||
|
||||
Two questions decide a version bump, and they are **not the same question**:
|
||||
|
||||
1. **Is the new version a drop-in replacement for the old one?** This is what the version
|
||||
number itself says. Compatibility is read off the **leftmost non-zero component** - on this
|
||||
stack (`2.x`) that is MAJOR, on a `0.x` stack it is MINOR. A bump that changes it is called
|
||||
*boundary-crossing* below, because that is the term `version bump` and `docs verify` use in
|
||||
their own messages.
|
||||
2. **Must existing content be migrated?** This is a *consequence* a boundary crossing may or
|
||||
may not have. `kb/` staying untouched does not make a change compatible, and
|
||||
`version bump --no-migration` exists precisely because boundary-crossing bumps with an
|
||||
untouched corpus are a real case.
|
||||
|
||||
Getting these backwards is how a genuinely breaking change ships as a MINOR. It happened once
|
||||
already (see the case study at the end), which is why this file exists.
|
||||
|
||||
## When to run
|
||||
|
||||
Before every `tools/wikitool version bump` - the `stack-dev` skill's step 3 sends you here.
|
||||
Read it in full the first time a change looks like it might be boundary-crossing; afterwards
|
||||
the three-line test below is usually enough.
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Apply the drop-in test.** The bump is boundary-crossing if **either** half fails:
|
||||
|
||||
- **Forward:** an existing instance can install the new machinery by copying `tools/`,
|
||||
`types/`, `instructions/`, `AGENTS.md`, `VERSION` and `.wikitool-release.json` over itself,
|
||||
and everything that worked before still works - with **no** hand-work by the user and **no**
|
||||
migration script. Any step beyond the copy, however small, fails this half.
|
||||
- **Backward:** having installed the new version, the user can put the old one back and be
|
||||
where they started. A state file the old version cannot read, a rewritten corpus, a
|
||||
renamed stamp - anything that makes the downgrade fail or leave a broken instance - fails
|
||||
this half.
|
||||
|
||||
Content migration is one way to fail the forward half, not the definition of it.
|
||||
|
||||
2. **Check the catalogue** when the answer still feels like a judgment call. Each of these
|
||||
crosses the boundary with `kb/` entirely untouched:
|
||||
|
||||
| What changed | Why the swap is not drop-in |
|
||||
|---|---|
|
||||
| The update path - `update_url`, the release feed, the repo it points at | The instance cannot repair its own `.wikitool-release.json`: it is machine-written, and invariant 1 forbids the hand-edit. The channel that would have told it to update is the channel that broke |
|
||||
| The release artefact's name | Every download script and every pin against it breaks |
|
||||
| The Python package's import name | `from <old> import ...` outside the shipped tree breaks |
|
||||
| A command, subcommand, or flag that was removed or renamed | Scripts, CI workflows and instruction files calling the old spelling break |
|
||||
| An environment variable's name | An instance configured through it silently loses the configuration |
|
||||
| The shape of a machine-read file - `.wikitool-kb.json`, `.wikitool-release.json`, a generated index | The old version cannot read what the new one wrote, so the downgrade half fails even if the upgrade half passed |
|
||||
| A type-spec's required fields | Existing pages stop validating - this one crosses *and* needs a content migration |
|
||||
|
||||
The catalogue is illustrative, not exhaustive. When something is not on it, go back to step 1.
|
||||
|
||||
3. **Otherwise pick the compatible part:**
|
||||
|
||||
| Change | Part |
|
||||
|---|---|
|
||||
| Fix, no interface change | `--patch` |
|
||||
| New capability, drop-in in both directions | `--minor` |
|
||||
|
||||
4. **Stop and talk to the user before a boundary-crossing bump.** It is expensive in a way the
|
||||
other two parts are not: every existing instance pays for it, once, by hand. Put in front of
|
||||
them, in this order:
|
||||
|
||||
- **What breaks**, concretely - which file, which name, which call site.
|
||||
- **What each existing instance must do**, as the steps they would actually run.
|
||||
- **The alternatives**, so the break is a choice and not a side effect:
|
||||
- *Avoid it* - keep the old name as an alias, read both file shapes, accept both flag
|
||||
spellings. A compatibility shim carried for one release is usually cheaper than a
|
||||
migration everyone runs.
|
||||
- *Defer and batch it* - hold the break until the next boundary crossing, so instances pay
|
||||
once instead of twice.
|
||||
- *Split it* - ship the compatible half now, the breaking half later behind a deprecation
|
||||
window that the changelog announces in advance.
|
||||
- **Your recommendation**, with the trade-off named.
|
||||
|
||||
Then wait for an explicit go-ahead. Do not bump across the boundary on your own initiative.
|
||||
|
||||
5. **Record the break in the bump itself.** A boundary-crossing bump requires
|
||||
`--breaking "<what breaks>"`, which writes a `**Breaking Change:**` line into the entry:
|
||||
|
||||
```bash
|
||||
tools/wikitool version bump --major \
|
||||
--title "<what changed>" \
|
||||
--breaking "<what stops working, and what an instance must do about it>" \
|
||||
--no-migration "<why no page has to change>" # only if that is true
|
||||
```
|
||||
|
||||
`--breaking` is refused on a bump that crosses nothing, and required on one that does;
|
||||
`docs verify` checks the newest boundary-crossing entry still carries the line. Write it for
|
||||
the operator of an instance that has not read this repository: what stops working, and what
|
||||
they do about it.
|
||||
|
||||
6. **Then answer the migration question separately.** Boundary-crossing and
|
||||
content-migrating are independent:
|
||||
|
||||
- Content must change → write the migration document under `instructions/migrations/` per
|
||||
[migrate-corpus.md](../migrate-corpus.md). `bump` finds it by its `migrates_to:` field.
|
||||
- Content need not change → `--no-migration "<reason>"`, which records that in the entry.
|
||||
|
||||
Both are also needed by `docs verify`, for the same reason: an instance that learns it must
|
||||
migrate, with nothing telling it how, is a dead end.
|
||||
|
||||
7. **Write the entry's body.** `bump` leaves it empty on purpose. A boundary-crossing entry
|
||||
earns a paragraph that says *why this is breaking* - it is the one thing a future reader
|
||||
cannot reconstruct from the diff, and it is what the next session in this position will read
|
||||
instead of guessing.
|
||||
|
||||
## Decision points
|
||||
|
||||
- **The change ships no code - only `README.md`, `INSTALL.md`, `EVALS.md`, or `.gitea/`?** No
|
||||
bump at all; CI's version gate is scoped to what changes behaviour.
|
||||
- **A break you can see coming but are not making yet?** File it as an issue and let it
|
||||
accumulate. Boundary crossings are cheaper in batches, and step 4's "defer" alternative is
|
||||
only real if someone wrote the break down.
|
||||
- **Unsure between MINOR and boundary-crossing?** It is boundary-crossing. The cost of an
|
||||
unnecessary MAJOR is one extra release note; the cost of a MINOR that actually breaks is an
|
||||
instance whose update path fails while its version number promised it would not.
|
||||
- **The break only affects this repository, not a distributed instance** - something under
|
||||
`instructions/dev/`, say? Then it is not a stack break at all: `dist export` never shipped it.
|
||||
Judge by what an *exported* instance sees.
|
||||
|
||||
## Scope
|
||||
|
||||
Applies to the stack version in `VERSION` - `tools/`, `types/`, `instructions/`, `AGENTS.md`
|
||||
and the contracts. It says nothing about the content shape in `.wikitool-kb.json`, which is
|
||||
advanced by `wikitool migrate done` and described by [migrate-corpus.md](../migrate-corpus.md),
|
||||
and nothing about wiki content operations, which are logged in `kb/log.md` and carry no version
|
||||
at all.
|
||||
|
||||
Choosing the part remains a judgment call, deliberately: `docs verify` checks that a
|
||||
boundary-crossing entry *documents* its break and its migration, never that the part was chosen
|
||||
correctly. No validator can tell a renamed flag from a new one.
|
||||
|
||||
## Case study: 2.0.0
|
||||
|
||||
The Chemenu rebranding renamed the repo, the release artefact and the Python package. No page
|
||||
in `kb/` changed, so the first attempt was `1.9.0` - the migration question, answered correctly,
|
||||
substituted for the compatibility question, which was never asked. Three things broke: every
|
||||
existing instance's `update_url` pointed at a repo path that no longer existed and could not be
|
||||
hand-repaired; the artefact name changed; the import name changed. The correct bump was
|
||||
`--major --no-migration`, and the `CHANGES.md` entry for `2.0.0` carries the reasoning in full
|
||||
under "Warum das trotzdem MAJOR ist". The error was caught by the user, not by the
|
||||
documentation - which is what step 4 is for.
|
||||
@@ -6,7 +6,7 @@ created: 2026-09-01
|
||||
modified: 2026-09-01
|
||||
related: [Chemenu]
|
||||
sources: ['Source - Public Release, Corpus Purge and History Squash Session 2026-09-01', Source - Private-Instance Merge Correction and Issue 30 Session 2026-09-01]
|
||||
confidence: 0.90
|
||||
confidence: 0.70
|
||||
confidence_base: 0.70
|
||||
provenance: sourced
|
||||
summary: 'Private Korpusinhalte per Loeschung entfernen statt zu anonymisieren: ein Seitentitel ist der einzige Identifier eines Wikis, Umbenennen ist die volle page-lifecycle-Prozedur je Seite, Loeschen ist ein unterstuetztes Kommando.'
|
||||
|
||||
@@ -6,7 +6,7 @@ created: 2026-09-01
|
||||
modified: 2026-09-01
|
||||
related: [Chemenu]
|
||||
sources: ['Source - Public Release, Corpus Purge and History Squash Session 2026-09-01']
|
||||
confidence: 0.50
|
||||
confidence: 0.70
|
||||
confidence_base: 0.70
|
||||
provenance: sourced
|
||||
summary: Ein Repo mit Code- und Inhaltsanteil erhaelt zwei Lizenzen; die Grenze zwischen ihnen ist kein zweiter, gepflegter Pfadkatalog, sondern der ohnehin vorhandene Dateiplan des Distributionswerkzeugs.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# kb/concepts/ - Index
|
||||
|
||||
79 page(s). Regenerated by `wikitool index rebuild`.
|
||||
80 page(s). Regenerated by `wikitool index rebuild`.
|
||||
|
||||
## All
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
| [[Implementation Spectrum]] | architecture | Modularer Einführungspfad für die Funktionen von LLM Wiki v2, vom minimal tragfähigen Wiki bis zur vollen Umsetzung mit Automatisierung und Governance. | 2026-08-29 |
|
||||
| [[Index Scaling]] | workflow | Skalierungsregeln für Indexseiten: Tabellenabschnitte ab 50 Einträgen teilen, ab 200 Seiten _meta/topic-map.md anlegen | 2026-08-29 |
|
||||
| [[Issue Label Scheme]] | decision | Zweiachsiges Pflicht-Labelschema fuer das Gitea-Board: prio/1..3 und size/XS..L, bewusst keine dritte Achse; die Regel liegt in instructions/dev/, weil sie keine ausgelieferte Instanz erreichen darf | 2026-08-31 |
|
||||
| [[Iteration and Cost Limits]] | workflow | Im Code durchgesetzte Obergrenze von 60 wikitool-Aufrufen je Session\, Loop-Breaker bei 3 identischen Wiederholungen\, Slot-Erstattung bei abgelehntem Aufruf und ein seit 1.5.0 gemessenes Kalibrierungsband von 5-15 (einfach) bzw. 20-35 (komplex) Aufrufen | 2026-08-31 |
|
||||
| [[Iteration and Cost Limits]] | workflow | Im Code durchgesetzte Obergrenze von 60 wikitool-Aufrufen je Session, Loop-Breaker bei 3 identischen Wiederholungen, Slot-Erstattung, ein gemessenes Kalibrierungsband, und Retrieval sowie der MCP-Leseserver bleiben ausgenommen | 2026-09-02 |
|
||||
| [[KB Migration]] | workflow | Migration des KB-Inhalts entlang einer geordneten Versionskette; abgegrenzt gegen offene Instanz-Aktionen, die in den doctor-Check gehoeren statt in die Kette | 2026-08-31 |
|
||||
| [[KB Stack Versioning]] | decision | Semantische Versionierung des Wiki-Stacks: VERSION beschreibt die Maschinerie, Kompatibilitaet ist die linkeste Nicht-Null-Komponente, und drei getrennte Dateien trennen Maschinerie, Herkunft und Content-Form | 2026-08-30 |
|
||||
| [[Knowledge Compounding]] | workflow | Effekt, bei dem Wissen im Wiki an Wert gewinnt, weil jede neue Quelle an bestehende, untereinander verwiesene Seiten anknüpft und sie ergänzt. | 2026-08-29 |
|
||||
@@ -50,6 +50,7 @@
|
||||
| [[Lint Workflow]] | workflow | Deterministischer Health-Check rund um wikitool lint; seit 1.7.2 maskiert es Code vor dem Notation-Match und zaehlt Zitat-Bloecke statt Zeilen | 2026-09-01 |
|
||||
| [[LLM Wiki Pattern]] | architecture | Methodik für persönliches Wissensmanagement, bei der ein LLM aus Rohquellen ein dauerhaftes Wiki aufbaut - Wissen wird kompiliert statt per RAG neu hergeleitet. | 2026-08-29 |
|
||||
| [[Mass-Update Gate]] | workflow | Mass-Update Gate: publish endet mit 42 (Freigabe durch den Menschen noetig) ab 10 gezaehlten Dateien; generierte Dateien und work/ werden committet\, aber seit 1.5.0 nicht gezaehlt; freigegeben per --confirm <token> | 2026-09-01 |
|
||||
| [[MCP-Leseserver]] | architecture | Zweiter Konsument von chemenu ueber MCP: search/types/describe_type/lint/status auf chemenu.api.Corpus, strukturell ohne Schreibpfad, jede Antwort trage einen Commit-Stempel. | 2026-09-02 |
|
||||
| [[Memory Lifecycle]] | architecture | Architektur des Wissenslebenszyklus mit Confidence Scoring, Supersession, Forgetting und Consolidation Tiers zur Pflege von Fakten über die Zeit. | 2026-08-29 |
|
||||
| [[Mesh Sync]] | pattern | Abgleichsmechanismus, der Beobachtungen paralleler Agenten in ein gemeinsames Wiki überführt; Last-Write-Wins mit Konflikterkennung und manuellem Eingriff. | 2026-08-29 |
|
||||
| [[Modbus]] | protocol | Industrielles Kommunikationsprotokoll von 1979 zur Anbindung speicherprogrammierbarer Steuerungen und Geräte über serielle oder TCP-Netze. | 2026-08-29 |
|
||||
@@ -60,7 +61,7 @@
|
||||
| [[Personalization Plane]] | architecture | Schicht fuer Instanz-Identitaet: USER.md/SOUL.md werden als Template ausgeliefert, im Setup-Interview woertlich befuellt und vom doctor-Check auf fehlend wie unbefuellt geprueft | 2026-08-31 |
|
||||
| [[Privacy and Governance]] | workflow | Rahmenwerk zur Absicherung von Wiki-Inhalten über Datenfilterung beim Ingest, Audit-Trail-Protokollierung und umkehrbare Massenoperationen. | 2026-08-29 |
|
||||
| [[Procedural Memory]] | architecture | Langlebigste Speicherschicht für Abläufe, Muster, bewährte Vorgehensweisen und Rezepte, gewonnen aus wiederholten semantischen Beobachtungen. | 2026-08-29 |
|
||||
| [[Publish-Remote Gate]] | workflow | Drittes, im Code durchgesetztes Gate: publish bricht mit Exit 42 ab, wenn die aufgeloeste Push-URL nicht in einer optionalen, gitignoreten Allowlist steht; anders als die anderen Gates gibt es keinen Freigabe-Token. | 2026-09-01 |
|
||||
| [[Publish-Remote Gate]] | workflow | Drittes, im Code durchgesetztes Gate: publish bricht mit Exit 42 ab, wenn die aufgeloeste Push-URL nicht in einer optionalen, gitignoreten Allowlist steht; doctor benennt seit 2026-09-02 den Gate-Zustand statt nur die Dateiexistenz | 2026-09-02 |
|
||||
| [[Quality and Self-Correction]] | workflow | Automatische Qualitätssicherung für Wikis mit Inhaltsbewertung, Selbstheilung und Widerspruchserkennung. | 2026-08-29 |
|
||||
| [[Quality Scoring]] | pattern | Quantitative Bewertung aller vom LLM geschriebenen Inhalte nach struktureller Qualität, Vollständigkeit der Quellenangaben, Konsistenz mit dem Wiki und Themenabdeckung. | 2026-08-29 |
|
||||
| [[RAG]] | architecture | Architekturmuster, bei dem LLMs die Generierung um Dokumente aus einer Wissensbasis anreichern. | 2026-08-29 |
|
||||
|
||||
@@ -3,13 +3,13 @@ type: types/concept.md
|
||||
concept_type: workflow
|
||||
tags: [gate, safety, iteration-budget, loop-breaker]
|
||||
created: 2026-08-07
|
||||
modified: 2026-08-31
|
||||
related: [Mass-Update Gate, Anti-Cramming Heuristic, Index Scaling, wikitool, Structural Enforcement over Documented Rule]
|
||||
sources: [Source - LLM Improvements Production Agent Gaps 2026, Source - Conversation - Comma Bug Budget Refund and Lint Report Path Session 2026-08-31, Source - Conversation - Gate Counting and Measured Calibration Session 2026-08-31]
|
||||
modified: 2026-09-02
|
||||
related: [Mass-Update Gate, Anti-Cramming Heuristic, Index Scaling, wikitool, Structural Enforcement over Documented Rule, MCP-Leseserver]
|
||||
sources: [Source - LLM Improvements Production Agent Gaps 2026, Source - Conversation - Comma Bug Budget Refund and Lint Report Path Session 2026-08-31, Source - Conversation - Gate Counting and Measured Calibration Session 2026-08-31, Source - MCP Read Server Implementation Session 2026-09-02]
|
||||
confidence: 0.88
|
||||
confidence_base: 0.88
|
||||
provenance: sourced
|
||||
summary: Im Code durchgesetzte Obergrenze von 60 wikitool-Aufrufen je Session\, Loop-Breaker bei 3 identischen Wiederholungen\, Slot-Erstattung bei abgelehntem Aufruf und ein seit 1.5.0 gemessenes Kalibrierungsband von 5-15 (einfach) bzw. 20-35 (komplex) Aufrufen
|
||||
summary: Im Code durchgesetzte Obergrenze von 60 wikitool-Aufrufen je Session, Loop-Breaker bei 3 identischen Wiederholungen, Slot-Erstattung, ein gemessenes Kalibrierungsband, und Retrieval sowie der MCP-Leseserver bleiben ausgenommen
|
||||
---
|
||||
# Iteration and Cost Limits
|
||||
|
||||
@@ -48,6 +48,11 @@ Eine hart in Code durchgesetzte Obergrenze für die Anzahl der Tool-Aufrufe, die
|
||||
|
||||
- Einzelne, begrenzte Einmalvorgänge, bei denen die Aufrufen-Anzahl inhärent festgelegt ist (z. B. ein einzelner `new entity`-Aufruf) - das Gate wird dort immer noch gleichmäßig angewendet, wird aber im Wesentlichen nie ausgelöst.
|
||||
- Als Ersatz für das [[Mass-Update Gate]], das auf den *Schadensradius* eines `publish` (Dateien, die von einem einzelnen Push betroffen sind) begrenzt ist, nicht auf die *Iterationsmenge* über eine Sitzung - die beiden Gates beheben unterschiedliche Ausfallmodi und beide bleiben notwendig.
|
||||
- Im [[MCP-Leseserver]]. Das Gate begrenzt eine Agenten-Session am unbemerkten Iterieren über den
|
||||
Wiki-Zustand - deshalb ist Retrieval bereits generell ausgenommen (`SKIP_COMMANDS`) -, nicht
|
||||
einen Nutzer, der oft sucht. Ein zu häufig suchender Nutzer ist ein Ressourcenproblem, das vor
|
||||
den Serverprozess gehört (Rate Limiting), nicht in dieses Gate - beide zu vermischen würde es
|
||||
zu einem Rate Limiter verwässern.[^s-mcp-read-server-implementation-session-2026-09-02]
|
||||
|
||||
## Verwandte Concepts
|
||||
|
||||
@@ -63,6 +68,7 @@ Eine hart in Code durchgesetzte Obergrenze für die Anzahl der Tool-Aufrufe, die
|
||||
- **schützt:** [[Index Scaling]]
|
||||
- **implementiert durch:** [[wikitool]]
|
||||
- **wendet an:** [[Structural Enforcement over Documented Rule]]
|
||||
- **nimmt aus:** [[MCP-Leseserver]]
|
||||
|
||||
## Siehe auch
|
||||
|
||||
@@ -73,9 +79,11 @@ Eine hart in Code durchgesetzte Obergrenze für die Anzahl der Tool-Aufrufe, die
|
||||
- [[Source - LLM Improvements Production Agent Gaps 2026]]
|
||||
- [[Source - Conversation - Gate Counting and Measured Calibration Session 2026-08-31]]
|
||||
- [[Structural Enforcement over Documented Rule]]
|
||||
- [[MCP-Leseserver]]
|
||||
|
||||
## Fußnoten
|
||||
|
||||
[^s-llm-improvements-production-agent-gaps-2026]: [[Source - LLM Improvements Production Agent Gaps 2026]]
|
||||
[^s-conversation-gate-counting-and-measured-calibration-session-2026-08-31]: [[Source - Conversation - Gate Counting and Measured Calibration Session 2026-08-31]]
|
||||
[^s-conversation-comma-bug-budget-refund-and-lint-report-path-session-2026-08-31]: [[Source - Conversation - Comma Bug Budget Refund and Lint Report Path Session 2026-08-31]]
|
||||
[^s-mcp-read-server-implementation-session-2026-09-02]: [[Source - MCP Read Server Implementation Session 2026-09-02]]
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
---
|
||||
type: types/concept.md
|
||||
concept_type: architecture
|
||||
tags: [mcp, library-boundary, search, server]
|
||||
created: 2026-09-02
|
||||
modified: 2026-09-02
|
||||
related: [wikitool, Publish-Remote Gate, Mass-Update Gate, Iteration and Cost Limits, Chemenu]
|
||||
sources: [Source - MCP Read Server Implementation Session 2026-09-02]
|
||||
confidence: 0.50
|
||||
confidence_base: 0.50
|
||||
provenance: sourced
|
||||
summary: 'Zweiter Konsument von chemenu ueber MCP: search/types/describe_type/lint/status auf chemenu.api.Corpus, strukturell ohne Schreibpfad, jede Antwort trage einen Commit-Stempel.'
|
||||
---
|
||||
# MCP-Leseserver
|
||||
|
||||
**Typ:** Architecture
|
||||
|
||||
## Definition
|
||||
|
||||
Ein zweiter Konsument desselben Kerns, nicht ein zweites Programm: `tools/chemenu/mcp/` exponiert
|
||||
`search`, `types`, `describe_type`, `lint` und `status` über MCP, indem es dieselben Funktionen
|
||||
aufruft, die `wikitool` auch aufruft - vermittelt durch `chemenu.api.Corpus`, den In-Process-
|
||||
Einstiegspunkt. Ein Golden-Test hält die Ausgaben beider Wege gegeneinander, statt darauf zu
|
||||
vertrauen, dass sie übereinstimmen.
|
||||
|
||||
## Kernpunkte
|
||||
|
||||
- **Kein Schreibpfad, strukturell.** Weder der Server noch `chemenu.api` importiert etwas unter
|
||||
`chemenu.commands` - `new`, `touch`, `xref`, `publish`, `migrate` sind aus diesem Prozess
|
||||
heraus nicht erreichbar, statt aus einer Liste gefiltert zu werden. Ein Test importiert das
|
||||
Servermodul in einem frischen Interpreter und prüft
|
||||
`sys.modules`.[^s-mcp-read-server-implementation-session-2026-09-02]
|
||||
- **Zwei Transports.** `stdio` zum Entwickeln und Testen ohne Netz; `streamable-http` für die
|
||||
Auslieferung, der einzige, vor den sich ein HTTP-Reverse-Proxy setzen kann. `sse` ist über das
|
||||
SDK erreichbar und wird bewusst nicht angeboten - der abgelöste Remote-Transport, jetzt darauf
|
||||
zu bauen verschiebt den Wechsel nur.
|
||||
- **Jede Antwort trägt den Commit, aus dem sie berechnet wurde** (`commit`, `as_of`). Ein
|
||||
veralteter Checkout antwortet sonst selbstbewusst falsch. `null` heißt: der bediente Baum hat
|
||||
uncommittete Änderungen, die Antwort entspricht keiner Revision. Der Stempel ist die Revision,
|
||||
aus der die Seiten *tatsächlich* gelesen wurden, nicht die zum Zeitpunkt des Stempelns aktuelle
|
||||
- ein Bug, der genau diesen Unterschied überging, wurde beim Schreiben des Golden-Tests selbst
|
||||
gefunden und behoben.[^s-mcp-read-server-implementation-session-2026-09-02]
|
||||
- **Telemetrie in den bedienten Baum wird beim Start verweigert**, nicht still umgeleitet. Der
|
||||
Sync, der den Checkout aktuell hält (`git fetch && git reset --hard`), darf `reports/telemetry/`
|
||||
wegräumen; ein Trace, der dort landet, wäre ein Verlust und eine stille Möglichkeit, den Baum
|
||||
zu beschmutzen, dessen Sauberkeit der Korpus-Cache prüft.
|
||||
- **Kein Iteration Budget Gate im Server.** Das Gate begrenzt eine Agenten-Session am unbemerkten
|
||||
Iterieren über den Wiki-Zustand, nicht einen Nutzer, der oft sucht - Retrieval ist deshalb
|
||||
bereits generell davon ausgenommen (siehe [[Iteration and Cost Limits]]). Rate Limiting gehört
|
||||
stattdessen vor den Prozess, neben die Authentifizierung.
|
||||
- **Authentifizierung ist Middleware, nicht Servercode.** Eine Traefik-ForwardAuth-Instanz
|
||||
(Bearer-Token gegen SHA-256-Hashes) sitzt vor dem Prozess; nicht sauber authentifizierte
|
||||
Zugriffe erreichen Python gar nicht erst.
|
||||
- **Gemessen:** Korpus-Parse für 176 Seiten 265 ms → 54 ms (`CSafeLoader`),
|
||||
`wikitool search` end-to-end 593 ms → 347 ms; die verbleibenden ~262 ms sind Modulimport und
|
||||
entfallen im residenten Serverprozess, weil er ihn einmal pro Start statt pro Aufruf
|
||||
zahlt.[^s-mcp-read-server-implementation-session-2026-09-02]
|
||||
|
||||
## Beispiele
|
||||
|
||||
- `search`/`types`/`describe_type`/`lint`/`status` als die fünf Tools - siehe
|
||||
`tools/chemenu/mcp/server.py`.
|
||||
- Der Korpus-Cache (`chemenu/corpus_cache.py`) hält einen Parse pro Commit und cacht nie einen
|
||||
schmutzigen Arbeitsbaum - dieselbe Eigenschaft, die den Antwort-Stempel korrekt hält.
|
||||
- `chemenu.api.Corpus`: nimmt einen Root, liefert exakt die `--json`-Formen der CLI, raised statt
|
||||
zu exitieren.
|
||||
|
||||
## Wann zu verwenden
|
||||
|
||||
- Ein Konsument, der keine Shell auf der bedienenden Maschine ist, soll dieselben Fragen stellen
|
||||
können wie ein Agent, der `wikitool` direkt aufruft.
|
||||
- Mehrere gleichzeitige Leser eines Korpus, für die ein Prozess pro CLI-Aufruf (Modulimport,
|
||||
Korpus-Parse) unnötigen Overhead bedeutet.
|
||||
|
||||
## Wann NICHT zu verwenden
|
||||
|
||||
- Als Ort für einen Schreibpfad - die Ingest-Queue (geplant, Issue #32) ist ein anderes Design
|
||||
mit einer Quarantäne davor, nicht eine Erweiterung dieses Servers.
|
||||
- Als Ersatz für den Iteration Budget Gate oder das Traefik-Rate-Limiting - beide bleiben
|
||||
notwendig und leben an anderer Stelle.
|
||||
|
||||
## Verwandte Concepts
|
||||
|
||||
- [[Publish-Remote Gate]]
|
||||
- [[Mass-Update Gate]]
|
||||
- [[Iteration and Cost Limits]]
|
||||
|
||||
## Fußnoten
|
||||
|
||||
[^s-mcp-read-server-implementation-session-2026-09-02]: [[Source - MCP Read Server Implementation Session 2026-09-02]]
|
||||
|
||||
## Beziehungen
|
||||
|
||||
- **implementiert:** [[wikitool]]
|
||||
- **verwandt mit:** [[Publish-Remote Gate]]
|
||||
- **verwandt mit:** [[Mass-Update Gate]]
|
||||
- **ausgenommen von:** [[Iteration and Cost Limits]]
|
||||
- **Teil von:** [[Chemenu]]
|
||||
|
||||
## Siehe auch
|
||||
|
||||
- [[wikitool]]
|
||||
- [[Publish-Remote Gate]]
|
||||
- [[Mass-Update Gate]]
|
||||
- [[Iteration and Cost Limits]]
|
||||
- [[Chemenu]]
|
||||
- [[Source - MCP Read Server Implementation Session 2026-09-02]]
|
||||
|
||||
@@ -4,7 +4,7 @@ concept_type: workflow
|
||||
tags: [gate, safety, mass-update, confirmation]
|
||||
created: 2026-08-03
|
||||
modified: 2026-09-01
|
||||
related: [Content Quality Control, wikitool, Iteration and Cost Limits, Structural Enforcement over Documented Rule, Bulk Operations, Publish-Remote Gate]
|
||||
related: [Content Quality Control, wikitool, Iteration and Cost Limits, Structural Enforcement over Documented Rule, Bulk Operations, Publish-Remote Gate, MCP-Leseserver]
|
||||
sources: [Source - LLM Improvements Sonnet Analysis, Source - LLM Improvements Production Agent Gaps 2026, Source - Conversation - Comma Bug Budget Refund and Lint Report Path Session 2026-08-31, Source - Conversation - Gate Counting and Measured Calibration Session 2026-08-31, Source - LLM Improvements Codex Analysis]
|
||||
confidence: 0.88
|
||||
confidence_base: 0.88
|
||||
@@ -78,6 +78,7 @@ Das Mass-Update Gate ist ein Sicherheitsmechanismus, der die Ausführung pausier
|
||||
- **wendet an:** [[Structural Enforcement over Documented Rule]]
|
||||
- **grenzt ab gegen:** [[Bulk Operations]]
|
||||
- **verwandtes Gate:** [[Publish-Remote Gate]]
|
||||
- **verwandt mit:** [[MCP-Leseserver]]
|
||||
|
||||
## Siehe auch
|
||||
|
||||
@@ -88,6 +89,7 @@ Das Mass-Update Gate ist ein Sicherheitsmechanismus, der die Ausführung pausier
|
||||
- [[Structural Enforcement over Documented Rule]]
|
||||
- [[Bulk Operations]]
|
||||
- [[Publish-Remote Gate]]
|
||||
- [[MCP-Leseserver]]
|
||||
|
||||
## Fußnoten
|
||||
|
||||
|
||||
@@ -3,13 +3,13 @@ type: types/concept.md
|
||||
concept_type: workflow
|
||||
tags: []
|
||||
created: 2026-09-01
|
||||
modified: 2026-09-01
|
||||
related: [Mass-Update Gate, Chemenu]
|
||||
sources: [Source - Publish-Remote Gate and Issue Triage Session 2026-09-01, Source - Private-Instance Merge Correction and Issue 30 Session 2026-09-01]
|
||||
confidence: 0.50
|
||||
modified: 2026-09-02
|
||||
related: [Mass-Update Gate, Chemenu, MCP-Leseserver]
|
||||
sources: [Source - Publish-Remote Gate and Issue Triage Session 2026-09-01, Source - Private-Instance Merge Correction and Issue 30 Session 2026-09-01, Source - MCP Read Server Implementation Session 2026-09-02]
|
||||
confidence: 0.70
|
||||
confidence_base: 0.70
|
||||
provenance: sourced
|
||||
summary: 'Drittes, im Code durchgesetztes Gate: publish bricht mit Exit 42 ab, wenn die aufgeloeste Push-URL nicht in einer optionalen, gitignoreten Allowlist steht; anders als die anderen Gates gibt es keinen Freigabe-Token.'
|
||||
summary: 'Drittes, im Code durchgesetztes Gate: publish bricht mit Exit 42 ab, wenn die aufgeloeste Push-URL nicht in einer optionalen, gitignoreten Allowlist steht; doctor benennt seit 2026-09-02 den Gate-Zustand statt nur die Dateiexistenz'
|
||||
---
|
||||
# Publish-Remote Gate
|
||||
|
||||
@@ -40,6 +40,12 @@ Remote lokal konfiguriert ist.
|
||||
ist wichtig: Ein Checkout ohne Beschränkungsbedarf soll nicht gezwungen sein, eine leere
|
||||
Konfigurationsdatei zu pflegen; eine beschädigte Datei darf aber nicht wie eine abwesende
|
||||
behandelt werden, sonst wird eine defekte Sicherung zu einer stillschweigend abgeschalteten.
|
||||
- **`doctor` benennt seit 2026-09-02 den Gate-*Zustand*, nicht nur, ob die Datei existiert.**
|
||||
Vorher meldete der Check nur die Anwesenheit von `.wikitool-remotes.json`; ob das
|
||||
gleichbedeutend mit "scharf" ist, musste der Leser selbst schließen. Alle drei Ausgaben
|
||||
beginnen jetzt mit `Gate armed:` bzw. `Gate not armed:` - der Ein-Remote-Fall ohne Allowlist
|
||||
bleibt `OK` (er hat nichts zu schützen), sagt aber ausdrücklich, dass jedes Push-Ziel
|
||||
durchkommt.[^s-mcp-read-server-implementation-session-2026-09-02]
|
||||
|
||||
## Wann zu verwenden
|
||||
|
||||
@@ -88,11 +94,13 @@ Maschinerie ziehen) stehen in Gitea-Issue #30.
|
||||
## Verwandte Concepts
|
||||
|
||||
- [[Mass-Update Gate]]
|
||||
- [[MCP-Leseserver]]
|
||||
|
||||
## Beziehungen
|
||||
|
||||
- **gilt fuer:** [[Chemenu]]
|
||||
- **verwandtes Gate:** [[Mass-Update Gate]]
|
||||
- **verwandt mit:** [[MCP-Leseserver]]
|
||||
|
||||
## Siehe auch
|
||||
|
||||
@@ -100,7 +108,9 @@ Maschinerie ziehen) stehen in Gitea-Issue #30.
|
||||
- [[Chemenu]]
|
||||
- [[Mass-Update Gate]]
|
||||
- [[Source - Private-Instance Merge Correction and Issue 30 Session 2026-09-01]]
|
||||
- [[MCP-Leseserver]]
|
||||
|
||||
## Fußnoten
|
||||
|
||||
[^s-private-instance-merge-correction-and-issue-30-session-2026-09-01]: [[Source - Private-Instance Merge Correction and Issue 30 Session 2026-09-01]]
|
||||
[^s-mcp-read-server-implementation-session-2026-09-02]: [[Source - MCP Read Server Implementation Session 2026-09-02]]
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|------|------|---------|----------------|
|
||||
| [[andybalholm-edl]] | project | Go-basierte EDL-Bibliothek für die Kommunikation mit eingebetteten Geräten. | 2026-08-29 |
|
||||
| [[BCDModule]] | project | Go-Modul, das die Entscheidungslogik für die Batterieladung umsetzt. | 2026-08-29 |
|
||||
| [[Chemenu]] | project | Deterministischer Wissenskompiler (raw/ -> kb/); seit 2.0.0 unter dem Namen Chemenu, seit 2026-09-01 oeffentlich als Testbett und Demo unter AGPL-3.0/CC-BY-4.0 | 2026-09-01 |
|
||||
| [[Chemenu]] | project | Deterministischer Wissenskompiler (raw/ -> kb/); seit 2.0.0 unter dem Namen Chemenu, seit 2026-09-01 oeffentlich, seit 2.4.0 mit einem MCP-Leseserver als zweitem Konsumenten | 2026-09-02 |
|
||||
| [[goresponsiveness]] | project | Go-Werkzeug zur Messung von Anwendungsleistung und Responsiveness. | 2026-08-29 |
|
||||
| [[ha-core]] | project | Kern-Integrationsbibliothek für Home-Assistant-E3DC-Systeme; stellt die E3DC-Kommunikationsprotokolle und den Home-Assistant-Integrationscode bereit. | 2026-08-29 |
|
||||
| [[hacs-e3dc]] | project | Home Assistant Custom Component zur Überwachung von E3DC-Energiesystemen. | 2026-08-29 |
|
||||
@@ -96,8 +96,8 @@
|
||||
| [[pascalandy schema]] | tool | Von der Community beigesteuertes Wiki Schema (Global) aus pascalandys Kommentar in Farzas Gist, mit alternativer Tag-Taxonomie (area/kind/topic/status/pty) | 2026-08-29 |
|
||||
| [[Pi]] | tool | Assistenz-Agent von Inflection AI; kann das LLM-Wiki-Muster wie andere LLM-Agenten umsetzen. | 2026-08-29 |
|
||||
| [[Proton]] | tool | Wine-basierte Kompatibilitätsschicht von Valve; lässt Windows-Spiele über Steam unter Linux laufen, mit optimierter DirectX-Übersetzung. | 2026-08-29 |
|
||||
| [[qmd]] | tool | Lokale Suchmaschine für Markdown-Dateien mit hybrider BM25-Vektor-Suche und LLM-Reranking. | 2026-08-29 |
|
||||
| [[qmd]] | tool | Lokale Suchmaschine fuer Markdown-Dateien: TypeScript/Node.js/Bun, SQLite-FTS5-BM25 plus sqlite-vec-Vektorsuche plus node-llama-cpp-LLM-Reranking. | 2026-09-02 |
|
||||
| [[Steam]] | tool | Valves Plattform für digitalen Spielevertrieb und Spielebibliothek auf dem PC. | 2026-08-29 |
|
||||
| [[wikitool]] | tool | Deterministisches CLI fuer alle mechanischen Wiki-Operationen; seit 2.0.0 liegt es im Python-Paket chemenu, das Kommando heisst weiterhin wikitool | 2026-09-01 |
|
||||
| [[wikitool]] | tool | Deterministisches CLI fuer alle mechanischen Wiki-Operationen; seit 2.0.0 im Paket chemenu, seit 2.4.0 zusaetzlich als MCP-Leseserver erreichbar | 2026-09-02 |
|
||||
| [[Wine]] | tool | Kompatibilitätsschicht, die Windows-API-Aufrufe nach POSIX übersetzt und Windows-Anwendungen unter Linux, BSD und macOS ohne Virtualisierung oder Emulation ausführt. | 2026-08-29 |
|
||||
|
||||
|
||||
@@ -3,13 +3,13 @@ type: types/entity.md
|
||||
entity_type: project
|
||||
tags: [wiki, llm, knowledge-base]
|
||||
created: 2026-08-04
|
||||
modified: 2026-09-01
|
||||
related: [Personalization Plane, Issue Label Scheme, Optional Instance Context File, Delete Rather Than Anonymize, Dual Licensing by File Plan, Publish-Remote Gate]
|
||||
sources: [Source - Copilot Skill Restructure Instructions, Source - Conversation - AGENTS.md Skill Restructuring Session 2026-08-04, Source - Conversation - Versioning CI-CD and Content Migration Session 2026-08-30, Source - Conversation - Comma Bug Budget Refund and Lint Report Path Session 2026-08-31, Source - Conversation - Issue Triage Labels and TODO Retirement Session 2026-08-31, Source - Conversation - Write-Once Frontmatter Fields and touch --set Session 2026-08-31, Source - Conversation - Gate Counting and Measured Calibration Session 2026-08-31, Source - Conversation - Two Round-Trip Defects Found by an Ingest Session 2026-08-31, Source - Conversation - Hardening the Test Suite Against Silent Environment Dependencies Session 2026-08-31, 'Source - Public Release, Corpus Purge and History Squash Session 2026-09-01', Source - Publish-Remote Gate and Issue Triage Session 2026-09-01, Source - Private-Instance Merge Correction and Issue 30 Session 2026-09-01]
|
||||
modified: 2026-09-02
|
||||
related: [Personalization Plane, Issue Label Scheme, Optional Instance Context File, Delete Rather Than Anonymize, Dual Licensing by File Plan, Publish-Remote Gate, MCP-Leseserver]
|
||||
sources: [Source - Copilot Skill Restructure Instructions, Source - Conversation - AGENTS.md Skill Restructuring Session 2026-08-04, Source - Conversation - Versioning CI-CD and Content Migration Session 2026-08-30, Source - Conversation - Comma Bug Budget Refund and Lint Report Path Session 2026-08-31, Source - Conversation - Issue Triage Labels and TODO Retirement Session 2026-08-31, Source - Conversation - Write-Once Frontmatter Fields and touch --set Session 2026-08-31, Source - Conversation - Gate Counting and Measured Calibration Session 2026-08-31, Source - Conversation - Two Round-Trip Defects Found by an Ingest Session 2026-08-31, Source - Conversation - Hardening the Test Suite Against Silent Environment Dependencies Session 2026-08-31, 'Source - Public Release, Corpus Purge and History Squash Session 2026-09-01', Source - Publish-Remote Gate and Issue Triage Session 2026-09-01, Source - Private-Instance Merge Correction and Issue 30 Session 2026-09-01, Source - MCP Read Server Implementation Session 2026-09-02]
|
||||
confidence: 0.90
|
||||
confidence_base: 0.90
|
||||
provenance: mixed
|
||||
summary: Deterministischer Wissenskompiler (raw/ -> kb/); seit 2.0.0 unter dem Namen Chemenu, seit 2026-09-01 oeffentlich als Testbett und Demo unter AGPL-3.0/CC-BY-4.0
|
||||
summary: Deterministischer Wissenskompiler (raw/ -> kb/); seit 2.0.0 unter dem Namen Chemenu, seit 2026-09-01 oeffentlich, seit 2.4.0 mit einem MCP-Leseserver als zweitem Konsumenten
|
||||
---
|
||||
# Chemenu
|
||||
|
||||
@@ -63,6 +63,7 @@ Das Repository hat bereits ein deterministisches CLI, `tools/wikitool` (Python,
|
||||
- **wendet an:** [[Delete Rather Than Anonymize]]
|
||||
- **wendet an:** [[Dual Licensing by File Plan]]
|
||||
- **setzt um:** [[Publish-Remote Gate]]
|
||||
- **enthaelt:** [[MCP-Leseserver]]
|
||||
|
||||
## Details
|
||||
|
||||
@@ -142,6 +143,13 @@ Repositorys selbst und keine Aussagen aus einer Rohdatenquelle; der Änderungsda
|
||||
|
||||
## Historie
|
||||
|
||||
- 2026-09-02 - `2.2.3`-`2.4.1`: Issue #36s vierstufige Sequenz zum [[MCP-Leseserver]] umgesetzt
|
||||
([[Publish-Remote Gate]] scharf gestellt, Lesepfad gehärtet, Root-Auflösung von der Importzeit
|
||||
gelöst, der Server selbst), dazu `INSTALL-MCP.md` und Issue #37 für das noch fehlende
|
||||
Container-Image. Alle vier Sequenz-Issues geschlossen; #36 blieb offen, weil sein eigenes
|
||||
Abschlusskriterium - ein Konsument, der nachweislich über die
|
||||
Authentifizierungs-Middleware antwortet - erst mit #37 erfüllbar
|
||||
ist.[^s-mcp-read-server-implementation-session-2026-09-02]
|
||||
- 2026-09-01 - `2.0.0` (Commit `9a7abe6`, 121 Dateien, 730 Tests grün): Rebranding von
|
||||
`llm-wiki-test1` auf **Chemenu** nach Gitea-Issue #3 - Repo-Rename, Produktname,
|
||||
Release-Artefakt (`chemenu-stack-<version>.tar.gz`), Release-Feed, und das Python-Paket
|
||||
@@ -219,6 +227,7 @@ Repositorys selbst und keine Aussagen aus einer Rohdatenquelle; der Änderungsda
|
||||
- [[Source - Publish-Remote Gate and Issue Triage Session 2026-09-01]]
|
||||
- [[Publish-Remote Gate]]
|
||||
- [[Source - Private-Instance Merge Correction and Issue 30 Session 2026-09-01]]
|
||||
- [[MCP-Leseserver]]
|
||||
|
||||
## Fußnoten
|
||||
|
||||
@@ -230,3 +239,4 @@ Repositorys selbst und keine Aussagen aus einer Rohdatenquelle; der Änderungsda
|
||||
[^s-conversation-gate-counting-and-measured-calibration-session-2026-08-31]: [[Source - Conversation - Gate Counting and Measured Calibration Session 2026-08-31]]
|
||||
[^s-conversation-write-once-frontmatter-fields-and-touch-set-session-2026-08-31]: [[Source - Conversation - Write-Once Frontmatter Fields and touch --set Session 2026-08-31]]
|
||||
[^s-conversation-comma-bug-budget-refund-and-lint-report-path-session-2026-08-31]: [[Source - Conversation - Comma Bug Budget Refund and Lint Report Path Session 2026-08-31]]
|
||||
[^s-mcp-read-server-implementation-session-2026-09-02]: [[Source - MCP Read Server Implementation Session 2026-09-02]]
|
||||
|
||||
+22
-11
@@ -3,13 +3,13 @@ type: types/entity.md
|
||||
entity_type: tool
|
||||
tags: [search, markdown, cli, local]
|
||||
created: 2026-07-26
|
||||
modified: 2026-08-29
|
||||
modified: 2026-09-02
|
||||
related: [Obsidian, LLM Wiki Pattern]
|
||||
sources: [Source - LLM Wiki Pattern]
|
||||
confidence: 0.85
|
||||
confidence_base: 0.85
|
||||
sources: [Source - LLM Wiki Pattern, Source - qmd - GitHub Repository]
|
||||
confidence: 0.80
|
||||
confidence_base: 0.80
|
||||
provenance: sourced
|
||||
summary: Lokale Suchmaschine für Markdown-Dateien mit hybrider BM25-Vektor-Suche und LLM-Reranking.
|
||||
summary: 'Lokale Suchmaschine fuer Markdown-Dateien: TypeScript/Node.js/Bun, SQLite-FTS5-BM25 plus sqlite-vec-Vektorsuche plus node-llama-cpp-LLM-Reranking.'
|
||||
---
|
||||
# qmd
|
||||
|
||||
@@ -22,11 +22,12 @@ qmd ist eine lokale Suchmaschine, die speziell für Markdown-Dateien ausgelegt i
|
||||
## Kerndaten
|
||||
|
||||
- **Typ:** CLI-Tool
|
||||
- **Sprache:** Nicht angegeben (wahrscheinlich Go oder Rust)
|
||||
- **Such-Typen:** Hybrid (BM25 + Vector)
|
||||
- **Neu-Ranking:** LLM-basiert
|
||||
- **Sprache:** TypeScript, Laufzeit Node.js oder Bun
|
||||
- **Such-Typen:** Hybrid (SQLite-FTS5-BM25 + `sqlite-vec`-Vektorsuche)
|
||||
- **Neu-Ranking:** LLM-basiert über `node-llama-cpp` (lokale GGUF-Modelle)
|
||||
- **Bereitstellung:** On-device/lokal
|
||||
- **Repository:** https://github.com/tobi/qmd
|
||||
- **Installation:** `npm install -g @tobilu/qmd` oder `bun install -g @tobilu/qmd`
|
||||
|
||||
## Beziehungen
|
||||
|
||||
@@ -50,11 +51,13 @@ qmd ist eine lokale Suchmaschine, die speziell für Markdown-Dateien ausgelegt i
|
||||
## Installation und Verwendung
|
||||
|
||||
```bash
|
||||
# Installation (hypothetisch, siehe aktuelles Repo für Details)
|
||||
go install github.com/tobi/qmd@latest
|
||||
# Installation (Node oder Bun)
|
||||
npm install -g @tobilu/qmd
|
||||
# oder
|
||||
bun install -g @tobilu/qmd
|
||||
|
||||
# Suche von CLI
|
||||
qmd search "knowledge management"
|
||||
qmd query "knowledge management"
|
||||
|
||||
# Als MCP-Server für LLM-Integration verwenden
|
||||
qmd server
|
||||
@@ -74,9 +77,17 @@ qmd server
|
||||
|
||||
## Historie
|
||||
|
||||
- [2026-09-02] - Sprachangabe korrigiert. Die Seite trug seit ihrer Erstellung "Nicht angegeben
|
||||
(wahrscheinlich Go oder Rust)" bei `confidence: 0.85` - eine Vermutung mit einer Konfidenz, die
|
||||
für eine Vermutung zu hoch war. Direkt gegen das Repository geprüft: TypeScript, Laufzeit
|
||||
Node.js/Bun, SQLite-FTS5-BM25 + `sqlite-vec` + `node-llama-cpp`.[^s-qmd-github-repository]
|
||||
- [2026-07-26] - Entity-Seite während der Aufnahme des LLM-Wiki-Pattern-Artikels erstellt
|
||||
|
||||
## Siehe auch
|
||||
|
||||
- [[LLM Wiki Pattern]]
|
||||
- [[Obsidian]]
|
||||
|
||||
## Fußnoten
|
||||
|
||||
[^s-qmd-github-repository]: [[Source - qmd - GitHub Repository]]
|
||||
|
||||
@@ -3,13 +3,13 @@ type: types/entity.md
|
||||
entity_type: tool
|
||||
tags: [cli, automation, deterministic, wiki-management]
|
||||
created: 2026-08-03
|
||||
modified: 2026-09-01
|
||||
related: [Semantic Lint Automation, Session Orientation, Iteration and Cost Limits, KB Stack Versioning, KB Migration, Personalization Plane, Detect-Repair Asymmetry, Write-Once Frontmatter Fields, Denylist over Allowlist, Command Round-Trip Integrity, Green Suite Blind Spot, Ambient Environment Dependency, Structural Enforcement over Documented Rule, Optional Instance Context File]
|
||||
sources: [Source - LLM Improvements Codex Analysis, Source - LLM Improvements Sonnet Analysis, Source - Copilot Skill Restructure Instructions, Source - Conversation - AGENTS.md Skill Restructuring Session 2026-08-04, Source - LLM Improvements Production Agent Gaps 2026, Source - Conversation - Versioning CI-CD and Content Migration Session 2026-08-30, Source - Conversation - Comma Bug Budget Refund and Lint Report Path Session 2026-08-31, Source - Conversation - Issue Triage Labels and TODO Retirement Session 2026-08-31, Source - Conversation - Auto Mode and Tool Choice Session 2026-08-31, Source - Conversation - Write-Once Frontmatter Fields and touch --set Session 2026-08-31, Source - Conversation - Gate Counting and Measured Calibration Session 2026-08-31, Source - Conversation - Two Round-Trip Defects Found by an Ingest Session 2026-08-31, Source - Conversation - Hardening the Test Suite Against Silent Environment Dependencies Session 2026-08-31, Source - Conversation - ENVIRONMENT.md as an Optional Third Session-Level File Session 2026-08-31, 'Source - Public Release, Corpus Purge and History Squash Session 2026-09-01', Source - Publish-Remote Gate and Issue Triage Session 2026-09-01, Source - Private-Instance Merge Correction and Issue 30 Session 2026-09-01]
|
||||
modified: 2026-09-02
|
||||
related: [Semantic Lint Automation, Session Orientation, Iteration and Cost Limits, KB Stack Versioning, KB Migration, Personalization Plane, Detect-Repair Asymmetry, Write-Once Frontmatter Fields, Denylist over Allowlist, Command Round-Trip Integrity, Green Suite Blind Spot, Ambient Environment Dependency, Structural Enforcement over Documented Rule, Optional Instance Context File, MCP-Leseserver]
|
||||
sources: [Source - LLM Improvements Codex Analysis, Source - LLM Improvements Sonnet Analysis, Source - Copilot Skill Restructure Instructions, Source - Conversation - AGENTS.md Skill Restructuring Session 2026-08-04, Source - LLM Improvements Production Agent Gaps 2026, Source - Conversation - Versioning CI-CD and Content Migration Session 2026-08-30, Source - Conversation - Comma Bug Budget Refund and Lint Report Path Session 2026-08-31, Source - Conversation - Issue Triage Labels and TODO Retirement Session 2026-08-31, Source - Conversation - Auto Mode and Tool Choice Session 2026-08-31, Source - Conversation - Write-Once Frontmatter Fields and touch --set Session 2026-08-31, Source - Conversation - Gate Counting and Measured Calibration Session 2026-08-31, Source - Conversation - Two Round-Trip Defects Found by an Ingest Session 2026-08-31, Source - Conversation - Hardening the Test Suite Against Silent Environment Dependencies Session 2026-08-31, Source - Conversation - ENVIRONMENT.md as an Optional Third Session-Level File Session 2026-08-31, 'Source - Public Release, Corpus Purge and History Squash Session 2026-09-01', Source - Publish-Remote Gate and Issue Triage Session 2026-09-01, Source - Private-Instance Merge Correction and Issue 30 Session 2026-09-01, Source - MCP Read Server Implementation Session 2026-09-02]
|
||||
confidence: 0.90
|
||||
confidence_base: 0.90
|
||||
provenance: sourced
|
||||
summary: Deterministisches CLI fuer alle mechanischen Wiki-Operationen; seit 2.0.0 liegt es im Python-Paket chemenu, das Kommando heisst weiterhin wikitool
|
||||
summary: Deterministisches CLI fuer alle mechanischen Wiki-Operationen; seit 2.0.0 im Paket chemenu, seit 2.4.0 zusaetzlich als MCP-Leseserver erreichbar
|
||||
---
|
||||
# wikitool
|
||||
|
||||
@@ -51,6 +51,7 @@ Wie in der Codex-Analyse vermerkt, bietet wikitool die deterministische Grundlag
|
||||
- **zeigte:** [[Ambient Environment Dependency]]
|
||||
- **setzt um:** [[Structural Enforcement over Documented Rule]]
|
||||
- **setzt um:** [[Optional Instance Context File]]
|
||||
- **implementiert:** [[MCP-Leseserver]]
|
||||
|
||||
## Befehle
|
||||
|
||||
@@ -73,6 +74,9 @@ wikitool bietet die folgenden Befehlskategorien:
|
||||
Seitenkopf zurückgefaltet statt abgelehnt, und weil der Block immer zuletzt gerendert wird,
|
||||
richtet die erste Zitatoperation eine verrutschte Seite von selbst wieder ein[^s-conversation-two-round-trip-defects-found-by-an-ingest-session-2026-08-31]
|
||||
- **Abfrage:** `search` - Textsuche über `kb/` durch ein austauschbares Backend (`rg` heute), plus `--field`-Prädikate, die auf Frontmatter evaluiert werden (`entity_type=system`, `confidence>=0.8`, `tags=k8s`, `!source_url`). Ohne Text ist es eine reine strukturierte Abfrage. Schreibgeschützt und ausgenommen von der Iteration-Budget-Gate, da Abfrage das Lesen statt das Iterieren ist
|
||||
- **MCP-Server:** `python -m chemenu.mcp` (`--transport stdio|streamable-http`) - kein
|
||||
`wikitool`-Unterbefehl, sondern ein zweiter Einstiegspunkt über `chemenu.api.Corpus`, derselbe
|
||||
Kern wie `search`/`types`/`lint`. Siehe [[MCP-Leseserver]]
|
||||
- **Indizierung:** `index rebuild` - regeneriert die `kb/index.md`-Map plus eine pro-Sammlung `INDEX.md`, wobei ein Bereich bei 50 Zeilen in seine eigene Shard aufgeteilt wird
|
||||
- **Herkunft:** `sources coverage`, `sources trace`, `sources rebuild-index`
|
||||
- **Protokollierung:** `log append`, `log status`
|
||||
@@ -147,6 +151,22 @@ ist[^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30].
|
||||
|
||||
## Historie
|
||||
|
||||
- 2026-09-02 - `2.2.3`-`2.4.1`: die vierstufige Sequenz aus Issue #36 (Publish-Remote-Gate
|
||||
scharf, Lesepfad gehärtet, Root-Auflösung und Bibliotheksgrenze, [[MCP-Leseserver]]) plus
|
||||
Menschendoku. `.wikitool-remotes.json` war trotz gegenteiliger Dokumentation nicht gesetzt -
|
||||
angelegt und gegen ein erfundenes Ziel gegengeprüft (Exit 42). Sechs Lesepfad-Härtungen:
|
||||
gelöschter ReDoS-Zweig in der Ranking-Funktion, ein 30-Sekunden-`rg`-Timeout, ein
|
||||
YAML-Alias-Refusal (267 B → 672.603 Knoten reproduziert), `CSafeLoader` (265 ms → 54 ms),
|
||||
gemeldetes statt geschlucktes kaputtes Frontmatter, ein Korpus-Cache, der nie einen
|
||||
schmutzigen Arbeitsbaum cacht. `config.ROOT` und alle abgeleiteten Pfade waren zur Importzeit
|
||||
gebunden - jetzt lazy aufgelöst (`$CHEMENU_ROOT` → Walk-up), mit einem eigenen
|
||||
`config.reset()` gegen eine Falle, in die `monkeypatch`s eigener Teardown sonst zurückläuft.
|
||||
Neuer typerloser Lesekern (`search/service.py`, `lint_core.py`, `types_core.py`) hinter
|
||||
`chemenu.api.Corpus`, darüber der MCP-Server: `search`/`types`/`describe_type`/`lint`/`status`,
|
||||
strukturell ohne Schreibpfad, jede Antwort mit Commit-Stempel. `wikitool search` end-to-end
|
||||
593 ms → 347 ms. Menschendoku `INSTALL-MCP.md`, ausgeliefert über `dist_cmd.ROOT_FILES`.
|
||||
Siehe [[Publish-Remote Gate]], [[Mass-Update Gate]],
|
||||
[[MCP-Leseserver]][^s-mcp-read-server-implementation-session-2026-09-02]
|
||||
- 2026-09-01 - `2.1.0`-`2.2.2`: Vorbereitung und Durchführung der Veröffentlichung. `dist export`
|
||||
bekommt `REQUIRED_ROOT_FILES` (fehlende Lizenzdateien lassen den Export scheitern statt still
|
||||
weiterzulaufen) und `find_leaks()` (strukturelle Prüfung des fertigen Export-Plans gegen
|
||||
@@ -267,6 +287,7 @@ ist[^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30].
|
||||
- [[Source - Public Release, Corpus Purge and History Squash Session 2026-09-01]]
|
||||
- [[Source - Publish-Remote Gate and Issue Triage Session 2026-09-01]]
|
||||
- [[Source - Private-Instance Merge Correction and Issue 30 Session 2026-09-01]]
|
||||
- [[MCP-Leseserver]]
|
||||
|
||||
## Fußnoten
|
||||
|
||||
@@ -281,3 +302,4 @@ ist[^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30].
|
||||
[^s-llm-improvements-codex-analysis]: [[Source - LLM Improvements Codex Analysis]]
|
||||
[^s-public-release-corpus-purge-and-history-squash-session-2026-09-01]: [[Source - Public Release, Corpus Purge and History Squash Session 2026-09-01]]
|
||||
[^s-publish-remote-gate-and-issue-triage-session-2026-09-01]: [[Source - Publish-Remote Gate and Issue Triage Session 2026-09-01]]
|
||||
[^s-mcp-read-server-implementation-session-2026-09-02]: [[Source - MCP Read Server Implementation Session 2026-09-02]]
|
||||
|
||||
+6
-6
@@ -13,12 +13,12 @@ The page tables live in a generated `INDEX.md` inside each collection, linked be
|
||||
|
||||
## Statistics
|
||||
|
||||
- **Total Pages:** 176
|
||||
- **Total Pages:** 179
|
||||
- **Comparisons:** 1
|
||||
- **Concepts:** 79
|
||||
- **Concepts:** 80
|
||||
- **Entities:** 72
|
||||
- **Sources:** 24
|
||||
- **Last Updated:** 2026-09-01
|
||||
- **Sources:** 26
|
||||
- **Last Updated:** 2026-09-02
|
||||
|
||||
---
|
||||
|
||||
@@ -27,9 +27,9 @@ The page tables live in a generated `INDEX.md` inside each collection, linked be
|
||||
| Collection | Pages | Index |
|
||||
|------------|------:|-------|
|
||||
| `comparisons/` | 1 | [comparisons/INDEX.md](comparisons/INDEX.md) |
|
||||
| `concepts/` | 79 | [concepts/INDEX.md](concepts/INDEX.md) |
|
||||
| `concepts/` | 80 | [concepts/INDEX.md](concepts/INDEX.md) |
|
||||
| `entities/` | 72 | [entities/INDEX.md](entities/INDEX.md) |
|
||||
| `sources/` | 24 | [sources/INDEX.md](sources/INDEX.md) |
|
||||
| `sources/` | 26 | [sources/INDEX.md](sources/INDEX.md) |
|
||||
|
||||
### entities/
|
||||
|
||||
|
||||
@@ -73,3 +73,21 @@ Source-Seite angelegt, neue Concept-Seite Publish-Remote Gate, wikitool-Historie
|
||||
Source-Seite angelegt, Publish-Remote-Gate-Seite um die gemessene Merge-Semantik erweitert, quer verlinkt.
|
||||
|
||||
---
|
||||
|
||||
## [2026-09-02] ingest | MCP Read Server Implementation Session 2026-09-02
|
||||
|
||||
Source-Seite und neues Concept MCP-Leseserver angelegt; wikitool, Chemenu, Publish-Remote Gate und Iteration and Cost Limits aktualisiert. Deckt Issue #36s Sequenz (#34/#33/#31/#19), INSTALL-MCP.md und Issue #37 ab.
|
||||
|
||||
---
|
||||
|
||||
## [2026-09-02] update | qmd - Sprachangabe korrigiert
|
||||
|
||||
Direkt gegen tobi/qmd auf GitHub geprueft: TypeScript statt der geratenen 'Go oder Rust'-Angabe. Neue Quelle Source - qmd - GitHub Repository (raw/documents/), confidence_base 0.85 -> 0.80 neu begruendet, Installationsbeispiel korrigiert.
|
||||
|
||||
---
|
||||
|
||||
## [2026-09-02] update | MCP Read Server Implementation Session 2026-09-02 - Korrektur
|
||||
|
||||
Aufgaben-Checkbox fuer die qmd.md-Korrektur nachgezogen (war [ ], ist erledigt) und ein Korrektur-Hinweis ergaenzt: der Fidelity-Block des Rohtranskripts kuendigte ein zweites Transkript fuer die qmd-Korrektur an, das nie geschrieben wurde - die Korrektur lief stattdessen als eigene Quellen-Verifikation. raw/ ist unveraenderlich, die Korrektur steht deshalb auf der Source-Seite.
|
||||
|
||||
---
|
||||
|
||||
+12
-2
@@ -8,8 +8,8 @@ inline `[^cite-id]` footnote).
|
||||
|
||||
## Coverage Summary
|
||||
|
||||
- **Total raw files:** 24
|
||||
- **Covered:** 24
|
||||
- **Total raw files:** 26
|
||||
- **Covered:** 26
|
||||
- **Uncovered:** 0
|
||||
|
||||
---
|
||||
@@ -31,6 +31,11 @@ inline `[^cite-id]` footnote).
|
||||
- Covered by: [[Source - LLM Wiki Pattern]]
|
||||
- Cited by: [[Andrej Karpathy]], [[ChatGPT]], [[Claude Code]], [[Dataview]], [[Knowledge Compounding]], [[LLM Wiki Pattern]], [[Marp]], [[Memex]], [[NotebookLM]], [[Obsidian]], [[Obsidian Web Clipper]], [[OpenAI Codex]], [[OpenCode]], [[Pi]], [[RAG]], [[Three-Layer Architecture]], [[Tolkien Gateway]], [[Vannevar Bush]], [[qmd]]
|
||||
|
||||
### `raw/documents/qmd - GitHub Repository.md`
|
||||
|
||||
- Covered by: [[Source - qmd - GitHub Repository]]
|
||||
- Cited by: [[qmd]]
|
||||
|
||||
### `raw/notes/Arch Linux Cheat Sheet.md`
|
||||
|
||||
- Covered by: [[Source - Arch Linux Cheat Sheet]]
|
||||
@@ -71,6 +76,11 @@ inline `[^cite-id]` footnote).
|
||||
- Covered by: [[Source - Conversation - Issue Triage Labels and TODO Retirement Session 2026-08-31]]
|
||||
- Cited by: [[Chemenu]], [[Detect-Repair Asymmetry]], [[Gitea]], [[Gitea Actions]], [[Gitea MCP Server]], [[Issue Label Scheme]], [[KB Stack Versioning]], [[wikitool]]
|
||||
|
||||
### `raw/notes/Conversation Transcript - MCP Read Server Implementation Session 2026-09-02.md`
|
||||
|
||||
- Covered by: [[Source - MCP Read Server Implementation Session 2026-09-02]]
|
||||
- Cited by: [[Chemenu]], [[Iteration and Cost Limits]], [[MCP-Leseserver]], [[Publish-Remote Gate]], [[wikitool]]
|
||||
|
||||
### `raw/notes/Conversation Transcript - Nightly Drift-Check Workflow and doctor's Bootstrap Gap Session 2026-08-31.md`
|
||||
|
||||
- Covered by: [[Source - Conversation - Nightly Drift-Check Workflow and doctor's Bootstrap Gap Session 2026-08-31]]
|
||||
|
||||
+3
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
# kb/sources/ - Index
|
||||
|
||||
24 page(s). Regenerated by `wikitool index rebuild`.
|
||||
26 page(s). Regenerated by `wikitool index rebuild`.
|
||||
|
||||
## All
|
||||
|
||||
@@ -28,8 +28,10 @@
|
||||
| [[Source - LLM Improvements Sonnet Analysis]] | notes | Sonnet-Analyse, die AGENTS.md und wikitool mit Farzas Gist und awesome-llm-wiki vergleicht und die Codex-Analyse um konkrete Empfehlungen zu Qualitätsschwellen, Stilrichtlinie, Auditrhythmus und Skalierung ergänzt | 2026-08-03 |
|
||||
| [[Source - LLM Wiki Pattern]] | article | Grundlegendes Muster für persönliche Wissensbasen mit LLMs: ein dauerhaftes Wiki schrittweise pflegen, statt es aus den Quellen neu herzuleiten. | 2026-07-26 |
|
||||
| [[Source - LLM Wiki v2]] | article | Erweitertes LLM-Wiki-Muster mit Praxiserfahrungen aus agentmemory zu Memory Lifecycle, Confidence Scoring, Wissensgraph und Automatisierung. | 2026-07-26 |
|
||||
| [[Source - MCP Read Server Implementation Session 2026-09-02]] | notes | Sitzung, die die Sequenz aus Issue #36 umsetzt: Publish-Remote Gate scharf, Lesepfad gehaertet, Root-Aufloesung und Bibliotheksgrenze gezogen, MCP-Leseserver gebaut - vier Versionsstufen 2.2.3 bis 2.4.0, dazu INSTALL-MCP.md und Issue #37. | 2026-09-02 |
|
||||
| [[Source - Private-Instance Merge Correction and Issue 30 Session 2026-09-01]] | notes | Sitzung, die eine ungeprueft niedergeschriebene Merge-Behauptung in private-instance.md durch einen empirischen Test widerlegt, die Prozedur korrigiert (2.2.1) und Issue #30 mit einem getesteten Skript sowie zwei Architekturvorschlaegen anlegt. | 2026-09-01 |
|
||||
| [[Source - Public Release, Corpus Purge and History Squash Session 2026-09-01]] | notes | Sitzung, die den Chemenu-Stack von einer privaten Testinstanz in ein oeffentliches Repo ueberfuehrt: Korpus geloescht statt anonymisiert, Git-History auf einen Commit gesquashed, AGPL-3.0/CC-BY-4.0-Dual-Lizenz gewaehlt, dist export um einen Leak-Canary gehaertet. | 2026-09-01 |
|
||||
| [[Source - Publish-Remote Gate and Issue Triage Session 2026-09-01]] | notes | Sitzung, die ein drittes, Token-loses Gate fuer publish baut, instructions/private-instance.md schreibt, sechs Gitea-Issues auf den Rename und die neue Architektur nachzieht und die Actions-Run-Historie entfernen laesst. | 2026-09-01 |
|
||||
| [[Source - qmd - GitHub Repository]] | document | GitHub-API-Metadaten, package.json und README-Auszuege von tobi/qmd: TypeScript/Node/Bun statt Go oder Rust, BM25 (SQLite FTS5) plus Vektor-Suche (sqlite-vec) plus LLM-Reranking ueber node-llama-cpp. | 2026-09-02 |
|
||||
| [[Source - Wine]] | notes | Wine-Konfiguration für Arch Linux: pacman-NoExtract-Einstellungen und Bottles-Runtime-Optionen einschließlich Proton- und Lutris-Varianten. | 2026-08-01 |
|
||||
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
---
|
||||
type: types/source.md
|
||||
source_type: notes
|
||||
author: Torben
|
||||
raw_files: [raw/notes/Conversation Transcript - MCP Read Server Implementation Session 2026-09-02.md]
|
||||
source_language: de
|
||||
date: 2026-09-02
|
||||
tags: []
|
||||
entities: [wikitool, Chemenu]
|
||||
concepts: [Publish-Remote Gate, Mass-Update Gate, Iteration and Cost Limits, MCP-Leseserver]
|
||||
summary: 'Sitzung, die die Sequenz aus Issue #36 umsetzt: Publish-Remote Gate scharf, Lesepfad gehaertet, Root-Aufloesung und Bibliotheksgrenze gezogen, MCP-Leseserver gebaut - vier Versionsstufen 2.2.3 bis 2.4.0, dazu INSTALL-MCP.md und Issue #37.'
|
||||
---
|
||||
# Source: MCP Read Server Implementation Session 2026-09-02
|
||||
|
||||
**Autor:** Torben
|
||||
**Datum:** 2026-09-02
|
||||
**Raw-Dateien:** raw/notes/Conversation Transcript - MCP Read Server Implementation Session 2026-09-02.md
|
||||
**Typ:** Notes
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
Diese Sitzung arbeitet die vierstufige Sequenz aus Issue #36 ab, dem Sammel-Issue für den Weg
|
||||
zum MCP-Leseserver: #34 (Publish-Remote-Gate scharf stellen), #33 (Lesepfad vor der Exposition
|
||||
härten), #31 (Root-Auflösung von der Importzeit lösen und eine Bibliotheksgrenze ziehen), #19
|
||||
(der Leseserver selbst). Jeder Schritt endet mit einem Versions-Bump und einem Testlauf; die
|
||||
Reihenfolge folgt dem Master-Issue, weil #33 dieselben Dateien anfasst, die #31 strukturell
|
||||
umbaut, und #31 die Grenze liefert, auf der #19 aufsetzt.
|
||||
|
||||
`.wikitool-remotes.json` fehlte in diesem Checkout trotz Dokumentation, die das Gegenteil
|
||||
behauptete - angelegt und gegen ein erfundenes Ziel gegengeprüft (Exit 42). Der Lesepfad bekam
|
||||
sechs Fixes gegen einen 267-Byte-YAML-Alias, der zu 672.603 Knoten expandiert, gegen einen
|
||||
ReDoS-Zweig in der Ranking-Funktion, einen fehlenden Subprozess-Timeout, und einen Korpus-Cache,
|
||||
der nie einen schmutzigen Arbeitsbaum cacht. `config.ROOT` und alle abgeleiteten Pfade waren zur
|
||||
Importzeit gebunden; die Auflösung ist jetzt lazy (`CHEMENU_ROOT` → Walk-up), und der reine
|
||||
Lesekern (`search/service.py`, `lint_core.py`, `types_core.py`) importiert kein `typer` mehr.
|
||||
Der MCP-Server (`tools/chemenu/mcp/`) exponiert `search`/`types`/`describe_type`/`lint`/`status`
|
||||
über `chemenu.api.Corpus` - strukturell ohne Schreibpfad, mit Commit-Stempel auf jeder Antwort
|
||||
und einer Startverweigerung, falls Telemetrie in den bedienten Baum schreiben würde.
|
||||
|
||||
Nach Freigabe des 37-Datei-Changesets (Mass-Update-Gate, Token `46442f4419c1`) folgten
|
||||
`INSTALL-MCP.md` für Menschen, ein Verweis auf die separate Traefik-ForwardAuth-Middleware
|
||||
(`gitea-mcp-forward-auth`), und Issue #37 für das noch fehlende Container-Image - mit den
|
||||
konkreten CI-Vorlagen aus `gitea-mcp-forward-auth` (Registry-Push) und `gitea-mcp`
|
||||
(Dockerfile-Form, aber DockerHub statt der eigenen Registry). Alle vier Sequenz-Issues wurden
|
||||
geschlossen, #36 blieb offen, weil sein eigenes Abschlusskriterium - ein Konsument, der
|
||||
nachweislich über die Middleware antwortet - erst mit #37 erfüllbar ist.
|
||||
|
||||
## Kernaussagen
|
||||
|
||||
- Gemessen: Korpus-Parse 265 ms → 54 ms (`CSafeLoader`), `wikitool search` end-to-end
|
||||
593 ms → 347 ms; die verbleibenden ~262 ms sind Modulimport und entfallen erst im residenten
|
||||
MCP-Prozess.
|
||||
- Der ReDoS-Zweig (`_contains` mit `re.search` gegen nutzergesteuerten Regex) wurde gelöscht,
|
||||
nicht begrenzt - `rg` wendet das Muster ohnehin mit einer linearen Engine an, bevor die
|
||||
Funktion je läuft.
|
||||
- `monkeypatch.setattr(config, "ROOT", ...)` baute nach der lazy-Auflösung die stale Bindung
|
||||
beim Teardown wieder auf, weil es den *aufgelösten* alten Wert zurückschreibt - `config.reset()`
|
||||
musste dazukommen, in derselben autouse-Fixture, die das Problem eine Ebene höher (Umgebungsvariablen)
|
||||
bereits kannte.
|
||||
- Der MCP-Server hat keinen Schreibpfad, weil `chemenu.api` nichts unter `chemenu.commands`
|
||||
importiert - nicht, weil eine Liste gefiltert wird. Ein Test importiert das Servermodul in
|
||||
einem frischen Interpreter und prüft `sys.modules`.
|
||||
- Ein Stempel-Bug wurde beim Schreiben des Golden-Tests selbst gefunden: `_stamp()` fragte nach
|
||||
der *aktuellen* statt der beim Laden tatsächlich gelesenen Revision und hätte bei einem
|
||||
minimal verzögerten zweiten Zugriff `commit: null` auf einem sauberen Baum liefern können.
|
||||
- `gitea-mcp` ist als Registry-Vorlage ungeeignet - sein Release-Workflow pusht nach DockerHub
|
||||
(Fork des Upstream), nicht in die eigene Gitea-Registry.
|
||||
|
||||
## Aufgaben
|
||||
|
||||
- [x] #34, #33, #31, #19 umgesetzt und mit Abschlusskommentar geschlossen
|
||||
- [x] `INSTALL-MCP.md` geschrieben, in `INSTALL.md`/`README.md` verlinkt, in `dist export` aufgenommen
|
||||
- [x] Issue #37 (Container-Image) angelegt, mit neun offenen Entscheidungen benannt
|
||||
- [ ] #37 selbst umsetzen
|
||||
- [ ] #36 schließen, sobald #37 den Middleware-Nachweis liefert
|
||||
- [ ] #23 (Env-Var-Erzwingung) - `CHEMENU_ROOT` wurde von Hand in `_WIKITOOL_ENV` eingetragen
|
||||
- [x] `kb/entities/tools/qmd.md` - falsche Sprachangabe korrigiert (siehe Korrektur unten)
|
||||
|
||||
## Korrektur zum Transkript-Kopf
|
||||
|
||||
Der Fidelity-Block des Rohtranskripts sagt: "One of two transcripts cut from this session; the
|
||||
other covers fixing `kb/entities/tools/qmd.md`". Dieses zweite Transkript wurde nie geschrieben
|
||||
- `raw/` ist unveränderlich, die Korrektur gehört hierher, nicht in die Datei selbst. Tatsächlich
|
||||
lief die Korrektur ohne eigenes Transkript: direkt gegen `tobi/qmd` auf GitHub geprüft und als
|
||||
eigene Quelle mit eigenem Raw-Beleg abgelegt (`Source - qmd - GitHub Repository`,
|
||||
`raw/documents/qmd - GitHub Repository.md`) - eine Quellen-Verifikation statt eines
|
||||
Gesprächsprotokolls, was für eine Sprachangaben-Korrektur die passendere Belegform ist.
|
||||
|
||||
## Nicht übernommen
|
||||
|
||||
- Der vollständige Wortlaut der geprüften Docstrings, Kommentare und Testfälle - das Transkript
|
||||
benennt Dateien und die tragenden Eigenschaften, der Code selbst ist die Quelle.
|
||||
- Die exakten neun offenen Entscheidungspunkte aus Issue #37 (Korpus im Image vs. Volume,
|
||||
Basis-Image, Healthcheck etc.) - dort bereits vollständig dokumentiert, hier nicht dupliziert.
|
||||
- Der Wortlaut der abgerufenen READMEs von `gitea-mcp-forward-auth` und `gitea-mcp` - nur die
|
||||
für die Entscheidung relevanten Fakten (Config-Variablen, Workflow-Form, Registry-Ziel)
|
||||
wurden übernommen.
|
||||
|
||||
## Verwandte Entities
|
||||
|
||||
- [[wikitool]]
|
||||
- [[Chemenu]]
|
||||
|
||||
## Verwandte Concepts
|
||||
|
||||
- [[Publish-Remote Gate]]
|
||||
- [[Mass-Update Gate]]
|
||||
- [[Iteration and Cost Limits]]
|
||||
- [[MCP-Leseserver]]
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
type: types/source.md
|
||||
source_type: document
|
||||
author: Torben
|
||||
raw_files: [raw/documents/qmd - GitHub Repository.md]
|
||||
source_url: https://github.com/tobi/qmd
|
||||
source_language: en
|
||||
date: 2026-09-02
|
||||
tags: []
|
||||
entities: [qmd]
|
||||
concepts: []
|
||||
summary: 'GitHub-API-Metadaten, package.json und README-Auszuege von tobi/qmd: TypeScript/Node/Bun statt Go oder Rust, BM25 (SQLite FTS5) plus Vektor-Suche (sqlite-vec) plus LLM-Reranking ueber node-llama-cpp.'
|
||||
---
|
||||
# Source: qmd - GitHub Repository
|
||||
|
||||
**Autor:** Torben
|
||||
**Datum:** 2026-09-02
|
||||
**Raw-Dateien:** raw/documents/qmd - GitHub Repository.md
|
||||
**Typ:** Document
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
Direkter Abruf von `tobi/qmd` auf GitHub (Repo-Metadaten über die GitHub-API, `package.json`,
|
||||
README-Auszüge), um eine bestehende, unsichere Behauptung auf der Entity-Seite [[qmd]] zu
|
||||
prüfen. Die Seite trug seit ihrer Erstellung `Sprache: Nicht angegeben (wahrscheinlich Go oder
|
||||
Rust)` bei `confidence: 0.85` - eine geratene Angabe mit einer Konfidenz, die für eine Vermutung
|
||||
zu hoch war. Die GitHub-API meldet `"language": "TypeScript"`, mit einem byte-gewichteten
|
||||
Sprach-Split von 1.597.168 B TypeScript gegenüber 200.880 B Python, 26.136 B Shell,
|
||||
23.132 B JavaScript und weniger als 6 KB restlicher Sprachen - kein Go, kein Rust im Repository.
|
||||
|
||||
Das npm-Paket heißt `@tobilu/qmd`, installiert per `npm install -g` oder `bun install -g`,
|
||||
ausgeführt per `npx`/`bunx` - keine Go-typische `go install`-Zeile, wie die alte Seite
|
||||
behauptete. `package.json` listet `node-llama-cpp` (LLM-Inferenz), `sqlite-vec` (Vektorindex)
|
||||
und `better-sqlite3` (SQLite-Bindung) als direkte Abhängigkeiten; das README bestätigt das
|
||||
Zusammenspiel explizit: „QMD combines BM25 full-text search, vector semantic search, and LLM
|
||||
re-ranking—all running locally via node-llama-cpp with GGUF models." Die Scoring-Tabelle des
|
||||
Architektur-Abschnitts benennt zusätzlich `SQLite FTS5 BM25` als konkreten Volltext-Mechanismus,
|
||||
nicht nur „BM25" allgemein.
|
||||
|
||||
## Kernaussagen
|
||||
|
||||
- Sprache: TypeScript (GitHub-API `language`-Feld, bestätigt durch die Byte-Gewichtung).
|
||||
- Runtime: Node.js oder Bun, nicht Go/Rust - Installationsbefehle im README belegen das direkt.
|
||||
- Such-Stack: SQLite FTS5 (BM25) + `sqlite-vec` (Vektor-Ähnlichkeit) + `node-llama-cpp`
|
||||
(LLM-Reranking mit GGUF-Modellen) - deckungsgleich mit dem, was die alte Seite unter
|
||||
„Such-Capabilities" bereits beschrieb, nur ohne konkrete Technologienamen.
|
||||
- Enthält einen `@modelcontextprotocol/server`-Abhängigkeit, deckungsgleich mit der bereits auf
|
||||
der Seite genannten MCP-Server-Funktion.
|
||||
|
||||
## Aufgaben
|
||||
|
||||
- [x] `kb/entities/tools/qmd.md`s Sprachangabe korrigiert und mit dieser Quelle belegt
|
||||
|
||||
## Nicht übernommen
|
||||
|
||||
- Der vollständige Funktionsumfang (Library-API, MCP-Server-Details, Tree-Sitter-basiertes
|
||||
Code-Chunking, Konfigurationsdatei-Referenz, CLI-Unterbefehle) - nur das zur Korrektur der
|
||||
Sprach-/Stack-Angabe Nötige wurde übernommen. Eine künftige Erweiterung der `qmd`-Seite um
|
||||
diese Themen bräuchte einen neuen Abruf, nicht diese Quelle.
|
||||
|
||||
## Verwandte Entities
|
||||
|
||||
- [[qmd]]
|
||||
|
||||
## Verwandte Concepts
|
||||
|
||||
- None identified
|
||||
@@ -0,0 +1,101 @@
|
||||
# qmd - GitHub Repository (tobi/qmd)
|
||||
|
||||
> Source: https://github.com/tobi/qmd
|
||||
> Retrieved: 2026-09-02, via `https://api.github.com/repos/tobi/qmd`,
|
||||
> `https://api.github.com/repos/tobi/qmd/languages`, and the raw README/`package.json` at the
|
||||
> `main` branch HEAD (`pushed_at: 2026-08-18T14:26:31Z` at retrieval time).
|
||||
> Fidelity: the API JSON fields are quoted verbatim; the README/package.json excerpts below are
|
||||
> quoted verbatim from the fetched files, trimmed to what backs the corrected claims on
|
||||
> `kb/entities/tools/qmd.md` - not a full copy of either file.
|
||||
|
||||
## Repository metadata (GitHub API)
|
||||
|
||||
```json
|
||||
{
|
||||
"full_name": "tobi/qmd",
|
||||
"description": "mini cli search engine for your docs, knowledge bases, meeting notes, whatever. Tracking current sota approaches while being all local",
|
||||
"language": "TypeScript",
|
||||
"html_url": "https://github.com/tobi/qmd",
|
||||
"license": {"key": "mit", "name": "MIT License", "spdx_id": "MIT"}
|
||||
}
|
||||
```
|
||||
|
||||
Byte-weighted language breakdown (`/languages` endpoint):
|
||||
|
||||
```json
|
||||
{
|
||||
"TypeScript": 1597168,
|
||||
"Python": 200880,
|
||||
"Shell": 26136,
|
||||
"JavaScript": 23132,
|
||||
"Nix": 5984,
|
||||
"Just": 1081,
|
||||
"Dockerfile": 1074
|
||||
}
|
||||
```
|
||||
|
||||
## `package.json` dependencies
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "@tobilu/qmd",
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/server": "2.0.0",
|
||||
"better-sqlite3": "^13.0.3",
|
||||
"fast-glob": "3.3.3",
|
||||
"node-llama-cpp": "3.20.0",
|
||||
"picomatch": "4.0.5",
|
||||
"sqlite-vec": "0.1.9",
|
||||
"tree-sitter-go": "0.25.0",
|
||||
"tree-sitter-python": "0.25.0",
|
||||
"tree-sitter-rust": "0.24.0",
|
||||
"tree-sitter-typescript": "0.23.2",
|
||||
"web-tree-sitter": "0.26.12",
|
||||
"yaml": "2.9.0",
|
||||
"zod": "4.2.1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## README excerpts
|
||||
|
||||
Opening description (README.md, line 5):
|
||||
|
||||
> QMD combines BM25 full-text search, vector semantic search, and LLM re-ranking—all running
|
||||
> locally via node-llama-cpp with GGUF models.
|
||||
|
||||
Install ("Quick Start" section):
|
||||
|
||||
```sh
|
||||
# Install globally (Node or Bun)
|
||||
npm install -g @tobilu/qmd
|
||||
# or
|
||||
bun install -g @tobilu/qmd
|
||||
|
||||
# Or run directly
|
||||
npx @tobilu/qmd ...
|
||||
bunx @tobilu/qmd ...
|
||||
```
|
||||
|
||||
Scoring table (architecture section):
|
||||
|
||||
| Stage | Method | Formula | Range |
|
||||
|---|---|---|---|
|
||||
| FTS (BM25) | SQLite FTS5 BM25 | `Math.abs(score)` | 0 to ~25+ |
|
||||
| Vector | Cosine distance | `1 / (1 + distance)` | 0.0 to 1.0 |
|
||||
| Reranker | LLM 0-10 rating | `score / 10` | 0.0 to 1.0 |
|
||||
|
||||
Diagnostic command comment, confirming `sqlite-vec` is the vector index used at runtime, not
|
||||
only a listed dependency:
|
||||
|
||||
```
|
||||
# Diagnose the install (runtime, sqlite-vec, embedding fingerprints, GPU probe)
|
||||
```
|
||||
|
||||
## Not extracted
|
||||
|
||||
The full README (1301 lines: library API, MCP server usage, tree-sitter code-chunking options,
|
||||
config file reference, CLI subcommand reference) - only the excerpts backing the corrected
|
||||
`qmd.md` claims (language, runtime, install method, search/rerank stack) were pulled. A future
|
||||
qmd page expansion covering its library API or MCP server would need a fresh fetch, not a reuse
|
||||
of this file's `## Not extracted` judgment.
|
||||
+245
@@ -0,0 +1,245 @@
|
||||
# Conversation Transcript - MCP Read Server Implementation Session
|
||||
|
||||
> Source: Claude Code session (`claude-opus-5`), chemenu workspace
|
||||
> Collected: 2026-09-02
|
||||
> Participant: Torben
|
||||
> Fidelity: **faithful summary transcript, not a verbatim log.** Torben's instructions are
|
||||
> quoted verbatim; the assistant's design reasoning, code, and file contents are condensed to
|
||||
> what a later reader needs to find the artifact - the artifacts themselves are the code, not
|
||||
> this transcript. Command outputs shown (test counts, timings, the Mass-Update Gate's printed
|
||||
> file list, gate refusal messages) are real, copied from the session. No credentials appeared.
|
||||
> No subagents were used - all work in this transcript is first-hand.
|
||||
> One of two transcripts cut from this session; the other covers fixing `kb/entities/tools/qmd.md`,
|
||||
> a documentation defect noted but not fixed during this one.
|
||||
|
||||
Covers implementing the four-issue sequence held by #36 (the master issue for "path to the MCP
|
||||
read server"): #34 (arm the Publish-Remote Gate), #33 (harden the read path), #31 (root
|
||||
resolution + library boundary), #19 (the MCP server itself), plus the human-facing
|
||||
`INSTALL-MCP.md` and filing #37 (the container-image follow-up) that #19's closure surfaced as
|
||||
still missing. Four version bumps in sequence: 2.2.3, 2.2.4, 2.3.0, 2.4.0, then 2.4.1 for the
|
||||
documentation follow-up. All five touched issues (#34, #33, #31, #19, #36) got closing comments;
|
||||
#36 was left open pending #37.
|
||||
|
||||
---
|
||||
|
||||
## Turn 1 - `/stack-dev implementiere #36`
|
||||
|
||||
The `stack-dev` skill loaded, switching the session into tool-development rules (ordinary
|
||||
software-engineering judgment on `tools/`, `types/`, `instructions/` - no source-binding, no
|
||||
`raw/` citation needed for code).
|
||||
|
||||
Read issue #36 (the master issue) via `gitea-mcp`. It holds no implementation itself - a
|
||||
sequence table (#34 → #33 → #31 → #19), a table of platform/auth/transport decisions already
|
||||
made and closed to debate, a measured baseline (593 ms per `wikitool search`, broken down:
|
||||
262 ms module import, 274 ms corpus parse, 7 ms ripgrep), ten verified findings backing the
|
||||
design, and an explicit "not in scope" list (Go, deployment details, a write path, #15's
|
||||
research capability). Read #34, #33, #31, #19 in full including comments to get the acceptance
|
||||
criteria and the reasoning behind each.
|
||||
|
||||
Worked the sequence in order, starting a session-scoped `WIKITOOL_SESSION_ID`.
|
||||
|
||||
**#34 - Publish-Remote Gate.** `.wikitool-remotes.json` did not exist in this checkout; absence
|
||||
means unrestricted per `git_publish.read_allowed_push_urls()`. Created it with `origin`'s exact
|
||||
push URL as the sole allowed target. Counter-checked by adding a second git remote to a made-up
|
||||
URL and running `publish --remote gatecheck`: refused with **exit 42**, working tree untouched,
|
||||
before any fetch. Remote removed afterward.
|
||||
|
||||
`doctor`'s `check_publish_remotes()` reported only whether the *file* existed, not whether the
|
||||
gate was actually armed. Rewrote its three outcome messages to lead with `Gate armed:` /
|
||||
`Gate not armed:` explicitly - the single-remote-no-file case stays `OK` (nothing to protect,
|
||||
and a FAIL would make the file mandatory through the back door) but now says outright that every
|
||||
push target passes. The check had **no tests**; added three, one per state.
|
||||
|
||||
Bumped `--patch` → **2.2.3**.
|
||||
|
||||
**#33 - Harden the read path.** Six findings, each addressed with a regression:
|
||||
|
||||
1. *ReDoS.* `search/ripgrep.py:_contains` passed `query.regex` to `re.search`. Deleted the
|
||||
branch entirely rather than bounding it - `rg` already applies the pattern with a linear
|
||||
engine before this function runs, so nothing is lost except the extra title/summary ranking
|
||||
boost for a non-literal pattern (and summary/H1 lines are themselves counted by `rg`).
|
||||
Regression test asserts both the timing (`< 0.5s` against `(\w+\s?)+$`) and the return value,
|
||||
because a bound alone would pass with a merely-faster engine.
|
||||
2. *No subprocess timeout.* Added `RIPGREP_TIMEOUT_SECONDS = 30.0`; `TimeoutExpired` translates
|
||||
to the existing `RipgrepFailed` path.
|
||||
3. *YAML aliases.* Frontmatter has no legitimate use for anchors/aliases, so they are refused
|
||||
outright rather than budgeted, checked on the streaming *event* parse (`yaml.parse`) so the
|
||||
check itself never triggers the expansion it is checking for - `*` is a necessary character
|
||||
in any alias node, so its absence proves absence with zero parse cost. Constructed a
|
||||
reproduction: 267 bytes of nested aliases compose into 672,603 nodes on traversal at
|
||||
constant (0.2 ms) parse time, growth 9^n with nesting depth. Added a 64 KiB frontmatter size
|
||||
limit and a `RecursionError` catch (PyYAML composes recursively; deep nesting is not a
|
||||
`YAMLError`).
|
||||
4. *`CSafeLoader` unused.* Switched to it with a `SafeLoader` fallback. Measured over this
|
||||
corpus (176 pages, best of 5): **265 ms → 54 ms**.
|
||||
5. *Silent frontmatter loss.* Decided: the read path now *reports* rather than swallows.
|
||||
Unparseable YAML still degrades to `{}` for bulk operations, but the reason travels with it
|
||||
(`Page.frontmatter_error`, set by a single parser shared between `read_page()` and
|
||||
`frontmatter_error()` - previously two separate `safe_load` call sites that could describe
|
||||
the same broken file differently). `search --json` now always carries an `unreadable` list
|
||||
of `{path, reason}`; the table form writes the same lines to stderr. Added `read_page_strict()`
|
||||
for the future ingest-quarantine path (#32), which must stop on unparseable input rather than
|
||||
empty it.
|
||||
6. *Corpus reparse per call.* New `chemenu/corpus_cache.py`: a `CorpusCache` object a caller
|
||||
*holds* (not a module-global switch). The CLI holds none and is unaffected. Correctness
|
||||
property, not just speed: **a dirty working tree is never cached** - if git cannot answer
|
||||
whether the tree is clean, it is treated as dirty. `wikitool search` end-to-end (best of 5):
|
||||
**593 ms → 347 ms**.
|
||||
|
||||
Bumped `--patch` → **2.2.4**.
|
||||
|
||||
**#31 - Root resolution + library boundary.** `config.ROOT` and everything derived from it were
|
||||
Python module constants, bound at import time from `Path(__file__).resolve().parents[2]` - so
|
||||
`monkeypatch.setattr(config, "ROOT", tmp_path)` repointed `ROOT` but left `KB_DIR`/`RAW_DIR`
|
||||
aimed at the real checkout, the exact failure class `raw_dir`'s own fixture docstring already
|
||||
warned about one layer up.
|
||||
|
||||
Rewrote `config.py`: `resolve_root()` by precedence (explicit argument → `$CHEMENU_ROOT` →
|
||||
walk-up, the walk-up staying default so `tools/wikitool` is unaffected), and every derived path
|
||||
resolved on *attribute access* via module `__getattr__` (PEP 562) rather than stored - so an
|
||||
assignment onto `ROOT` (test or otherwise) is honored by every path under it, live. This
|
||||
surfaced a subtler bug while fixing the first one: `monkeypatch`'s own undo mechanism reads the
|
||||
old value (which resolves it) and writes it back as a real attribute on teardown, recreating the
|
||||
stale binding the rewrite was meant to eliminate. Added `config.reset()`, called by the autouse
|
||||
hermetic-environment fixture on both setup and teardown.
|
||||
|
||||
Split the CLI-coupled command modules into a pure core + thin adapter, three times over:
|
||||
`search/service.py`, `lint_core.py`, `types_core.py` - none of them import `typer` or `rich`.
|
||||
`commands/search.py`, `commands/lint.py`, `commands/types_cmd.py` became the terminal adapters,
|
||||
re-exporting the same names so no existing import breaks.
|
||||
|
||||
New `chemenu/errors.py`: `ChemenuError` → `ValidationError` (also inherits `ValueError`, since
|
||||
`PredicateError` already was one and callers catch it that way) / `BackendError`.
|
||||
`PredicateError`, `FrontmatterError`, `UnknownBackend`, `RipgrepMissing`, `RipgrepFailed` moved
|
||||
under this hierarchy.
|
||||
|
||||
New `chemenu/api.py`: `Corpus` class, the in-process entry point - takes a root, returns exactly
|
||||
the CLI's `--json` shapes, raises instead of exiting, stamps every response with `commit`/
|
||||
`as_of`. Wrote the acceptance test by monkeypatching `Path.read_text`/`Path.rglob` to fail on any
|
||||
access under the real checkout root while a foreign root is set - this test could not have
|
||||
passed before the lazy-resolution rewrite.
|
||||
|
||||
Two more accidental dependencies surfaced and were fixed: `TypeResolver.repo_root` was also
|
||||
import-bound (fixed the same way, with `config.rooted()` as a process-wide context manager for
|
||||
callers that reach `config` directly rather than taking a root argument - and `use_shipped_type_specs()`
|
||||
added to the test fixtures that had been relying on it silently); and `search/registry.resolve()`
|
||||
did not pass `kb_dir`/`root` through to the backend, so a caller pointing `run_search` at a
|
||||
foreign corpus could still have `RipgrepBackend` read `config.KB_DIR` underneath it.
|
||||
|
||||
Bumped `--minor` → **2.3.0** (new capability, backward-compatible).
|
||||
|
||||
**#19 - MCP read server.** New package `tools/chemenu/mcp/` (`server.py`, `__main__.py`).
|
||||
Installed the `mcp` SDK (`mcp>=2.0`, discovered mid-session that this pulled in the v2 API -
|
||||
`FastMCP` renamed to `MCPServer`, imported from `mcp.server.mcpserver`). Five tools over
|
||||
`chemenu.api.Corpus`: `search`, `types`, `describe_type`, `lint`, `status` (`status` is
|
||||
server-composed, not a wrapper - there is no `wikitool status` command to wrap). No write tool,
|
||||
structurally: neither the server module nor `chemenu.api` imports anything under
|
||||
`chemenu.commands`.
|
||||
|
||||
Both transports built and smoke-tested end-to-end against the real 176-page corpus: `stdio` via
|
||||
a hand-written MCP client script, and `streamable-http` (host/port bound explicitly - the
|
||||
default binds loopback, wrong for a container behind a proxy) via a subprocess + HTTP client
|
||||
round-trip. `sse` deliberately not offered (superseded transport).
|
||||
|
||||
`ChemenuError` translated to the SDK's `ToolError` at the tool-call boundary (a deliberate
|
||||
refusal whose message reaches the caller) rather than left to become an `UnexpectedToolError`
|
||||
(a crash whose message stays server-side).
|
||||
|
||||
Found and fixed a stamping bug while writing the golden test: `_stamp()` was asking the cache for
|
||||
the *current* revision after the load had already happened, so a caller with a perfectly clean
|
||||
tree could see `"commit": null` if the cache's cached revision lagged. Fixed by threading the
|
||||
revision the load actually returned through to the stamp.
|
||||
|
||||
Wrote `tools/chemenu/tests/test_mcp_server.py`: the golden test runs `wikitool ... --json` as a
|
||||
subprocess against the same fixture tree (via `$CHEMENU_ROOT`) and asserts the server's
|
||||
structured output matches field-for-field; a before/after test captures file size+contents,
|
||||
`git rev-parse HEAD`, and `git status --porcelain` around all five tool calls to prove nothing
|
||||
writes; a structural test imports the server module in a fresh interpreter and checks
|
||||
`sys.modules` for absence of `chemenu.commands.*`.
|
||||
|
||||
Added `check_trace_destination()`: the server **refuses to start** if `WIKI_TRACE` is on and
|
||||
would write into the served checkout's `reports/telemetry/` - the directory the sync's
|
||||
`git reset --hard` is entitled to wipe. `WIKI_TRACE=0` or `WIKI_TRACE_DIR` outside the corpus
|
||||
both satisfy it.
|
||||
|
||||
New `instructions/mcp-read-server.md` (agent-facing operating procedure), `tools/requirements-mcp.txt`
|
||||
(the SDK's dependency, kept out of `requirements.txt` so a CLI-only instance need not install
|
||||
pydantic/starlette/uvicorn/cryptography), a CI step to install it (so the golden test cannot
|
||||
silently be skipped), and doc updates (`tools/CONTRACT.md`, `tools/README.md`, `README.md`).
|
||||
|
||||
Bumped `--minor` → **2.4.0**.
|
||||
|
||||
Ran `docs verify`, `instructions verify`, and the full suite (**799 passed**) plus an
|
||||
empty-machine run (`env -i ... pytest`) with the same result, before presenting the changeset.
|
||||
|
||||
`tools/wikitool publish` hit the **Mass-Update Gate**: 37 files, +3,037/-625 lines, exit 42.
|
||||
Reproduced the full file-by-area breakdown verbatim in the reply (as the gate's message
|
||||
requires - the output does not reach the user's screen on its own) and stopped without running
|
||||
further commands, per the gate's instruction and AGENTS.md invariant 6.
|
||||
|
||||
## Turn 2 - "Freigegeben. Erstelle eine install-MCP.md für Menschen. Für traefik middleware verweise auf https://gitea.nehmer.net/torben/gitea-mcp-forward-auth ... Wir brauchen ein issue, der uns dicker Container für ein deployment erzeugt. Fasse dort schon mal zusammen, was du bisher weißt... Die ci scripte in https://gitea.nehmer.net/torben/gitea-mcp dürfte ein guter startpunkt sein."
|
||||
|
||||
Published with the token from the gate's own printed line
|
||||
(`--confirm 46442f4419c1`) - commit `576df2c`.
|
||||
|
||||
Fetched both referenced repos via `gitea-mcp` (`get_repository_tree`, `get_file_contents`) to
|
||||
ground the two follow-up documents in what actually exists rather than in assumption:
|
||||
|
||||
- `gitea-mcp-forward-auth`: a small Go Traefik ForwardAuth service - Bearer-token-vs-SHA-256-hash
|
||||
checking, `AUTH_PROXY_TOKEN_HASHES_DIR`/`AUTH_PROXY_TOKEN_HASHES` config, `/healthz` always
|
||||
open, demo token hashes checked into the repo, a registry-image test script with ephemeral
|
||||
Docker/Podman login.
|
||||
- `gitea-mcp`: its Dockerfile (multi-stage, `CGO_ENABLED=0`, distroless non-root, OCI labels) is
|
||||
a usable pattern, but its release workflow pushes to **DockerHub** (`DOCKER_ORG: gitea`) - it
|
||||
is a fork of the upstream project, so it is *not* a usable registry-push template for this
|
||||
repo. Noted explicitly rather than silently copied.
|
||||
|
||||
Wrote `install-MCP.md` (later renamed, see Turn 3): six numbered steps (install dependency, run
|
||||
stdio, wire a client, run streamable-http, put authentication in front, keep the corpus current
|
||||
via polling), a runnable stdio verification script (executed for real before being written into
|
||||
the doc, output: `Tools: [...]`, `Seiten: 176 | Commit: <sha>`), and a troubleshooting section
|
||||
keyed to the server's actual error messages. Linked it from `INSTALL.md` and `README.md`, and
|
||||
added `CHEMENU_ROOT`/`WIKI_TRACE`/`WIKI_TRACE_DIR` to `INSTALL.md`'s configuration table (both
|
||||
had been in effect since earlier work but undocumented there). Added the file to `dist_cmd.py`'s
|
||||
`ROOT_FILES` allowlist and verified with a real `dist export` that it ships.
|
||||
|
||||
Filed **issue #37** ("Container-Image für den MCP-Leseserver"): summarized what is already fixed
|
||||
(startup command, required env vars, the ripgrep-in-the-image trap a naive `pip install`
|
||||
Dockerfile would miss, where auth/rate-limiting belong) and the concrete templates found above,
|
||||
then nine explicit open decisions (corpus baked into the image vs. mounted as a volume and
|
||||
synced by a sidecar; who runs the sync; base image, since Go-style `distroless` does not carry a
|
||||
Python interpreter or `rg`; how the version reaches the image; whether to build `arm64`;
|
||||
**a healthcheck endpoint does not exist yet - the one item that implies new code in this repo**;
|
||||
registry path; OCI labels; whether a smoke test against the built image is added). Labeled
|
||||
`prio/2 size/M`.
|
||||
|
||||
Closed **#34, #33, #31, #19** with detailed comments each restating what was implemented against
|
||||
the issue's own acceptance criteria, including the two accidental-dependency findings from #31
|
||||
and the corrected alias-bomb numbers. Commented on **#36** with a summary table across all four
|
||||
versions, noted its closing criterion (a consumer provably reaching the server through the
|
||||
Traefik middleware) is not yet met - that needs #37's deployment - and proposed leaving #36 open
|
||||
until then; also carried forward its two remaining loose ends (the wrong `qmd.md` language claim,
|
||||
and the still-missing place for architecture decisions).
|
||||
|
||||
## Turn 3 - "Freigegeben. Nenne die Datei INSTALL-MCP.md all Caps sonst fahre mit dem Auftrag fort" (interrupting a `dist export` verification call)
|
||||
|
||||
Renamed `install-MCP.md` → `INSTALL-MCP.md`, fixed every reference (`INSTALL.md`, `README.md`,
|
||||
`tools/chemenu/commands/dist_cmd.py`). Re-ran the full suite (**799 passed**) and `docs verify`,
|
||||
bumped `--patch` → **2.4.1**, wrote the changelog entry, published (commit `83018fc`). Saved a
|
||||
feedback memory (`root-docs-are-all-caps.md`): root-level human docs in this repo are named in
|
||||
ALL CAPS, and a new one has to be added to `dist_cmd.ROOT_FILES` or it silently does not ship.
|
||||
|
||||
## Outcome
|
||||
|
||||
- **Version:** 2.2.2 -> 2.2.3 -> 2.2.4 -> 2.3.0 -> 2.4.0 -> 2.4.1
|
||||
- **Commits:** `576df2c` (2.4.0, the 37-file changeset cleared through the Mass-Update Gate),
|
||||
`83018fc` (2.4.1, `INSTALL-MCP.md` and its wiring)
|
||||
- **Tests:** 776 -> 786 -> 799 passed, green throughout, including on an `env -i` empty machine
|
||||
- **Measured:** corpus parse 265ms -> 54ms; `wikitool search` end-to-end 593ms -> 347ms
|
||||
- **Issues:** #34, #33, #31, #19 closed with detailed comments; #36 commented, left open pending
|
||||
#37; #37 opened (`prio/2 size/M`)
|
||||
- **CI:** `.gitea/workflows/ci.yml` updated to install `tools/requirements-mcp.txt`, otherwise
|
||||
unchanged; not separately re-run in this session (publish triggers it)
|
||||
- **Not done in this session, carried forward:** #37 itself (container image); #23 (env var
|
||||
registration enforcement - `CHEMENU_ROOT` was added to `_WIKITOOL_ENV` by hand); the `qmd.md`
|
||||
language-claim fix (separate transcript); an ADR-style home for architecture decisions
|
||||
+2
-2
@@ -74,7 +74,7 @@ tools/wikitool <command> --help
|
||||
| `version show [--json]` | Print this instance's stack version and where it came from (development tree, or a distribution with its export date and origin). Bare `wikitool version` is an alias for this. Read-only, offline, and **exempt from the Iteration Budget Gate** |
|
||||
| `version check [--url U] [--timeout S] [--json]` | Ask the origin's release feed whether a newer stack exists, and whether the step crosses a compatibility boundary (`state: current\|update\|migration\|ahead`). **The only command in `wikitool` that makes a network call** - never reached implicitly from another command, needs no key, times out, and reports an unreachable feed as an error rather than as "up to date". The feed is `$WIKITOOL_UPDATE_URL`, else the release stamp's, else the built-in origin; `$WIKITOOL_UPDATE_TOKEN` is only needed if that feed is not readable anonymously. Read-only and exempt from the budget gate |
|
||||
| `version notes [--version X.Y.Z]` | Print one version's `CHANGES.md` entry, for use as release notes (default: this tree's `VERSION`). Read-only and exempt from the budget gate |
|
||||
| `version bump --major\|--minor\|--patch --title "<...>" [--no-migration "<reason>"] [--dry-run]` | Raise `VERSION` and open the matching `CHANGES.md` entry - heading, date and author only; the body stays the author's to write, the way `new` writes frontmatter and leaves the prose. Refuses more or fewer than one part, an empty title, and a changelog already documenting a version that is not older than the new one. Compatibility follows the **leftmost non-zero component**, which for this stack (at `1.0.0` and up, no pre-release suffixes anywhere) means MAJOR: PATCH is a fix, MINOR a compatible capability, MAJOR requires instances to migrate. A MAJOR bump additionally requires a migration document targeting the new version, or `--no-migration "<reason>"`, which records the reason in the entry |
|
||||
| `version bump --major\|--minor\|--patch --title "<...>" [--breaking "<what breaks>"] [--no-migration "<reason>"] [--dry-run]` | Raise `VERSION` and open the matching `CHANGES.md` entry - heading, date and author only; the body stays the author's to write, the way `new` writes frontmatter and leaves the prose. Refuses more or fewer than one part, an empty title, and a changelog already documenting a version that is not older than the new one. Compatibility follows the **leftmost non-zero component**, which for this stack (at `1.0.0` and up, no pre-release suffixes anywhere) means MAJOR: PATCH is a fix, MINOR a compatible capability, MAJOR a version that is **not a drop-in replacement** - any hand-work on update, or a downgrade that no longer works. Whether content must be migrated is a second, independent question. A MAJOR bump therefore requires `--breaking "<what stops working>"`, which is refused on any other part, and on top of it a migration document targeting the new version or `--no-migration "<reason>"`; both are recorded in the entry. Which part a change earns stays a judgment call: the command enforces that a crossing documents itself, never that the part was chosen correctly |
|
||||
| `migrate list [--json]` | List every migration document under `instructions/migrations/`, oldest target first, with its kind. Read-only and **exempt from the Iteration Budget Gate** |
|
||||
| `migrate status [--json]` | Show the migrations this instance still owes, in the order they must run: every document whose `migrates_to` lies in `(kb_version, VERSION]`. Exits 1 only when `.wikitool-kb.json` is missing - the content's shape is a question the tool refuses to answer by guessing. Read-only and exempt from the budget gate |
|
||||
| `migrate verify --from <rev> [--path P ...] [--expect-body-change] [--json] [--fail-on-error]` | Compare `kb/` against a git revision on the invariants a content migration must not change: wikilink and citation **counts** (not sets), footnote definitions, H1, and structural frontmatter. Reports added/removed pages without failing on them. `--expect-body-change` additionally flags a page whose body did not change at all. Not migration-specific - worth running after any bulk rewrite, and the one question `lint` cannot answer, since it reads a single revision and so cannot see that something went missing. Read-only and exempt from the budget gate |
|
||||
@@ -190,7 +190,7 @@ is atomic, and whether a retry is safe.
|
||||
| `dist export` | Target exists and is not empty, is not a directory, or the tree has no readable `VERSION` | Yes - nothing is written until every file is planned | Point `<target>` at an empty (or new) directory and retry. Never merge into a non-empty one by hand |
|
||||
| `version show` / `version notes` | `VERSION` is missing or unparseable; for `notes`, no `CHANGES.md` entry names the version asked for | Read-only | Fix `VERSION`, or write the changelog entry (`version bump` writes its heading). Safe to retry |
|
||||
| `version check` | The feed could not be reached, answered non-JSON, or carried no `tag_name`. **Never** answers "up to date" for a question it could not ask | Read-only, no local writes | A network failure is transient - retry once, then report it. HTTP 401/403 names `$WIKITOOL_UPDATE_TOKEN`; 404 means no release exists yet or the URL points at the wrong repo |
|
||||
| `version bump` | More or fewer than one of `--major/--minor/--patch`, an empty `--title`, a missing `VERSION`/`CHANGES.md`, a changelog already documenting a version not older than the new one, a boundary-crossing bump with neither a migration document nor `--no-migration`, or `--no-migration` on a bump that crosses nothing | No - `VERSION` then `CHANGES.md` | **Not idempotent**: a second run bumps again. If the outcome is uncertain, read `VERSION` and the top of `CHANGES.md` before retrying |
|
||||
| `version bump` | More or fewer than one of `--major/--minor/--patch`, an empty `--title`, a missing `VERSION`/`CHANGES.md`, a changelog already documenting a version not older than the new one, a boundary-crossing bump without `--breaking` or with neither a migration document nor `--no-migration`, or `--breaking`/`--no-migration` on a bump that crosses nothing | No - `VERSION` then `CHANGES.md` | **Not idempotent**: a second run bumps again. If the outcome is uncertain, read `VERSION` and the top of `CHANGES.md` before retrying |
|
||||
| `migrate list` / `migrate status` | `list` never fails; `status` exits 1 when `.wikitool-kb.json` is missing or unreadable, or `VERSION` is | Read-only | For a missing declaration: run `migrate baseline <version>` once, then retry. Safe to retry freely otherwise |
|
||||
| `migrate verify` | Only with `--fail-on-error`: an invariant changed. Also exits 1 if `--from` is not a revision in this repository | Read-only | Exit 1 from `--fail-on-error` means "act on the findings", not "the tool is broken". A finding is never fixed by re-running - it names a page and what changed on it |
|
||||
| `migrate done` | Unknown version, no `.wikitool-kb.json`, nothing outstanding, or a version that is not the next link in the chain | Yes - single file write | **Not idempotent**: it advances the chain. For "not the next link", run `migrate status` and apply them in the order it prints - never force the order |
|
||||
|
||||
@@ -473,6 +473,43 @@ def check_migration_for_boundary() -> list[str]:
|
||||
]
|
||||
|
||||
|
||||
def check_breaking_change_for_boundary() -> list[str]:
|
||||
"""A version that crosses the compatibility boundary must say what breaks.
|
||||
|
||||
Separate from `check_migration_for_boundary`, because the two answer
|
||||
different questions: that one asks whether the *content* has to move, this
|
||||
one whether the operator was told the swap is not drop-in at all. A
|
||||
boundary crossing with an untouched corpus - a renamed feed, artefact,
|
||||
import name or flag - satisfies that check and still leaves every existing
|
||||
instance with something to do by hand.
|
||||
|
||||
Only the newest entry is checked, for the same reason: older crossings are
|
||||
history, and re-reporting them forever would make the check noise.
|
||||
"""
|
||||
changes_path = config.ROOT / version_mod.CHANGES_FILENAME
|
||||
version_path = config.ROOT / version_mod.VERSION_FILENAME
|
||||
if not changes_path.is_file() or not version_path.is_file():
|
||||
return [] # already reported by check_version_changelog
|
||||
|
||||
text = changes_path.read_text(encoding="utf-8")
|
||||
current = version_mod.top_changes_version(text)
|
||||
previous = _second_changes_version(text)
|
||||
if current is None or previous is None:
|
||||
return [] # the first versioned entry has no predecessor to cross from
|
||||
if current.compat_key == previous.compat_key:
|
||||
return []
|
||||
|
||||
if version_mod.BREAKING_CHANGE_MARKER in (version_mod.changes_section(text, current) or ""):
|
||||
return []
|
||||
|
||||
return [
|
||||
f"{current} crosses the compatibility boundary from {previous}, so it is not a drop-in "
|
||||
f"replacement - but its {version_mod.CHANGES_FILENAME} entry carries no "
|
||||
f"`{version_mod.BREAKING_CHANGE_MARKER}` line saying what stops working. Add it "
|
||||
"(`version bump --breaking` writes it; see instructions/dev/version-parts.md)"
|
||||
]
|
||||
|
||||
|
||||
@app.command("verify")
|
||||
def verify():
|
||||
"""Check the CLI/README command tables, contract presence, type-form drift, ignore rules, and version/changelog agreement."""
|
||||
@@ -484,6 +521,7 @@ def verify():
|
||||
+ check_ignored_content()
|
||||
+ check_version_changelog()
|
||||
+ check_migration_for_boundary()
|
||||
+ check_breaking_change_for_boundary()
|
||||
)
|
||||
|
||||
if issues:
|
||||
|
||||
@@ -189,6 +189,11 @@ def bump_command(
|
||||
minor: bool = typer.Option(False, "--minor", help="Bump MINOR (resets PATCH)"),
|
||||
patch: bool = typer.Option(False, "--patch", help="Bump PATCH"),
|
||||
title: str = typer.Option(..., "--title", help="One-line title for the new CHANGES.md entry"),
|
||||
breaking: Optional[str] = typer.Option(
|
||||
None,
|
||||
"--breaking",
|
||||
help="What stops working, for a boundary-crossing bump (recorded in CHANGES.md). Required on one, refused on any other",
|
||||
),
|
||||
no_migration: Optional[str] = typer.Option(
|
||||
None,
|
||||
"--no-migration",
|
||||
@@ -203,10 +208,14 @@ def bump_command(
|
||||
frontmatter and leaves the prose. `docs verify` afterwards enforces that
|
||||
the two agree, so a bump with no entry cannot reach a release.
|
||||
|
||||
A bump that crosses the compatibility boundary additionally requires a
|
||||
migration document for the new version, or `--no-migration "<reason>"`.
|
||||
An instance learning that it must migrate, with nothing telling it how, is
|
||||
the gap this closes."""
|
||||
A bump that crosses the compatibility boundary - one whose new version is
|
||||
not a drop-in replacement, whether or not any content moves - requires
|
||||
`--breaking "<what stops working>"`, and on top of that either a migration
|
||||
document for the new version or `--no-migration "<reason>"`. An instance
|
||||
learning that it must migrate, with nothing telling it what broke or how to
|
||||
cross, is the gap these close. Which part to pass stays a judgment call
|
||||
this command does not make - it enforces only that a crossing says what it
|
||||
costs."""
|
||||
selected = [name for name, chosen in (("major", major), ("minor", minor), ("patch", patch)) if chosen]
|
||||
if len(selected) != 1:
|
||||
fail("Pass exactly one of --major / --minor / --patch")
|
||||
@@ -239,6 +248,23 @@ def bump_command(
|
||||
crossing = new_version.compat_key != current.compat_key
|
||||
boundary = " (crosses a compatibility boundary - instances must migrate)" if crossing else ""
|
||||
|
||||
if crossing and not breaking:
|
||||
fail(
|
||||
f"{current} -> {new_version} crosses the compatibility boundary, so it is not a "
|
||||
f"drop-in replacement - re-run with --breaking \"<what stops working, and what an "
|
||||
f"instance must do about it>\".\n"
|
||||
f"If that sentence is hard to write because nothing actually breaks - no hand-work "
|
||||
f"on update, and the old version can still be put back - then the bump is probably "
|
||||
f"not --{selected[0]}."
|
||||
)
|
||||
return
|
||||
if breaking and not crossing:
|
||||
fail(
|
||||
f"--breaking only applies to a bump that crosses the compatibility boundary; "
|
||||
f"{current} -> {new_version} does not."
|
||||
)
|
||||
return
|
||||
|
||||
if crossing and not no_migration:
|
||||
from chemenu import kb_state
|
||||
|
||||
@@ -267,6 +293,7 @@ def bump_command(
|
||||
version_mod.insert_changes_entry(
|
||||
text, new_version, today_iso(), title.strip(), author,
|
||||
no_migration_reason=no_migration.strip() if no_migration else None,
|
||||
breaking_reason=breaking.strip() if breaking else None,
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
@@ -237,6 +237,43 @@ def test_a_migration_document_satisfies_the_check(tmp_path, monkeypatch):
|
||||
assert docs_verify.check_migration_for_boundary() == []
|
||||
|
||||
|
||||
def test_a_breaking_release_without_a_breaking_note_is_reported(tmp_path, monkeypatch):
|
||||
"""A crossing that migrates nothing still leaves hand-work behind, so the
|
||||
migration check passing is not evidence that anyone was told."""
|
||||
from chemenu import version as version_mod
|
||||
|
||||
_boundary_tree(
|
||||
tmp_path, monkeypatch, "2.0.0", "1.4.0",
|
||||
marker=f"{version_mod.MIGRATION_NONE_MARKER} - nothing to change.\n\n",
|
||||
)
|
||||
assert docs_verify.check_migration_for_boundary() == []
|
||||
issues = docs_verify.check_breaking_change_for_boundary()
|
||||
assert any("2.0.0" in issue and "drop-in" in issue for issue in issues)
|
||||
|
||||
|
||||
def test_a_compatible_release_needs_no_breaking_note(tmp_path, monkeypatch):
|
||||
_boundary_tree(tmp_path, monkeypatch, "1.5.0", "1.4.0")
|
||||
assert docs_verify.check_breaking_change_for_boundary() == []
|
||||
|
||||
|
||||
def test_a_breaking_change_marker_satisfies_the_check(tmp_path, monkeypatch):
|
||||
from chemenu import version as version_mod
|
||||
|
||||
_boundary_tree(
|
||||
tmp_path, monkeypatch, "2.0.0", "1.4.0",
|
||||
marker=f"{version_mod.BREAKING_CHANGE_MARKER} the feed moved.\n\n",
|
||||
)
|
||||
assert docs_verify.check_breaking_change_for_boundary() == []
|
||||
|
||||
|
||||
def test_verify_raises_when_a_boundary_has_no_breaking_note(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
docs_verify, "check_breaking_change_for_boundary", lambda: ["unannounced"]
|
||||
)
|
||||
with pytest.raises(typer.Exit):
|
||||
docs_verify.verify()
|
||||
|
||||
|
||||
def test_verify_raises_when_a_boundary_has_no_migration(monkeypatch):
|
||||
monkeypatch.setattr(docs_verify, "check_migration_for_boundary", lambda: ["unbridged"])
|
||||
with pytest.raises(typer.Exit):
|
||||
|
||||
@@ -183,7 +183,7 @@ def test_insert_changes_entry_lands_above_the_newest_entry():
|
||||
def test_bump_writes_both_the_version_and_the_changelog_heading(tree):
|
||||
version_cmd.bump_command(
|
||||
major=False, minor=True, patch=False, title="Something happened",
|
||||
no_migration=None, dry_run=False,
|
||||
breaking=None, no_migration=None, dry_run=False,
|
||||
)
|
||||
assert (tree / "VERSION").read_text(encoding="utf-8").strip() == "1.1.0"
|
||||
changes = (tree / "CHANGES.md").read_text(encoding="utf-8")
|
||||
@@ -194,7 +194,7 @@ def test_bump_writes_both_the_version_and_the_changelog_heading(tree):
|
||||
|
||||
def test_bump_dry_run_writes_nothing(tree):
|
||||
version_cmd.bump_command(
|
||||
major=False, minor=False, patch=True, title="Nope", no_migration=None, dry_run=True
|
||||
major=False, minor=False, patch=True, title="Nope", breaking=None, no_migration=None, dry_run=True
|
||||
)
|
||||
assert (tree / "VERSION").read_text(encoding="utf-8").strip() == "1.0.0"
|
||||
assert "1.0.1" not in (tree / "CHANGES.md").read_text(encoding="utf-8")
|
||||
@@ -207,7 +207,7 @@ def test_bump_demands_exactly_one_part(tree, flags):
|
||||
major, minor, patch = flags
|
||||
with pytest.raises(typer.Exit):
|
||||
version_cmd.bump_command(
|
||||
major=major, minor=minor, patch=patch, title="x", no_migration=None, dry_run=False
|
||||
major=major, minor=minor, patch=patch, title="x", breaking=None, no_migration=None, dry_run=False
|
||||
)
|
||||
assert (tree / "VERSION").read_text(encoding="utf-8").strip() == "1.0.0"
|
||||
|
||||
@@ -215,7 +215,7 @@ def test_bump_demands_exactly_one_part(tree, flags):
|
||||
def test_bump_refuses_an_empty_title(tree):
|
||||
with pytest.raises(typer.Exit):
|
||||
version_cmd.bump_command(
|
||||
major=False, minor=False, patch=True, title=" ", no_migration=None, dry_run=False
|
||||
major=False, minor=False, patch=True, title=" ", breaking=None, no_migration=None, dry_run=False
|
||||
)
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@ def test_bump_refuses_when_the_changelog_is_already_ahead(tree):
|
||||
)
|
||||
with pytest.raises(typer.Exit):
|
||||
version_cmd.bump_command(
|
||||
major=False, minor=False, patch=True, title="x", no_migration=None, dry_run=False
|
||||
major=False, minor=False, patch=True, title="x", breaking=None, no_migration=None, dry_run=False
|
||||
)
|
||||
assert (tree / "VERSION").read_text(encoding="utf-8").strip() == "1.0.0"
|
||||
|
||||
@@ -241,7 +241,7 @@ def test_a_boundary_crossing_bump_without_a_migration_is_refused(tree):
|
||||
with pytest.raises(typer.Exit):
|
||||
version_cmd.bump_command(
|
||||
major=True, minor=False, patch=False, title="Breaking",
|
||||
no_migration=None, dry_run=False,
|
||||
breaking="the feed moved", no_migration=None, dry_run=False,
|
||||
)
|
||||
assert (tree / "VERSION").read_text(encoding="utf-8").strip() == "1.0.0"
|
||||
|
||||
@@ -255,7 +255,8 @@ def test_a_boundary_crossing_bump_passes_with_a_migration_document(tree):
|
||||
encoding="utf-8",
|
||||
)
|
||||
version_cmd.bump_command(
|
||||
major=True, minor=False, patch=False, title="Breaking", no_migration=None, dry_run=False
|
||||
major=True, minor=False, patch=False, title="Breaking",
|
||||
breaking="every page is retyped", no_migration=None, dry_run=False,
|
||||
)
|
||||
assert (tree / "VERSION").read_text(encoding="utf-8").strip() == "2.0.0"
|
||||
|
||||
@@ -263,6 +264,7 @@ def test_a_boundary_crossing_bump_passes_with_a_migration_document(tree):
|
||||
def test_no_migration_records_the_reason_in_the_changelog(tree):
|
||||
version_cmd.bump_command(
|
||||
major=True, minor=False, patch=False, title="Breaking",
|
||||
breaking="the release feed moved",
|
||||
no_migration="no distributed instance exists yet", dry_run=False,
|
||||
)
|
||||
changes = (tree / "CHANGES.md").read_text(encoding="utf-8")
|
||||
@@ -275,10 +277,50 @@ def test_no_migration_is_refused_on_a_compatible_bump(tree):
|
||||
with pytest.raises(typer.Exit):
|
||||
version_cmd.bump_command(
|
||||
major=False, minor=False, patch=True, title="Fix",
|
||||
no_migration="not needed", dry_run=False,
|
||||
breaking=None, no_migration="not needed", dry_run=False,
|
||||
)
|
||||
|
||||
|
||||
# --- version bump: the breaking-change note --------------------------------
|
||||
|
||||
|
||||
def test_a_boundary_crossing_bump_without_breaking_is_refused(tree):
|
||||
"""The corpus question and the drop-in question are independent: a bump
|
||||
can migrate nothing and still leave every instance with hand-work."""
|
||||
with pytest.raises(typer.Exit):
|
||||
version_cmd.bump_command(
|
||||
major=True, minor=False, patch=False, title="Renamed the feed",
|
||||
breaking=None, no_migration="kb/ keeps its shape", dry_run=False,
|
||||
)
|
||||
assert (tree / "VERSION").read_text(encoding="utf-8").strip() == "1.0.0"
|
||||
|
||||
|
||||
def test_breaking_records_what_stops_working_in_the_changelog(tree):
|
||||
version_cmd.bump_command(
|
||||
major=True, minor=False, patch=False, title="Renamed the feed",
|
||||
breaking="update_url points at a repo path that no longer exists",
|
||||
no_migration="kb/ keeps its shape", dry_run=False,
|
||||
)
|
||||
changes = (tree / "CHANGES.md").read_text(encoding="utf-8")
|
||||
assert version_mod.BREAKING_CHANGE_MARKER in changes
|
||||
assert "update_url points at a repo path that no longer exists" in changes
|
||||
# The break comes before the migration note: it is what an operator acts on.
|
||||
assert changes.index(version_mod.BREAKING_CHANGE_MARKER) < changes.index(
|
||||
version_mod.MIGRATION_NONE_MARKER
|
||||
)
|
||||
|
||||
|
||||
def test_breaking_is_refused_on_a_compatible_bump(tree):
|
||||
"""A compatible bump that claims a break is describing itself wrongly -
|
||||
one of the two is a mistake, and the command will not guess which."""
|
||||
with pytest.raises(typer.Exit):
|
||||
version_cmd.bump_command(
|
||||
major=False, minor=True, patch=False, title="New command",
|
||||
breaking="nothing, really", no_migration=None, dry_run=False,
|
||||
)
|
||||
assert (tree / "VERSION").read_text(encoding="utf-8").strip() == "1.0.0"
|
||||
|
||||
|
||||
# --- version notes ---------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
@@ -10,11 +10,23 @@ ingest into a release.
|
||||
|
||||
**Compatibility is read off the leftmost non-zero component**, the rule Cargo's
|
||||
caret ranges use: `0.1.3 -> 0.1.4` is safe, `0.1.3 -> 0.2.0` is not, and from
|
||||
`1.0.0` on the same rule reads as the familiar "MAJOR means migration". Stating
|
||||
it that way is what lets the 0.x era carry the migration signal at all - under
|
||||
plain "MAJOR breaks" semantics every 0.x release would be indistinguishable
|
||||
from every other, which is exactly the signal update detection needs. Nothing
|
||||
about the mechanism changes at 1.0.0.
|
||||
`1.0.0` on the same rule reads as the familiar "MAJOR breaks". Stating it that
|
||||
way is what lets the 0.x era carry the signal at all - under a rule keyed to
|
||||
the MAJOR component alone, every 0.x release would be indistinguishable from
|
||||
every other, which is exactly the signal update detection needs. Nothing about
|
||||
the mechanism changes at 1.0.0.
|
||||
|
||||
What that component answers is **whether the new version is a drop-in
|
||||
replacement**: whether an instance can copy the new machinery over itself with
|
||||
no hand-work and still put the old version back afterwards. Whether *content*
|
||||
must be migrated is a **second, independent question**. It is one way to fail
|
||||
the first - but a renamed release feed, artefact, import name, flag or envvar
|
||||
fails it too, with `kb/` untouched, which is why `--no-migration` exists at all:
|
||||
boundary-crossing bumps that migrate nothing are a real case, not an escape
|
||||
hatch. Hence two markers below rather than one - `BREAKING_CHANGE_MARKER`
|
||||
records the break, `MIGRATION_NONE_MARKER` records the absence of the
|
||||
migration. Which part a change earns stays a judgment call made before the
|
||||
bump; this module only enforces that a crossing says what it costs.
|
||||
|
||||
Paths are resolved through `config.ROOT` at call time rather than at import,
|
||||
because the tests (and `dist export`'s own fixtures) relocate the root.
|
||||
@@ -64,6 +76,11 @@ _SEMVER_RE = re.compile(r"^\s*v?(\d+)\.(\d+)\.(\d+)\s*$")
|
||||
# boundary that needs no content migration. `docs verify` accepts it in place
|
||||
# of a migration document, so the exact string is a contract between the two.
|
||||
MIGRATION_NONE_MARKER = "**Migration:** none required"
|
||||
# Written into every CHANGES.md entry whose version crosses a compatibility
|
||||
# boundary, migration or not: the swap is not drop-in, and the operator of an
|
||||
# existing instance has to be told what stops working. `docs verify` checks the
|
||||
# newest crossing carries it, so this string too is a contract between the two.
|
||||
BREAKING_CHANGE_MARKER = "**Breaking Change:**"
|
||||
# A changelog entry that names a version. Entries predating versioning start
|
||||
# with a date instead and are deliberately not matched - they are history, not
|
||||
# a claim about which version the tree is.
|
||||
@@ -332,15 +349,22 @@ def insert_changes_entry(
|
||||
title: str,
|
||||
author: str,
|
||||
no_migration_reason: Optional[str] = None,
|
||||
breaking_reason: Optional[str] = None,
|
||||
) -> str:
|
||||
"""Add a heading for `version` above the newest existing entry.
|
||||
|
||||
Only the skeleton: heading, date, author, and - when a compatibility
|
||||
boundary is crossed without a migration - the line that says so. The
|
||||
entry's actual content is written afterwards by whoever made the change,
|
||||
which is also why `bump` refuses to invent a title.
|
||||
boundary is crossed - the line saying what breaks, plus the line saying no
|
||||
content has to change where that applies. The entry's actual content is
|
||||
written afterwards by whoever made the change, which is also why `bump`
|
||||
refuses to invent a title.
|
||||
|
||||
The break comes first: it is what an operator reading the release notes has
|
||||
to act on, and the migration line only qualifies it.
|
||||
"""
|
||||
lines = [f"## {version} - {date} - {title}", "", f"**Author:** {author}", ""]
|
||||
if breaking_reason:
|
||||
lines += [f"{BREAKING_CHANGE_MARKER} {breaking_reason}", ""]
|
||||
if no_migration_reason:
|
||||
lines += [f"{MIGRATION_NONE_MARKER} - {no_migration_reason}", ""]
|
||||
entry = "\n".join(lines) + "\n---\n\n"
|
||||
|
||||
Reference in New Issue
Block a user