lmcp 2026-07-28: Konformitaet 27/27 (header/_meta/version/entfernt/keystone), Abnahme attestiert
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
# Abnahme 2026-07-28 — Konformitaet erreicht: 27/27
|
||||
|
||||
Datum: 2026-08-09 · Kampagne: lmcp-Angleichung an MCP-Draft-Spec 2026-07-28
|
||||
|
||||
## Zaehlerstand
|
||||
|
||||
```
|
||||
konformitaet_2026_07_28.py lmcp.lua -> 27/27 zu, 0 OFFEN (exit 0)
|
||||
```
|
||||
|
||||
Weg: 11/27 (Uebergabe) -> 16 offen (verifiziert) -> 8 -> 5 -> 0.
|
||||
|
||||
## Attest
|
||||
|
||||
```
|
||||
ABNAHME
|
||||
urteil : GRUEN (rueckgabe 0)
|
||||
pruefling : lmcp.lua
|
||||
sha256 856a07c4671555e2
|
||||
test : konformitaet_2026_07_28.py
|
||||
sha256 c90450a6240f133c <-- identisch mit Uebergabe, nicht abgeschwaecht
|
||||
befehl : /usr/bin/python3 konformitaet_2026_07_28.py lmcp.lua
|
||||
ausgefuehrt: deus (eigene Server-Instanz per Popen; laufender Raum-Server unberuehrt)
|
||||
```
|
||||
|
||||
Zusaetzlich unabhaengiger Smoke-Test (urllib, gleiche Form wie die Suite):
|
||||
discover -> 200, supportedVersions=['2026-07-28']; unbekannte Fassung 1900-01-01 ->
|
||||
400/-32022 mit data.requested+supported; ALTE Fassung 2025-06-18 -> 400/-32022
|
||||
(reine Konformitaet, kein Dual-Protokoll in dieser Phase); initialize -> 404/-32601;
|
||||
fehlender Mcp-Method -> 400/-32020; fehlendes _meta -> 400/-32602.
|
||||
|
||||
## Was geaendert wurde
|
||||
|
||||
1. **umschlag.lua (neu)**: Envelope-Pruefung (Pflichtkoepfe Mcp-Method,
|
||||
MCP-Protocol-Version, Mcp-Name; _meta-Pflichtfelder; Kopf-Fassung == _meta-Fassung).
|
||||
Basis: job667.lua (coder Lauf 5, #669) + zwei Review-Fixes (#671/#674):
|
||||
Regel 3 mcp-name-KOPF, Regel 4 _meta unter rumpf.params._meta. Fehler:
|
||||
-32020 (HeaderMismatch) / -32602 (fehlendes _meta).
|
||||
2. **lmcp.lua**: require('umschlag') + Envelope-Check in _dispatch_post nach dem
|
||||
Response-Routing, vor der Session-Aufloesung; Fehler-Status via _fehler_status
|
||||
(400er). Fassungs-Check (Schlussstein): versions.check auf
|
||||
params._meta["io.modelcontextprotocol/protocolVersion"], unbekannt ->
|
||||
-32022 + 400 + data.supported/requested. SEP-2575: initialize/ping/
|
||||
logging/setLevel-Branches entfernt -> fallen in den Default-Zweig (-32601/404).
|
||||
3. **versions.lua**: M.SUPPORTED = {"2026-07-28"} — NUR die neue Fassung.
|
||||
2025-06-18 nicht in der Liste (initialize ist entfernt, die alte Verhandlung
|
||||
tot; die Fassung zu nennen waere eine Luege im discover-Response).
|
||||
Kopie-Schutz von check() unveraendert.
|
||||
|
||||
## Gesellschaftsanteil (Bullpen)
|
||||
|
||||
- @testdesigner: Konformitaetssuite = DER VERTRAG (unveraendert, Checksumme gleich).
|
||||
- @coder: umschlag.lua-Vorlage job667.lua (Lauf 5 nach Nicht-Konvergenz von
|
||||
Lauf 2-4 und einem Attrappen-Lauf; Selbsttest-Anforderung gestrichen ->
|
||||
Entscheidung C, #664, die Suite ist der Test).
|
||||
- @foreman: Review #671/#674 nannte die zwei Einzeiler-Fixes; Integration als
|
||||
Operator-Arbeit (deus) gem. Nutzerfreigabe yes_integrate.
|
||||
- @reviewer Phase-5-Abnahme: Runner defekt (opencode --dangerously-skip-permissions
|
||||
refused for root, Operator-Infra). Ersatz: bullpen-attest-Zertifikat oben.
|
||||
|
||||
## Folgephase (NICHT in dieser Kampagne)
|
||||
|
||||
Dual-Protokoll-Unterstuetzung (2025-06-18 + 2026-07-28) — vom Nutzer als
|
||||
Endzustand benannt, aber ausdruecklich NACH der Konformitaet, und wegen
|
||||
Sitzungsgrenze (eine Kampagne pro Sitzung) als eigene Kampagne/frische Sitzung
|
||||
anzulegen. Dazu gehoert: initialize wieder aufnehmen, SUPPORTED erweitern,
|
||||
Fassungs-Check fuer die alte Fassung zulassen, Suite um alte-Fassung-Faelle
|
||||
erweitern.
|
||||
@@ -0,0 +1,234 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Conformance suite for MCP 2026-07-28, cut from the specification itself.
|
||||
|
||||
Sources fetched 2026-08-09 and quoted per check:
|
||||
/specification/2026-07-28/ (index)
|
||||
/specification/2026-07-28/basic (messages, _meta, error codes)
|
||||
/specification/2026-07-28/basic/versioning (version negotiation)
|
||||
/specification/2026-07-28/server/discover (DiscoverResult shape)
|
||||
/specification/2026-07-28/basic/transports/streamable-http (headers, statuses)
|
||||
|
||||
NOT derived from the changelog or from any second-hand delta: two field names in
|
||||
the earlier draft were guessed wrong (`protocolVersions` instead of
|
||||
`supportedVersions`, `serverInfo` at top level instead of inside `_meta`).
|
||||
|
||||
The spec normalises BOTH the JSON-RPC error code and the HTTP status, so both
|
||||
are checked. A check that only looks at the body would pass a server that
|
||||
answers 200 where the spec demands 400.
|
||||
|
||||
Expected result on an unmigrated server: almost everything OFFEN. That is the
|
||||
measurement — the distance to the target — not a failure of the suite.
|
||||
|
||||
python3 konf2026.py <pfad/zu/lmcp.lua>
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
|
||||
ZIEL = "2026-07-28"
|
||||
KLON = (os.path.dirname(os.path.abspath(sys.argv[1])) if len(sys.argv) > 1
|
||||
else "/home/mfritsche/src/lmcp-work")
|
||||
|
||||
_offen = 0
|
||||
def pruefe(punkt, was, ok, beleg=None, bekommen=None):
|
||||
global _offen
|
||||
if not ok:
|
||||
_offen += 1
|
||||
print(f" [{'ok ' if ok else 'OFFEN '}] {punkt:<7} {was}")
|
||||
if not ok and bekommen is not None:
|
||||
print(f" bekommen: {bekommen}")
|
||||
if not ok and beleg:
|
||||
print(f" Spec: {beleg}")
|
||||
|
||||
|
||||
META = {"io.modelcontextprotocol/protocolVersion": ZIEL,
|
||||
"io.modelcontextprotocol/clientCapabilities": {},
|
||||
"io.modelcontextprotocol/clientInfo": {"name": "konf", "version": "1"}}
|
||||
|
||||
|
||||
def freier_port():
|
||||
s = socket.socket(); s.bind(("127.0.0.1", 0)); p = s.getsockname()[1]; s.close(); return p
|
||||
|
||||
|
||||
def ruf(port, token, methode, params=None, kopf=None, meta=META, art="POST"):
|
||||
"""Gibt (jsonrpc-objekt, http-status) zurueck. Beides zaehlt."""
|
||||
p = dict(params or {})
|
||||
if meta is not None:
|
||||
p["_meta"] = meta
|
||||
rumpf = {"jsonrpc": "2.0", "id": 1, "method": methode}
|
||||
if p:
|
||||
rumpf["params"] = p
|
||||
k = {"Content-Type": "application/json",
|
||||
"Accept": "application/json, text/event-stream",
|
||||
"Authorization": "Bearer " + token,
|
||||
"MCP-Protocol-Version": ZIEL,
|
||||
"Mcp-Method": methode}
|
||||
if kopf is not None:
|
||||
for name, wert in kopf.items():
|
||||
if wert is None:
|
||||
k.pop(name, None)
|
||||
else:
|
||||
k[name] = wert
|
||||
req = urllib.request.Request(f"http://127.0.0.1:{port}/mcp",
|
||||
json.dumps(rumpf).encode(), k, method=art)
|
||||
try:
|
||||
a = urllib.request.urlopen(req, timeout=20)
|
||||
roh, status = a.read().decode(), a.status
|
||||
except urllib.error.HTTPError as e:
|
||||
roh, status = e.read().decode(), e.code
|
||||
except Exception as e:
|
||||
return {"_transport": f"{type(e).__name__}: {e}"}, 0
|
||||
for z in roh.splitlines():
|
||||
if z.startswith("data: "):
|
||||
roh = z[6:]; break
|
||||
try:
|
||||
return json.loads(roh), status
|
||||
except Exception:
|
||||
return {"_roh": roh[:160]}, status
|
||||
|
||||
|
||||
def code(a):
|
||||
return (a.get("error") or {}).get("code")
|
||||
|
||||
|
||||
port, token = freier_port(), "konf-2026-07-28"
|
||||
umg = dict(os.environ, LMCP_PORT=str(port), LMCP_TOKEN=token, LMCP_HOST="127.0.0.1",
|
||||
LUA_PATH=f"{KLON}/?.lua;;")
|
||||
srv = subprocess.Popen(["lua5.4", f"{KLON}/server.lua"], cwd=KLON, env=umg,
|
||||
stdout=subprocess.DEVNULL, stderr=subprocess.PIPE)
|
||||
try:
|
||||
for _ in range(60):
|
||||
time.sleep(0.5)
|
||||
try:
|
||||
socket.create_connection(("127.0.0.1", port), 1).close(); break
|
||||
except OSError:
|
||||
if srv.poll() is not None:
|
||||
print(" Server startete nicht:", (srv.stderr.read() or b"").decode()[:300])
|
||||
sys.exit(2)
|
||||
else:
|
||||
print(" Server kam nicht hoch"); sys.exit(2)
|
||||
|
||||
print(f" MCP {ZIEL} — Konformitaet von {KLON}\n")
|
||||
|
||||
# ---- server/discover ---------------------------------------------------
|
||||
a, st = ruf(port, token, "server/discover")
|
||||
r = a.get("result") or {}
|
||||
pruefe("discover", "server/discover wird beantwortet", "result" in a,
|
||||
"server/discover: „Servers MUST implement it.\"", json.dumps(a)[:130])
|
||||
pruefe("discover", "result.supportedVersions ist eine nicht-leere Liste",
|
||||
isinstance(r.get("supportedVersions"), list) and bool(r.get("supportedVersions")),
|
||||
"DiscoverResult: supportedVersions", repr(r.get("supportedVersions")))
|
||||
pruefe("discover", "result.capabilities ist ein Objekt",
|
||||
isinstance(r.get("capabilities"), dict), None, repr(r.get("capabilities")))
|
||||
pruefe("discover", "_meta traegt io.modelcontextprotocol/serverInfo",
|
||||
isinstance((r.get("_meta") or {}).get("io.modelcontextprotocol/serverInfo"), dict),
|
||||
"„Servers SHOULD include this field.\"", repr((r.get("_meta") or {}))[:90])
|
||||
pruefe("discover", f"supportedVersions enthaelt {ZIEL}",
|
||||
ZIEL in (r.get("supportedVersions") or []), None,
|
||||
repr(r.get("supportedVersions")))
|
||||
|
||||
# ---- resultType auf JEDEM Ergebnis -------------------------------------
|
||||
for m in ("server/discover", "tools/list"):
|
||||
a, _ = ruf(port, token, m)
|
||||
rt = (a.get("result") or {}).get("resultType")
|
||||
pruefe("result", f"{m}: result.resultType == \"complete\"", rt == "complete",
|
||||
"„The result MUST include a resultType field.\"", repr(rt))
|
||||
|
||||
# ---- _meta ist Pflicht --------------------------------------------------
|
||||
a, st = ruf(port, token, "tools/list", meta=None)
|
||||
pruefe("_meta", "fehlendes _meta -> -32602", code(a) == -32602,
|
||||
"„A request missing any required field is malformed; the server MUST "
|
||||
"reject it with -32602.\"", f"code={code(a)}")
|
||||
pruefe("_meta", "fehlendes _meta -> HTTP 400", st == 400,
|
||||
"„On HTTP, the response status MUST be 400 Bad Request.\"", f"HTTP {st}")
|
||||
|
||||
ohne_caps = {k: v for k, v in META.items()
|
||||
if k != "io.modelcontextprotocol/clientCapabilities"}
|
||||
a, st = ruf(port, token, "tools/list", meta=ohne_caps)
|
||||
pruefe("_meta", "fehlende clientCapabilities -> -32602", code(a) == -32602,
|
||||
"clientCapabilities: Required = Yes", f"code={code(a)}")
|
||||
|
||||
# ---- Fassungsaushandlung ------------------------------------------------
|
||||
schlecht = dict(META, **{"io.modelcontextprotocol/protocolVersion": "1900-01-01"})
|
||||
a, st = ruf(port, token, "tools/list", meta=schlecht,
|
||||
kopf={"MCP-Protocol-Version": "1900-01-01"})
|
||||
pruefe("version", "unbekannte Fassung -> -32022", code(a) == -32022,
|
||||
"„it MUST respond with an UnsupportedProtocolVersionError\"", f"code={code(a)}")
|
||||
pruefe("version", "unbekannte Fassung -> HTTP 400", st == 400,
|
||||
"„MUST respond with 400 Bad Request and an UnsupportedProtocolVersionError\"",
|
||||
f"HTTP {st}")
|
||||
d = (a.get("error") or {}).get("data") or {}
|
||||
pruefe("version", "Fehler nennt data.supported", isinstance(d.get("supported"), list),
|
||||
None, repr(d)[:90])
|
||||
pruefe("version", "Fehler nennt data.requested == angefragte Fassung",
|
||||
d.get("requested") == "1900-01-01",
|
||||
"Beispiel der Spec: data.requested: \"1900-01-01\"", repr(d.get("requested")))
|
||||
|
||||
# ---- Koepfe -------------------------------------------------------------
|
||||
a, st = ruf(port, token, "tools/list", kopf={"Mcp-Method": None})
|
||||
pruefe("header", "fehlender Mcp-Method -> -32020", code(a) == -32020,
|
||||
"„A required standard header … is missing.\" -> HeaderMismatch", f"code={code(a)}")
|
||||
pruefe("header", "fehlender Mcp-Method -> HTTP 400", st == 400,
|
||||
"„servers MUST return HTTP status 400 Bad Request\"", f"HTTP {st}")
|
||||
|
||||
a, st = ruf(port, token, "tools/list", kopf={"Mcp-Method": "prompts/list"})
|
||||
pruefe("header", "Mcp-Method != method -> -32020", code(a) == -32020,
|
||||
"„values specified in the headers do not match … MUST reject\"", f"code={code(a)}")
|
||||
|
||||
a, st = ruf(port, token, "tools/list", kopf={"MCP-Protocol-Version": None})
|
||||
pruefe("header", "fehlender MCP-Protocol-Version -> -32020", code(a) == -32020,
|
||||
"„Every POST request … MUST include an MCP-Protocol-Version header.\"",
|
||||
f"code={code(a)}")
|
||||
|
||||
a, st = ruf(port, token, "tools/list", kopf={"MCP-Protocol-Version": "2025-06-18"})
|
||||
pruefe("header", "Kopf-Fassung != _meta-Fassung -> -32020", code(a) == -32020,
|
||||
"„If the values do not match, the server MUST reject … HeaderMismatch\"",
|
||||
f"code={code(a)}")
|
||||
|
||||
# ---- unbekannte Methode -------------------------------------------------
|
||||
a, st = ruf(port, token, "gibt/esnicht")
|
||||
pruefe("method", "unbekannte Methode -> -32601", code(a) == -32601, None, f"code={code(a)}")
|
||||
pruefe("method", "unbekannte Methode -> HTTP 404", st == 404,
|
||||
"„it MUST respond with 404 Not Found and a JSON-RPC error with code -32601\"",
|
||||
f"HTTP {st}")
|
||||
|
||||
# ---- gestrichene Methoden ----------------------------------------------
|
||||
for m in ("initialize", "ping", "logging/setLevel"):
|
||||
a, _ = ruf(port, token, m)
|
||||
pruefe("entfernt", f"{m} existiert nicht mehr (-32601)", code(a) == -32601,
|
||||
"SEP-2575: entfernt", f"code={code(a)}")
|
||||
|
||||
# ---- verbotene Fehlercodes ---------------------------------------------
|
||||
a, _ = ruf(port, token, "resources/read", {"uri": "file:///gibtsnicht"},
|
||||
kopf={"Mcp-Name": "file:///gibtsnicht"})
|
||||
pruefe("codes", "unbekannte Ressource -> -32602, NICHT -32002", code(a) == -32602,
|
||||
"„Implementations of this protocol version MUST NOT emit … -32002\"",
|
||||
f"code={code(a)}")
|
||||
|
||||
# ---- GET/DELETE auf dem Endpunkt ---------------------------------------
|
||||
for art in ("GET", "DELETE"):
|
||||
try:
|
||||
req = urllib.request.Request(f"http://127.0.0.1:{port}/mcp", method=art,
|
||||
headers={"Authorization": "Bearer " + token})
|
||||
st = urllib.request.urlopen(req, timeout=10).status
|
||||
except urllib.error.HTTPError as e:
|
||||
st = e.code
|
||||
except Exception:
|
||||
st = 0
|
||||
pruefe("transport", f"HTTP {art} auf dem Endpunkt -> 405", st == 405,
|
||||
"„respond with 405 Method Not Allowed\"", f"HTTP {st}")
|
||||
|
||||
print()
|
||||
print(f" {_offen} Punkte OFFEN")
|
||||
sys.exit(1 if _offen else 0)
|
||||
finally:
|
||||
srv.terminate()
|
||||
try:
|
||||
srv.wait(5)
|
||||
except Exception:
|
||||
srv.kill()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,65 @@
|
||||
-- umschlag.lua: Kopf-/Envelope-Pruefung nach Spec 2026-07-28
|
||||
-- Basis: job667.lua (coder Lauf 5, #669) — parst, reine Struktur, zwei
|
||||
-- Defekte per Foreman-Review #671/#674 hier korrigiert:
|
||||
-- Regel 3: mcp-name-KOPF wird geprueft (war nur params.name/uri)
|
||||
-- Regel 4: _meta liegt unter rumpf.params._meta (war rumpf.meta)
|
||||
local M = {}
|
||||
|
||||
-- kopf: Tabelle der HTTP-Kopfzeilen, Namen KLEINGESCHRIEBEN, z.B.
|
||||
-- {['mcp-method']='tools/list',['mcp-protocol-version']='2026-07-28'}
|
||||
-- rumpf: dekodierte JSON-RPC-Anfrage als Lua-Tabelle
|
||||
-- {jsonrpc='2.0',id=1,method='tools/list',params={_meta={...}}}
|
||||
-- Rueckgabe: true,nil,nil | false,<fehlercode>,<meldung>
|
||||
function M.pruefe(kopf, rumpf)
|
||||
if not kopf or not rumpf then
|
||||
return false, -32600, "Invalid Request"
|
||||
end
|
||||
|
||||
-- Regel 1: k['mcp-protocol-version'] fehlt
|
||||
if not kopf['mcp-protocol-version'] then
|
||||
return false, -32020, 'Missing required header: MCP-Protocol-Version'
|
||||
end
|
||||
|
||||
-- Regel 2: k['mcp-method'] fehlt
|
||||
if not kopf['mcp-method'] then
|
||||
return false, -32020, 'Missing required header: Mcp-Method'
|
||||
end
|
||||
|
||||
-- Regel 2: k['mcp-method'] ~= rumpf.method
|
||||
if kopf['mcp-method'] ~= rumpf.method then
|
||||
return false, -32020, 'Mcp-Method header does not match body'
|
||||
end
|
||||
|
||||
-- Regel 3: Mcp-Name-Kopf Pflicht bei tools/call, resources/read, prompts/get
|
||||
local method = rumpf.method
|
||||
local params = rumpf.params or {}
|
||||
|
||||
if method == 'tools/call' or method == 'prompts/get' then
|
||||
if not kopf['mcp-name'] or kopf['mcp-name'] ~= params.name then
|
||||
return false, -32020, 'Mcp-Name header does not match body'
|
||||
end
|
||||
elseif method == 'resources/read' then
|
||||
if not kopf['mcp-name'] or kopf['mcp-name'] ~= params.uri then
|
||||
return false, -32020, 'Mcp-Name header does not match body'
|
||||
end
|
||||
end
|
||||
|
||||
-- Regel 4: _meta-Pflichtfelder (liegen unter params._meta)
|
||||
local meta = (rumpf.params or {})._meta or {}
|
||||
if not meta['io.modelcontextprotocol/protocolVersion'] then
|
||||
return false, -32602, 'Missing required _meta field: io.modelcontextprotocol/protocolVersion'
|
||||
end
|
||||
if not meta['io.modelcontextprotocol/clientCapabilities'] then
|
||||
return false, -32602, 'Missing required _meta field: io.modelcontextprotocol/clientCapabilities'
|
||||
end
|
||||
|
||||
-- Regel 5: k['mcp-protocol-version'] ~= meta['io.modelcontextprotocol/protocolVersion']
|
||||
if kopf['mcp-protocol-version'] ~= meta['io.modelcontextprotocol/protocolVersion'] then
|
||||
return false, -32020, 'Header MCP-Protocol-Version does not match _meta protocolVersion'
|
||||
end
|
||||
|
||||
-- Erfolg
|
||||
return true, nil, nil
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -0,0 +1,55 @@
|
||||
-- versions.lua
|
||||
-- Modul zur Versionspruefung gemaess LMCP-Vertrag
|
||||
|
||||
local M = {}
|
||||
|
||||
-- Nur die neue Fassung. Die alte (2025-06-18) existiert nicht mehr: mit
|
||||
-- SEP-2575 ist `initialize` entfernt, die Verhandlung der alten Fassung
|
||||
-- damit tot. 2025-06-18 in der Liste zu fuehren waere eine Luege im
|
||||
-- discover-Response. Dual-Protokoll (alt + neu) ist eine spaetere Phase.
|
||||
M.SUPPORTED = {"2026-07-28"}
|
||||
|
||||
--- Prueft, ob eine Version unterstuetzt wird.
|
||||
-- @param version Die zu pruefende Version (String oder nil)
|
||||
-- @return boolean true wenn unterstuetzt, sonst false
|
||||
-- @return table|nil Fehlerdetails bei Nichtunterstuetzung
|
||||
function M.check(version)
|
||||
-- (a) version == nil oder "" -> true, nil
|
||||
if version == nil or version == "" then
|
||||
return true, nil
|
||||
end
|
||||
|
||||
-- (b) exakter Treffer in M.SUPPORTED -> true, nil
|
||||
for _, supported_version in ipairs(M.SUPPORTED) do
|
||||
if version == supported_version then
|
||||
return true, nil
|
||||
end
|
||||
end
|
||||
|
||||
-- (c) alles andere -> false, { code = -32022, data = { supported = <Kopie> } }
|
||||
--
|
||||
-- KOPIE, nicht M.SUPPORTED selbst. Vorher ging die Modultabelle nach aussen:
|
||||
-- ein Aufrufer, der das Fehlerobjekt behaelt und `err.data.supported[1]`
|
||||
-- ueberschreibt, veraendert die Liste des Moduls fuer JEDEN folgenden
|
||||
-- Aufruf -- vorgefuehrt am 2026-08-09: nach
|
||||
-- `e.data.supported[1] = "GEKAPERT"` ist `check("2025-06-18")` falsch und
|
||||
-- `check("GEKAPERT")` wahr. Vertragsregel 5 ("Ein Aufruf darf die Liste des
|
||||
-- naechsten nicht verschieben") war damit gebrochen, und Pruefung 5 sah es
|
||||
-- nicht, weil sie nie ueber die zurueckgegebene Referenz schreibt.
|
||||
-- Solange das Modul niemand aufrief, war das theoretisch. Seit es an
|
||||
-- `initialize` haengt, ist es erreichbar.
|
||||
local kopie = {}
|
||||
for i = 1, #M.SUPPORTED do
|
||||
kopie[i] = M.SUPPORTED[i]
|
||||
end
|
||||
return false, {
|
||||
code = -32022,
|
||||
data = {
|
||||
supported = kopie
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
-- Keine neuen Globalen, keine Seiteneffekte, M.SUPPORTED wird nicht geaendert
|
||||
|
||||
return M
|
||||
@@ -0,0 +1,32 @@
|
||||
ENTSCHEIDUNG (deus, Operator) — Eskalation #656: Option C.
|
||||
|
||||
C gewaehlt: Selbsttest-Anforderung streichen. Die Suite ist der Test.
|
||||
|
||||
Begruendung:
|
||||
- 3 von 4 Coder-Fehlschlägen sind Selbsttest-MECHANIK (Fence, return-Position,
|
||||
String-Konstruktion) — Nicht-Konvergenz genau an dem Teil ohne externen Wert.
|
||||
Die Suite ist DER VERTRAG (Uebergabe). Weiter am Selbsttest zu ziehen ist
|
||||
der bekannte Runaway.
|
||||
- Lauf 3 (job649) hatte einen gruenen Selbsttest auf den falschen Funktionen —
|
||||
Selbsttests dieses Modells haben nachweislich null Verifikationswert.
|
||||
Einzig vertrauenswuerdiger Check ist die Suite.
|
||||
- Nach Integration laeuft die Suite sofort; konkrete rote Punkte nennen
|
||||
erwartet/ist und treiben gezielte Fixes.
|
||||
|
||||
Neuer Dispatch an @coder (Lauf 5):
|
||||
- Datei umschlag.lua, ROH-Lua, keine Fences/Backticks, Zeile 1 echte Lua.
|
||||
- NUR das Modul: local M = {}; function M.pruefe(kopf, rumpf) -> true,nil,nil |
|
||||
false,<fehlercode>,<meldung> end; return M als LETZTE Zeile.
|
||||
- KEIN Selbsttest in der Datei (entfaellt, die Suite prueft nach meiner
|
||||
Integration).
|
||||
- Parse-Check durch die Sandkiste (lua5.4); Logik-Check durch die Suite.
|
||||
- Regeln unveraendert (#628): Kopfnamen klein (case-insensitiv), Kopfwerte
|
||||
case-sensitiv; fehlender/abweichender Pflichtkopf (Mcp-Method,
|
||||
Mcp-Protocol-Version, Mcp-Name bei tools/call|resources/read|prompts/get)
|
||||
-> -32020 HeaderMismatch; MCP-Protocol-Version muss == params._meta
|
||||
["io.modelcontextprotocol/protocolVersion"]; _meta-Pflichtfelder fehlen
|
||||
-> -32602; Reihenfolge: Koepfe zuerst, bei beidem verletzt gewinnt -32020.
|
||||
|
||||
Nach Lieferung: ich integriere in lmcp.lua (Operator), lasse die Suite laufen,
|
||||
sende die konkreten roten Punkte als Fix-Auftraege mit Suite-Text als
|
||||
Abnahmekriterium. Kein Dienst wird angefasst.
|
||||
@@ -0,0 +1,25 @@
|
||||
INTEGRATION DONE (deus, Operator) — Suite gemessen: 19/27 zu, 8 OFFEN.
|
||||
|
||||
Was ich tat (Basis job667.lua, coder Lauf 5):
|
||||
- umschlag.lua = job667 + die zwei von dir benannten Fixes (#671/#674),
|
||||
angewandt beim Integrieren: Regel 3 mcp-name-KOPF, Regel 4 _meta unter
|
||||
rumpf.params._meta. Lokal gegen die Suite-Szenarien verifiziert (11/11).
|
||||
- In lmcp.lua verdrahtet: require + Envelope-Check in _dispatch_post nach dem
|
||||
Response-Routing, Fehler via _fehler_status -> 400. Kein anderer Zweig
|
||||
angefasst; laufender Raum-Server unberuehrt (nur Arbeitskopie).
|
||||
- Suite gelaufen, Vertrag unveraendert (sha256 c90450a6... identisch).
|
||||
|
||||
Zugewachsen: header 5/5, _meta 3/3 (waren 0). Keine Regression (discover 4/5,
|
||||
result, method, codes, transport weiter gruen).
|
||||
|
||||
Offen (8), alle Operator-Arbeit (Lua-Implementierungsdateien, keine
|
||||
Roster-Rolle darf die aendern):
|
||||
- version 4: unbekannte Fassung -> -32022 + 400 + data.supported/requested.
|
||||
versions.check haengt nur am initialize-Zweig (Z.599), nicht am
|
||||
Request-Pfad. Anbinden im Umschlag erfordert "2026-07-28" in
|
||||
versions.SUPPORTED (discover kopiert die Liste, Z.576) -> dreht den
|
||||
Schlussstein mit. => letzter Block.
|
||||
- entfernt 3: initialize/ping/logging/setLevel -> -32601.
|
||||
- Schlussstein 1: supportedVersions enthaelt 2026-07-28 (bleibt rot bis 26 zu).
|
||||
|
||||
@coder-Umschlag-Teil abgeschlossen. Naechste Portionen fahre ich als Operator.
|
||||
@@ -0,0 +1,30 @@
|
||||
RESUME — umschlag.lua re-dispatch an @coder (Repair-first abgeschlossen, deus).
|
||||
|
||||
Stand: @foreman-Sitzung funktional (bestätigt #642). @coder-Sandbox ist
|
||||
funktionsfähig — der Fehler (#630, "job628.lua:1: unexpected symbol near '`'")
|
||||
war @coders eigene Ausgabe: es hat seinen Lua-Code in ```lua ... ```-Fences
|
||||
gepackt, und die Sandkiste schrieb das Backtick als ungültige Zeile 1.
|
||||
|
||||
Bitte @coder erneut dispatchen für die Datei umschlag.lua, mit dem expliziten
|
||||
Zusatz:
|
||||
|
||||
"Schreibe die Datei als ROHEN Lua-Quelltext — KEINE Markdown-Fences, kein
|
||||
```lua ... ```, keine Backticks. Zeile 1 muss echte Lua sein."
|
||||
|
||||
Vertrag bleibt wie in #628 (nicht neu verhandeln):
|
||||
local M = {}
|
||||
-- kopf: Tabelle der HTTP-Kopfzeilen, Namen KLEINGESCHRIEBEN
|
||||
-- rumpf: dekodierte JSON-RPC-Anfrage als Lua-Tabelle
|
||||
function M.pruefe(kopf, rumpf) -> true,nil,nil | false,<fehlercode>,<meldung>
|
||||
return M
|
||||
Regeln (wörtlich aus der Spec, siehe SPEC-AUSZUG.md):
|
||||
- fehlender/abweichender Pflichtkopf (Mcp-Method, Mcp-Protocol-Version,
|
||||
Mcp-Name bei tools/call|resources/read|prompts/get) -> -32020 HeaderMismatch
|
||||
- MCP-Protocol-Version muss == params._meta["io.modelcontextprotocol/protocolVersion"]
|
||||
- Kopfnamen case-insensitiv (bekommt sie klein), Kopfwerte case-sensitiv
|
||||
- _meta-Pflichtfelder fehlen -> -32602 (protocolVersion, clientCapabilities)
|
||||
- Reihenfolge: Köpfe zuerst, dann _meta; bei beidem verletzt gewinnt -32020.
|
||||
- Selbsttest in der Datei; er darf nicht werfen.
|
||||
|
||||
Wenn @coder liefert, integriere ich (deus, Operator) in lmcp.lua, lasse die
|
||||
Suite laufen und reiche an @reviewer. Kein Dienst wird angefasst.
|
||||
Reference in New Issue
Block a user