Files
rune/scripts/check_core_server_parity.py
T
Nick 65ceff40b9 feat(core_server): close PARTIAL gaps — dichotomy wave
Port the 6 audit-missing fns name-preserving into src/go/core-server
(make_server, log_message, _send_json, _send_ndjson, do_GET, do_POST;
main via Main/os.Args surface): the full HTTP sidecar surface with
byte-identical wire bodies (vendored pyjson PyDump: json.dumps ', '/': '
separators + ensure_ascii + PyDict insertion order), CPython json
scanner error messages, int()/parse_qs/truthiness/or-laws, str[:200]
codepoint truncation, and the AttributeError crash-parity class.

Truth: 57-case shared-harness envelope (scripts/gen_core_server_truth.py
under scripts/cs_freeze_seams — pinned uuid/time on module attrs,
rig-bound probe seams exercising the REAL handler methods) verified
byte-identical x5; go test 9/9 (verbatim TestFrozenTruthReplay + 8
quirk tests); CI replay binary 57/57; live HTTP parity 24/24
byte-identical (scripts/check_core_server_parity.py — bodies exact
under pinned id/created, not modulo-volatile); canary_rune_serve 28/28;
gofmt/vet/build clean; ruff clean; shims pytest zero-delta vs stashed
base (9 fresh-worktree sibling-kernel failures pre-existing).
Dichotomy audit core_server 6/12 PARTIAL -> 12/12 FULL (107/192).
2026-10-14 16:25:25 +01:00

228 lines
8.5 KiB
Python

