Files
rune/scripts/gen_core_server_truth.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

165 lines
8.8 KiB
Python

#!/usr/bin/env python3
"""gen_core_server_truth.py — freeze core_server oracle truth (dichotomy
wave #2479 gap port, contract factory-gap-cs).
Runs under the cs freeze rig (PYTHONPATH=scripts/cs_freeze_seams:src) so
uuid/time are pinned on the oracle module and every case is
deterministic. Covers EVERY ported function and branch: the envelope
transforms (_envelope_error, models_view, chat_completion, chat_chunks)
directly, and the handler/server layer (log_message, _send_json,
_send_ndjson, do_GET, do_POST, make_server) through the rig-bound probe
seams that exercise the REAL oracle methods against a recording fake
handler. The Go battery (src/go/core-server/truth_test.go) and the CI
replay binary rebuild every row through the ported functions.
Usage:
PYTHONPATH=scripts/cs_freeze_seams:src python3 scripts/gen_core_server_truth.py
"""
from __future__ import annotations
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts"))
from freeze_truth import freeze, write_envelope # noqa: E402
FROZEN_NOW = "2026-10-14T08:00:00+00:00" # int epoch 1791964800 (rig FROZEN_EPOCH)
TRUTH = Path(__file__).resolve().parents[1] / "src" / "go" / "core-server" / "truth.json"
SPEC_MODELS = {"models": [{"name": "stub-a", "size_gb": 4.1}, {"size_gb": 2}, {}]}
SPEC_STATUS = {"status": {"identity": "rune", "role": "operator", "current_task": None,
"active_model": "stub-a", "tasks_pending": 0,
"tasks_completed": 3}}
SPEC_CHAT = {"send": {"task_id": "task-1", "status": "completed",
"model": "stub-model", "user_text": "Canned reply.",
"degraded": [], "iterations_used": 1}}
SPEC_WINDOW = {"window": [{"role": "user", "content": "m1"},
{"role": "assistant", "content": "m2"},
{"role": "user", "content": "m3"}]}
SPEC_FULL = {**SPEC_MODELS, **SPEC_STATUS, **SPEC_CHAT, **SPEC_WINDOW}
def post(path, body, spec, cl="auto"):
"""do_POST probe args; cl="auto" carries the exact byte length."""
cl_val = str(len(body.encode())) if cl == "auto" else cl
return (path, cl_val, body, spec)
CASES: list = [
# ── envelope transforms ────────────────────────────────────────────
("_envelope_error", ("not_found", "no route /v1/definitely-not-here")),
("_envelope_error", ("internal_error", "x" * 250)), # no truncation at the source
("_models_view_probe", (SPEC_MODELS,)), # missing-name → "" law, order preserved
("_models_view_probe", ({"models": []},)), # empty list
("chat_completion", ({"model": "stub-model", "user_text": "hello world",
"task_id": "t1"}, None)),
("chat_completion", ({"user_text": "x"}, "fallback-model")), # result model missing
("chat_completion", ({"model": "", "user_text": "y"}, "fb")), # falsy result model
("chat_completion", ({"model": 5, "user_text": "z"}, None)), # non-string truthy
("chat_completion", ({"user_text": None}, "m")), # present-null content passes
("chat_completion", ({"model": "m"}, "fb")), # missing user_text → ""
("chat_chunks", ({"model": "stub-model", "user_text": "streamed"}, None)),
("chat_chunks", ({"user_text": "x"}, "fb")),
("chat_chunks", ({"user_text": "héllo ✓"}, "m")), # ensure_ascii bytes in NDJSON
# ── handler surface ────────────────────────────────────────────────
("_log_message_probe", ('"GET %s" %d', ["/v1/models", 200])),
("_send_json_probe", (200, {"object": "list", "data": []})), # ", "/": " law
("_send_json_probe", (404, {"error": {"code": "not_found",
"message": "no route /x"}})),
("_send_json_probe", (200, {"msg": "héllo ✓"})), # ensure_ascii
("_send_ndjson_probe", (200, [{"a": 1}, {"b": [1, 2]}])),
("_send_ndjson_probe", (200, [])), # empty body, Content-Length 0
("_make_server_probe", (SPEC_FULL,)),
# ── do_GET ─────────────────────────────────────────────────────────
("_do_get_probe", ("/v1/models", SPEC_MODELS)),
("_do_get_probe", ("/v1/status", SPEC_STATUS)),
("_do_get_probe", ("/v1/status", {"raise_status": "boom"})),
("_do_get_probe", ("/v1/status", {"raise_status": "y" * 250})), # [:200] runes
("_do_get_probe", ("/v1/conversation?channel=ops&n=2", SPEC_WINDOW)),
("_do_get_probe", ("/v1/conversation", SPEC_WINDOW)), # defaults operator/8
("_do_get_probe", ("/v1/conversation?n=abc", SPEC_WINDOW)), # int ValueError → 500
("_do_get_probe", ("/v1/conversation?channel=", SPEC_WINDOW)), # blank dropped
("_do_get_probe", ("/v1/conversation?n=99&n=abc", SPEC_WINDOW)), # first value
("_do_get_probe", ("/v1/conversation?n=+12", SPEC_WINDOW)), # '+' → ' ' → int strip
("_do_get_probe", ("/v1/conversation?n=-1", SPEC_WINDOW)), # negative slice
("_do_get_probe", ("/v1/conversation?channel=%C3%A9+d", SPEC_WINDOW)), # %XX + '+'
("_do_get_probe", ("/v1/models?x=1", SPEC_MODELS)), # full-path mismatch → 404
("_do_get_probe", ("/v1/nope", SPEC_FULL)),
# ── do_POST ────────────────────────────────────────────────────────
("_do_post_probe", post("/v1/approvals/resolve", '{"approved": true}', {})),
("_do_post_probe", post("/v1/approvals/resolve", '{"approved": 1}', {})), # truthy
("_do_post_probe", post("/v1/approvals/resolve", '{"approved": "yes"}', {})),
("_do_post_probe", post("/v1/approvals/resolve", '{"approved": 0}', {})), # falsy
("_do_post_probe", post("/v1/approvals/resolve", "", {})), # empty → {} → False
("_do_post_probe", post("/v1/approvals/resolve", '{"approved": true}', {}, cl="-5")),
("_do_post_probe", post("/v1/approvals/resolve", "not json", {})),
("_do_post_probe", post("/v1/approvals/resolve", "{}", {}, cl="x")), # CL garbage
("_do_post_probe", post("/v1/approvals/resolve", "{bad", {})),
("_do_post_probe", post(
"/v1/chat/completions",
'{"model": "m2", "messages": [{"role": "user", "content": "first"}, '
'{"role": "assistant", "content": "mid"}, {"role": "user", "content": "final"}]}',
SPEC_CHAT)), # LAST user text + model passthrough
("_do_post_probe", post(
"/v1/chat/completions",
'{"messages": [{"role": "user", "content": "streamed"}], "stream": true}',
SPEC_CHAT)),
("_do_post_probe", post(
"/v1/chat/completions",
'{"messages": [{"role": "user", "content": "x"}], "stream": false}',
SPEC_CHAT)),
("_do_post_probe", post(
"/v1/chat/completions",
'{"messages": [{"role": "user", "content": "x"}], "stream": "yes"}',
SPEC_CHAT)), # truthy string
("_do_post_probe", post(
"/v1/chat/completions",
'{"messages": [{"role": "assistant", "content": "no user here"}]}',
SPEC_CHAT)), # 400 user-role law
("_do_post_probe", post(
"/v1/chat/completions",
'{"messages": [{"role": "user", "content": 5}]}',
SPEC_CHAT)), # non-string content passes through (echo 5)
("_do_post_probe", post(
"/v1/chat/completions",
'{"messages": "abc"}',
SPEC_CHAT)), # uncaught AttributeError crash class
("_do_post_probe", post(
"/v1/chat/completions",
'{"model": "", "messages": [{"role": "user", "content": "x"}]}',
SPEC_CHAT)), # "" → None → model_arg null
("_do_post_probe", post(
"/v1/chat/completions",
'{"model": 5, "messages": [{"role": "user", "content": "x"}]}',
SPEC_CHAT)), # truthy non-string model
("_do_post_probe", post(
"/v1/chat/completions",
'{"messages": [{"role": "user", "content": "x"}]}',
{"raise_send": "boom"})), # send_task raise → 500 envelope
("_do_post_probe", post(
"/v1/chat/completions",
'{"messages": [{"role": "user", "content": "c"}],}',
SPEC_CHAT)), # trailing comma message
("_do_post_probe", post(
"/v1/chat/completions",
'{"messages": []} x',
SPEC_CHAT)), # extra data message
("_do_post_probe", post(
"/v1/chat/completions",
'{"model" "m"}',
SPEC_CHAT)), # ':' delimiter message
("_do_post_probe", post("/v1/other", "{}", SPEC_FULL)), # 404
]
def main() -> int:
truth = freeze("rune.core_server", CASES, oracle_module="rune.core_server")
write_envelope(FROZEN_NOW, truth, TRUTH)
print(f"wrote {len(truth)} cases to {TRUTH}")
return 0
if __name__ == "__main__":
sys.exit(main())