forked from marfrit/lmcp
tests: Phase B an der Wirklichkeit verankern
Der Test prueft M.SUPPORTED bisher nur gegen sich selbst: erster Eintrag
wird angenommen, Unbekanntes abgelehnt, data.supported entspricht
M.SUPPORTED. Ein Modul mit {"2025-06-18","2025-11-25"} besteht ihn mit
14/14 -- obwohl lmcp 2025-11-25 nicht spricht. Genau das ist am
2026-08-08 passiert: die Gesellschaft hat sauber gearbeitet, der Test gab
Rueckgabe 0, und abgenommen wurde der falsche Vertrag.
Drei Instanzen liessen es durch, und keine war nachlaessig: @coder riet
eine echte MCP-Fassung, @foreman konnte es aus dem Vertragstext nicht
widerlegen und bestaetigte es zweimal ausdruecklich, und der Test hatte
die Luecke geerbt. Die Wurzel war der Vertrag: er verlangt "die
Fassungen, die DIESER Server spricht" und nennt sie nicht. Damit war die
Liste eine freie Variable statt einer Tatsache.
DER NAHELIEGENDE FIX WAERE FALSCH GEWESEN. Die Liste im Vertrag zu
NENNEN ersetzt eine ungebundene Variable durch eine zweite Kopie der
Tatsache -- die veraltet, sobald lmcp eine Fassung dazulernt, und dann
schreibt der Vertrag wieder etwas fest, das der Server nicht spricht,
nur andersherum. (Dank an Fable fuer den Widerspruch.)
Stattdessen misst der Test jetzt: er schickt dem laufenden lmcp ein
`initialize` und haelt M.SUPPORTED gegen die gemeldete protocolVersion.
Die Bindung sitzt damit an der Quelle, und keiner der Beteiligten kann
mehr raten.
Ohne erreichbaren Server FAELLT der Test, er ueberspringt nicht. Eine
Abnahme, die ihre zentrale Eigenschaft nicht pruefen kann, ist keine
Abnahme -- und ein stiller Uebersprung ist genau die Art Gruen, gegen die
diese Phase antritt. Gemessen: ohne LMCP_PROBE_URL Rueckgabe 1.
Damit hat die Regel drei Richtungen statt zwei:
rot gegen eine kaputte Fassung,
gruen gegen eine korrekte,
und gruen gegen die WIRKLICHKEIT.
Nachgemessen gegen hertz-tools:8080:
SUPPORTED = {"2025-06-18"} -> 0 Fehlschlaege, Rueckgabe 0
SUPPORTED = {"2025-06-18","2025-11-25"} -> 1 Fehlschlag, Rueckgabe 1
Das zweite ist das Modul, das heute Vormittag als GRUEN abgenommen
wurde. Die Abnahme ist damit rueckwirkend rot -- und das ist das
Ergebnis, nicht der Fehler.
Aufruf: LMCP_PROBE_URL=http://<host>:8080/mcp LMCP_PROBE_TOKEN=<token> \
lua5.4 tests/phase_b_acceptance.lua <impl.lua>
This commit is contained in:
@@ -116,6 +116,51 @@ else
|
||||
ok3b and tostring(zul3b) or "warf")
|
||||
end
|
||||
|
||||
-- 3c. VERANKERUNG: M.SUPPORTED gegen den LAUFENDEN Server.
|
||||
--
|
||||
-- Ohne diese Pruefung misst der Test die Liste nur an sich selbst -- und ein
|
||||
-- Modul, das eine Fassung beansprucht, die der Server nicht spricht, besteht
|
||||
-- ihn glatt. Genau das ist am 2026-08-08 passiert: {"2025-06-18","2025-11-25"}
|
||||
-- ergab 14/14, obwohl lmcp nur 2025-06-18 meldet.
|
||||
--
|
||||
-- Gefragt wird per `initialize`; die Antwort nennt genau EINE protocolVersion,
|
||||
-- naemlich die, die dieser Server spricht. M.SUPPORTED muss exakt daraus
|
||||
-- bestehen.
|
||||
--
|
||||
-- Kein Uebersprung, wenn der Server fehlt: eine Abnahme, die ihre zentrale
|
||||
-- Eigenschaft nicht pruefen kann, ist keine Abnahme.
|
||||
local probe_url = os.getenv("LMCP_PROBE_URL")
|
||||
local probe_token = os.getenv("LMCP_PROBE_TOKEN")
|
||||
pruefe("LMCP_PROBE_URL ist gesetzt (ohne Server keine Verankerung)",
|
||||
probe_url ~= nil and probe_url ~= "", tostring(probe_url))
|
||||
|
||||
if probe_url and probe_url ~= "" then
|
||||
local rumpf = '{"jsonrpc":"2.0","id":1,"method":"initialize","params":' ..
|
||||
'{"protocolVersion":"2025-06-18","capabilities":{},' ..
|
||||
'"clientInfo":{"name":"phase-b-acceptance","version":"1"}}}'
|
||||
local befehl = "curl -s -m 15 -X POST"
|
||||
.. " -H 'Content-Type: application/json'"
|
||||
.. " -H 'Accept: application/json, text/event-stream'"
|
||||
if probe_token and probe_token ~= "" then
|
||||
befehl = befehl .. " -H 'Authorization: Bearer " .. probe_token .. "'"
|
||||
end
|
||||
befehl = befehl .. " -d '" .. rumpf .. "' '" .. probe_url .. "' 2>/dev/null"
|
||||
|
||||
local p = io.popen(befehl)
|
||||
local antwort = p and p:read("*a") or ""
|
||||
if p then p:close() end
|
||||
|
||||
local gemessen = antwort:match('"protocolVersion"%s*:%s*"([^"]+)"')
|
||||
pruefe("Server nennt eine protocolVersion", gemessen ~= nil,
|
||||
(#antwort > 0) and antwort:sub(1, 70) or "keine Antwort")
|
||||
|
||||
if gemessen then
|
||||
local passt = (#M.SUPPORTED == 1) and (M.SUPPORTED[1] == gemessen)
|
||||
pruefe("M.SUPPORTED entspricht GENAU dem, was der Server spricht ("
|
||||
.. gemessen .. ")", passt, table.concat(M.SUPPORTED, ","))
|
||||
end
|
||||
end
|
||||
|
||||
-- 4. wirft nie
|
||||
local fremde = { 42, true, false, {}, print, 0/0 }
|
||||
local alle_still, welcher = true, nil
|
||||
|
||||
Reference in New Issue
Block a user