#!/usr/bin/env python3
"""check_core_server_parity.py — live HTTP parity: the Python oracle
(core_server.make_server) vs the GO port (src/go/core-server serve),
byte-exact bodies under pinned uuid/time (scripts/cs_freeze_seams).
Both servers run the SAME spec-built stub operator; the Go process gets
the identical spec via RUNE_CS_OPERATOR_SPEC plus the id/created pins
via RUNE_CS_CHUNK_HEX / RUNE_FROZEN_NOW, so every response body —
including chat.completion ids, created epochs, NDJSON framing, error
envelopes, and Python json.dumps separator bytes — must match the
oracle BYTE FOR BYTE (not modulo-volatile like the canary).
Run: python3 scripts/check_core_server_parity.py
"""
from __future__ import annotations
import http.client
import json
import os
import subprocess
import sys
import threading
import time
from pathlib import Path
REPO = Path(__file__).resolve().parents[1]
# Pull in the freeze rig (auto-imported when PYTHONPATH includes it; the
# explicit import covers bare invocation) — it pins uuid/time on the
# oracle module BEFORE import and exposes the stub operator + constants.
sys.path.insert(0, str(REPO / "scripts" / "cs_freeze_seams"))
import sitecustomize # noqa: E402 (the rig; pins apply on first import)
from rune import core_server # noqa: E402 (after the rig pins)
FROZEN_HEX = sitecustomize.FROZEN_HEX
FROZEN_NOW = sitecustomize.FROZEN_NOW
SPEC = {
"models": [{"name": "stub-a", "size_gb": 4.1}, {"size_gb": 2}, {}],
"status": {"identity": "rune", "role": "operator", "current_task": None,
"active_model": "stub-a", "tasks_pending": 0,
"tasks_completed": 3},
"send": {"task_id": "task-1", "status": "completed", "model": "stub-model",
"user_text": "Canned reply.", "degraded": [], "iterations_used": 1},
"window": [{"role": "user", "content": "m1"},
{"role": "assistant", "content": "m2"},
{"role": "user", "content": "m3"}],
}
SPEC_RAISE = {"raise_status": "boom", "raise_send": "boom send"}
PASS = 0
FAIL = 0
def test(name: str, ok: bool, detail: str = "") -> None:
global PASS, FAIL
if ok:
PASS += 1
print(f" ✓ {name}")
else:
FAIL += 1
print(f" ✗ {name} — {detail}")
def request(port: int, method: str, path: str, body: str | None = None):
"""One raw request → (status, content-type, body-bytes) or NO_RESPONSE."""
try:
conn = http.client.HTTPConnection("127.0.0.1", port, timeout=10)
headers = {}
data = None
if body is not None:
data = body.encode()
headers["Content-Type"] = "application/json"
conn.request(method, path, body=data, headers=headers)
resp = conn.getresponse()
out = (resp.status, resp.getheader("Content-Type"), resp.read())
conn.close()
return out
except Exception: # noqa: BLE001 — the crash-parity class IS the contract
return ("NO_RESPONSE", None, b"")
def wait_ready(port: int, timeout: float = 10.0) -> bool:
deadline = time.time() + timeout
while time.time() < deadline:
r = request(port, "GET", "/v1/status")
if r[0] != "NO_RESPONSE":
return True
time.sleep(0.1)
return False
def free_port() -> int:
import socket
s = socket.socket()
s.bind(("127.0.0.1", 0))
port = s.getsockname()[1]
s.close()
return port
class PyServer:
"""The oracle on a real socket with the rig's spec-built stub."""
def __init__(self, spec: dict):
self.port = free_port()
self.server = core_server.make_server(
"127.0.0.1", self.port, sitecustomize._stub_operator(spec))
self.thread = threading.Thread(target=self.server.serve_forever, daemon=True)
def __enter__(self) -> int:
self.thread.start()
assert wait_ready(self.port)
return self.port
def __exit__(self, *exc) -> None:
self.server.shutdown()
class GoServer:
def __init__(self, spec: dict):
self.port = free_port()
env = dict(os.environ)
env["RUNE_CS_OPERATOR_SPEC"] = json.dumps(spec)
env["RUNE_CS_CHUNK_HEX"] = FROZEN_HEX
env["RUNE_FROZEN_NOW"] = FROZEN_NOW
self.proc = subprocess.Popen(
["/tmp/cs-parity-serve", "--host", "127.0.0.1",
"--port", str(self.port)],
env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
def __enter__(self) -> int:
assert wait_ready(self.port)
return self.port
def __exit__(self, *exc) -> None:
self.proc.terminate()
try:
self.proc.wait(timeout=5)
except subprocess.TimeoutExpired:
self.proc.kill()
CHAT_BODY = json.dumps({"model": "m2", "messages": [
{"role": "user", "content": "first"},
{"role": "assistant", "content": "mid"},
{"role": "user", "content": "final"}]})
def cases() -> list[tuple[str, str, str, str | None]]:
return [
("models", "GET", "/v1/models", None),
("status", "GET", "/v1/status", None),
("conversation", "GET", "/v1/conversation?channel=ops&n=2", None),
("conversation-defaults", "GET", "/v1/conversation", None),
("conversation-bad-n", "GET", "/v1/conversation?n=abc", None),
("conversation-pct", "GET", "/v1/conversation?channel=%C3%A9+d", None),
("models-fullpath-mismatch", "GET", "/v1/models?x=1", None),
("not-found", "GET", "/v1/nope", None),
("approve", "POST", "/v1/approvals/resolve", '{"approved": true}'),
("approve-truthy-string", "POST", "/v1/approvals/resolve", '{"approved": "yes"}'),
("approve-empty-body", "POST", "/v1/approvals/resolve", ""),
("approve-bad-json", "POST", "/v1/approvals/resolve", "not json"),
("approve-trailing-comma", "POST", "/v1/approvals/resolve",
'{"approved": true,}'),
("chat", "POST", "/v1/chat/completions", CHAT_BODY),
("chat-stream", "POST", "/v1/chat/completions",
'{"messages": [{"role": "user", "content": "streamed"}], "stream": true}'),
("chat-stream-truthy-string", "POST", "/v1/chat/completions",
'{"messages": [{"role": "user", "content": "x"}], "stream": "yes"}'),
("chat-no-user", "POST", "/v1/chat/completions",
'{"messages": [{"role": "assistant", "content": "no"}]}'),
("chat-numeric-content", "POST", "/v1/chat/completions",
'{"messages": [{"role": "user", "content": 5}]}'),
("chat-crash-parity", "POST", "/v1/chat/completions",
'{"messages": "abc"}'),
("chat-model-empty", "POST", "/v1/chat/completions",
'{"model": "", "messages": [{"role": "user", "content": "x"}]}'),
("post-not-found", "POST", "/v1/other", "{}"),
]
def sweep(py_port: int, go_port: int) -> None:
for name, method, path, body in cases():
py = request(py_port, method, path, body)
go = request(go_port, method, path, body)
ok = py == go
detail = ""
if not ok:
detail = (f"py=({py[0]!r},{py[1]!r}) {py[2][:160]!r} "
f"go=({go[0]!r},{go[1]!r}) {go[2][:160]!r}")
test(f"parity: {name} byte-identical", ok, detail)
def main() -> int:
print("=" * 55)
print("core_server live parity — Python oracle vs GO port (pinned)")
print("=" * 55)
go_dir = REPO / "src" / "go" / "core-server"
r = subprocess.run(["go", "build", "-o", "/tmp/cs-parity-serve", "."],
cwd=go_dir, capture_output=True, text=True, timeout=300)
test("go build exits 0", r.returncode == 0, r.stderr[-300:])
with PyServer(SPEC) as py_port, GoServer(SPEC) as go_port:
print(f"py oracle :{py_port} go port :{go_port}")
sweep(py_port, go_port)
with PyServer(SPEC_RAISE) as py_port, GoServer(SPEC_RAISE) as go_port:
py = request(py_port, "GET", "/v1/status")
go = request(go_port, "GET", "/v1/status")
test("parity: raise-status 500 envelope byte-identical", py == go,
f"py={py[2][:160]!r} go={go[2][:160]!r}")
py = request(py_port, "POST", "/v1/chat/completions",
'{"messages": [{"role": "user", "content": "x"}]}')
go = request(go_port, "POST", "/v1/chat/completions",
'{"messages": [{"role": "user", "content": "x"}]}')
test("parity: raise-send 500 envelope byte-identical", py == go,
f"py={py[2][:160]!r} go={go[2][:160]!r}")
print(f"\nRESULTS: {PASS} pass, {FAIL} fail")
return 1 if FAIL else 0
if __name__ == "__main__":
sys.exit(main())