taicpp: port skills, scheduler, telegram, rag, install, release/audit backends with differential tests against tai.py

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-25 05:06:38 +01:00
co-authored by Claude Sonnet 5.5
parent fc436aeb24
commit 1d962cd3f1
59 changed files with 11732 additions and 0 deletions
+112
View File
@@ -0,0 +1,112 @@
#!/usr/bin/env python3
"""Generates the shared inputs of the differential tests (tests/misc_data/*.json) with a fixed seed.
Both the Python reference driver and the C++ driver read these files, so the two sides see identical
inputs. Re-run: python3 -I tests/gen_misc_data.py (from taicpp/).
"""
import json
import os
import random
HERE = os.path.dirname(os.path.abspath(__file__))
OUT = os.path.join(HERE, "misc_data")
def write(name, data):
os.makedirs(OUT, exist_ok=True)
with open(os.path.join(OUT, name), "w", encoding="utf-8") as handle:
json.dump(data, handle, ensure_ascii=True, indent=0)
handle.write("\n")
def json_cases():
cases = [
"{}", "[]", "null", "true", "false", "0", "-0", "1", "-1", "123456789012", "1.5", "-0.25", "1e3", "1E-7", "0.1", "1e22", "1e16", "123456789.123456789",
"0.00001", "0.0001", "100.0", "1e-5", "5e-324", "1.7976931348623157e308", "NaN", "Infinity", "-Infinity",
'"plain"', '"quote\\"inside"', '"back\\\\slash"', '"tab\\there"', '"nl\\nhere"', '"cr\\rhere"', '"\\b\\f"', '"\\u00e9"', '"\\u20ac"', '"\\ud83d\\ude00"',
'"\\u007f"', '"\\u0000"', '"\\u001f"', '"/"', '"\\/"', '"café"', '"€100"', '"\U0001f600 smile"', '"\\ud83d"',
'{"a": 1, "b": [1, 2, {"c": null}], "d": "e"}', '{"z": 1, "a": 2, "z": 3}', '[1, [2, [3, [4]]]]', ' { "x" : [ 1 , 2 ] } ',
'{"source": "tai-bundled", "mode": "bundled", "scope": "home", "files": {"SKILL.md": "abc12345"}, "installed_at": "2026-10-25T10:11:12.123456+00:00"}',
'[1,2', '{"a":}', '{"a" 1}', "{'a': 1}", '"unterminated', '[1,]', '{"a":1,}', "tru", "01", "1.", ".5", "+1", '"\\x41"', "", " ", "{} extra", '"a\nb"',
'[true, false, null, 1, 2.0, "s"]', '{"k": "\\u00e9\\u20ac\\ud83d\\ude00"}', "12345678901234567890", "-9223372036854775808", "9223372036854775807",
]
return cases
def datetime_cases():
return [
"2026-10-08T09:00", "2026-10-08 09:00", "2026-10-08", "2026-10-08T09:00:30", "2026-10-08T09:00:30.5", "2026-10-08T09:00:30.123456",
"2026-10-08T09:00:30.1234567", "2026-10-08T09:00Z", "2026-10-08T09:00:00z", "2026-10-08T09:00+02:00", "2026-10-08T09:00-05:30", "2026-10-08T09:00:00+0200",
"2026-10-08T09:00:00+02", "2026-10-08T09:00:00.25+02:00", "20261008T0900", "20261008", "20261008T090030", "2026-10-08T09", "2026-10-08T0900", "2026-10-08x09:00",
"2026-13-01", "2026-02-30", "2024-02-29T12:00", "2023-02-29T12:00", "2026-10-08T25:00", "2026-10-08T09:61", "2026-10-08T09:00:61", "now", "", " ", "tomorrow",
"2026-10-08T", "2026-10-08T09:", "2026-10-08T09:0", "2026-1-8", "26-10-08", "2026-10-08T09:00+25:00", "2026-10-08T09:00+02:00:30", " 2026-10-08T09:00 ",
"2026-10-08T09:00:00.123+01:00", "0001-01-01T00:00", "9999-12-31T23:59:59.999999", "2026-10-08T09:00 +02:00", "2026-10-08T09:00:00Z\n", "2026-03-29T02:30",
"2026-10-25T02:30", "2026-10-25T12:00:00+00:00", "2026-10-25T12:00:00.000001+00:00",
"2026-10-08T09:00x+02:00", "2026-10-08T09:00\u00a0+02:00", "2026-10-08T09:00\n+02:00", "2026-10-08T09:00:00x-02:00", "2026-10-08T09:00:00xZ", "2026-10-08T09:00:00 Z",
"2026-10-08T09 Z", "2026-10-08T0900 Z", "2026-10-08T090000 +01", "2026-10-08T09:00:00.123456789 +01", "2026-10-08T09:00:00,5 +01", "2026-10-08T09:00:00.5x+01",
"2026-10-08T09:00:00+01 ", "2026-10-08T09:00:00+0100", "2026-10-08T09:00:00+01:0", "2026-10-08T09:00:00+1", "2026-10-08T09:00:00+01:00:", "2026-10-08T09:00:00++01",
"2026-10-08T09:00:00+01Z", "2026-10-08T09:00:00 +", "2026-10-08T09:00:00-", "2026-10-08 T09:00", "2026-10-08TT09:00", "2026-10-08\u00e9", "2026-10-08\u00e909:00",
"2026-10-08\u20ac09:00", "2026-10-08T09:00:00.000001+01:00:00.5", "1999-12-31T24:00:00", "2026-10-08T24:00", "2026-10-08T24:00:00.0", "9999-12-31T24:00",
"2026-10-08T09:00:00+0100:00", "2026-10-08T09:00:00+01:00:0000", "2026-10-08T09:00:00-00:00", "2026-W01-1", "2026-W53-7", "2026-W00-1", "2026-W41-8", "2026W414",
"2026W41", "2026-W41-4T10:00", "2026-W41T10:00", "2026-10-08t09:00", "2026-10-08T09:+02:00", "2026-10-08T09:00xx+02:00", "2026-10-08T09:00:00.12345x+02:00",
"2026-10-08T09:00:00.1234567x+02:00", "2026-10-08T09:00:00.123456xy+02:00", "2026-10-08T09:0+02:00", "2026-10-08T09:00:00:00", "2026-10-08T09:00:00.5.5", "2026-10-08T0900:00",
"2026-10-08T09:0000", "2026-10-08T09:00:00+01:00:00.1234567", "2026-10-08T09:00:00+01:00:00.", "2026-W53-1", "2020-W53-5", "2015-W53-4", "2026-W41-4 10:00", "2026-W41-4x",
"2026-W41-4-10", "2026-W41-410", "2026W4141", "2026W41410", "2026-10-08T09:00-23:59", "2026-10-08T09:00+23:59:59", "2026-10-08T09:00+24:00", "2026-10-08T09:00-24:00",
"0001-01-01T00:00+00:00", "0001-01-01T00:00+01:00", "0001-01-01T00:00-01:00", "0001-01-01T10:00:00+00:00", "9999-12-31T23:59:59.999999+00:00", "9999-12-31T23:59:59+00:00",
"9999-12-31T23:59:59-01:00", "9999-12-31T00:00:00+01:00", "0001-01-01T00:00:00.000001+00:00", "1970-01-01T00:00:00", "1900-01-01T00:00:00", "1800-06-15T12:00:00",
"2026-03-29T01:59:59", "2026-03-29T02:00:00", "2026-03-29T03:00:00", "2026-10-25T01:59:59", "2026-10-25T02:00:00", "2026-10-25T03:00:00", "2026-10-25T02:59:59.999999",
"2038-01-19T03:14:08", "2100-12-31T23:59:59", "5000-01-01T00:00:00", "2026-10-08T09:00:00\u00e9", "\u2003 2026-10-08T09:00 \u2003", "2026-10-08T09:00:00,123",
"2026-02-29", "2028-02-29", "2100-02-29", "2000-02-29", "20260229", "2026-10-08T09:00:00.5+02:00", "2026-10-08T09:00:00,5+02:00", "2026-10-08T09:00:00.+02:00",
]
def duration_cases():
return ["30", "30s", "5m", "2h", "1d", "1w", "10 m", " 7D ", "0", "0s", "5x", "", "m", "-5", "5.5", "1e3", "00012h", "9999999999d", "5 M", "5mm", "5٠"]
def delay_cases():
return [-5.5, -1, -0.5, 0, 0.9, 1, 59, 59.99, 60, 61, 3599, 3600, 3601, 86399, 86400, 86401, 90061, 1000000, 1e9]
def chunk_cases():
rng = random.Random(20261025)
words = ["alpha", "beta", "gamma", "delta", "epsilon", "café", "naïve", "€", "\U0001f600", "x", "long" * 20, "", " ", "\t"]
seps = ["\n", "\r\n", "\r", "\x0b", "\x0c", "\x1c", "\x1d", "\x1e", "\x85", "
", "
"]
cases = []
fixed = [
"", "one line", "a\nb\nc", "a\n\nb\n\n\nc", "\n\n\n", " \n ", "trail\n", "\nlead", "a\r\nb\rc\x0bd\x0ce\x1cf\x1dg\x1eh\x85i
j
k",
"x" * 5000, "\n".join("line %d" % i for i in range(200)), "\n".join("w" * 50 for _ in range(100)), "é" * 4100 + "\nnext", "\n".join(["same"] * 12),
"a\nb\nb\nb\nc\nc\nd", "p\np\np\nq\nq\nq\nq\nr", "same\nsame\nsame", "\n".join(["same"] * 2 + ["other"] + ["same"] * 3),
]
for text in fixed:
cases.append({"text": text, "max_lines": 60, "overlap": 3, "max_chars": 4000})
for text in fixed[:12]:
cases.append({"text": text, "max_lines": 5, "overlap": 2, "max_chars": 40})
cases.append({"text": text, "max_lines": 3, "overlap": 0, "max_chars": 10})
cases.append({"text": text, "max_lines": 4, "overlap": 9, "max_chars": 100})
for index in range(80):
count = rng.randint(0, 150)
parts = []
for _ in range(count):
parts.append(" ".join(rng.choice(words) for _ in range(rng.randint(0, 12))))
parts.append(rng.choice(seps) if rng.random() < 0.3 else "\n")
text = "".join(parts)
cases.append({"text": text, "max_lines": rng.choice([60, 7, 13, 1, 2]), "overlap": rng.choice([3, 0, 1, 5]), "max_chars": rng.choice([4000, 120, 300, 17])})
return cases
def fts_cases():
return ["", "hello world", "Hello, World!", "café naïve", "Kelvin", "İstanbul", "a-b_c d.e", "UPPER lower 123", " ", "!!!", "x", "\"quoted\" 'single'", "tab\tsep\nnl", "éè ü", "snake_case_word", "alpha1beta2"]
def main():
write("json_cases.json", json_cases())
write("datetime_cases.json", datetime_cases())
write("duration_cases.json", duration_cases())
write("delay_cases.json", delay_cases())
write("chunk_cases.json", chunk_cases())
write("fts_cases.json", fts_cases())
print("wrote %s" % OUT)
main()
+34
View File
@@ -0,0 +1,34 @@
# Standalone build of the misc modules (skills, sched, telegram, rag, install) and their tests.
# Usage (from taicpp/): make -f tests/misc.mk test
# The integrator can fold these into the main Makefile; see docs/wiring/misc.md.
CXX ?= g++
CXXFLAGS ?= -std=c++23 -Wall -Wextra -O1
B = build/misc
DIRS = src/skills src/sched src/telegram src/rag src/install
INC = $(foreach d,$(DIRS),-I$d)
SRCS = $(foreach d,$(DIRS),$(wildcard $(d)/*.cpp))
OBJS = $(patsubst %.cpp,$(B)/%.o,$(SRCS))
LIBS = -lsqlite3 -lcurl -lz -lpthread
all: $(B)/misc_test $(B)/misc_driver
$(B)/%.o: %.cpp
@mkdir -p $(dir $@)
$(CXX) $(CXXFLAGS) $(INC) -MMD -MP -c $< -o $@
$(B)/misc_test: tests/misc_test.cpp $(OBJS)
@mkdir -p $(B)
$(CXX) $(CXXFLAGS) $(INC) tests/misc_test.cpp $(OBJS) $(LIBS) -o $@
$(B)/misc_driver: tests/misc_driver.cpp $(OBJS)
@mkdir -p $(B)
$(CXX) $(CXXFLAGS) $(INC) tests/misc_driver.cpp $(OBJS) $(LIBS) -lz -o $@
test: $(B)/misc_test
$(B)/misc_test
objs: $(OBJS)
.PHONY: all test objs
-include $(OBJS:.o=.d)
+273
View File
@@ -0,0 +1,273 @@
#!/usr/bin/env python3
"""Differential test of the misc modules: runs each scenario through the real tai.py (tests/misc_py.py)
and through the C++ driver (build/misc/misc_driver) on identical state, then diffs the transcripts and
the resulting file trees.
Usage (from taicpp/): python3 tests/misc_diff.py [scenario ...] (build first: make -f tests/misc.mk all)
Exit code 0 only when every selected scenario matches byte for byte after path/timestamp normalising.
"""
import difflib
import http.server
import json
import threading
import hashlib
import os
import re
import shutil
import subprocess
import sys
import tempfile
HERE = os.path.dirname(os.path.abspath(__file__))
TAICPP = os.path.dirname(HERE)
DRIVER = os.path.join(TAICPP, "build", "misc", "misc_driver")
PYDRV = os.path.join(HERE, "misc_py.py")
DATA = os.path.join(HERE, "misc_data")
ORDER = ["json", "datetime", "chunk", "fts", "skills_data", "skills_files", "skills_ops", "install_hooks", "install_hooks_noshell", "install_ops",
"install_noengine", "vault_line", "sched", "rag", "telegram", "telegram_install", "release", "audit"]
EXTRA_BIN = {"install_hooks": ("zsh", "fish")} # scenario -> extra executables to create in the restricted PATH dir
TZ = "Europe/Amsterdam"
TS_RE = re.compile(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:[+-]\d{2}:\d{2})?")
STAMP_RE = re.compile(r"\d{8}T\d{6}Z")
PID_RE = re.compile(r"\.tmp-\d+")
TG_UPDATES = [
{"update_id": 10, "message": {"chat": {"id": 111}, "text": "/start"}},
{"update_id": 11, "message": {"chat": {"id": 111}, "text": "hello there"}},
{"update_id": 12, "message": {"chat": {"id": 222}, "voice": {"file_id": "f1"}}},
{"update_id": 13, "message": {"chat": {"id": 111}, "text": "explode now"}},
{"update_id": 14},
{"update_id": 15, "message": {"chat": {"id": 333}, "text": "/new"}},
{"update_id": 16, "message": {"chat": {"id": 111}, "text": "long"}},
{"message": {"chat": {"id": 5}, "text": "no update id"}},
]
class TgServer:
"""Scripted Bot API on localhost; records every request so both sides can be compared on the wire."""
def __init__(self):
self.log = []
self.polls = {}
outer = self
class H(http.server.BaseHTTPRequestHandler):
def log_message(self, *a):
pass
def reply(self, code, body, reason=None):
data = body if isinstance(body, bytes) else body.encode()
self.send_response(code, reason)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
def handle_any(self, method):
n = int(self.headers.get("Content-Length") or 0)
body = self.rfile.read(n).decode() if n else ""
outer.log.append("%s %s ct=%s body=%s" % (method, self.path, self.headers.get("Content-Type"), body))
path = self.path
if path.startswith("/file/bot"):
if path.endswith("voice/f1.oga"):
return self.reply(200, b"AUDIO")
if path.endswith("voice/fmodel.oga"):
return self.reply(200, b"OTHER")
return self.reply(404, "{}", "Not Found")
token, _, name = path[len("/bot"):].partition("/")
if token == "bad":
return self.reply(401, json.dumps({"ok": False, "description": "Unauthorized"}), "Unauthorized")
if token == "nojson" and name == "getMe":
return self.reply(200, "not json")
if name == "getMe":
return self.reply(200, json.dumps({"ok": True, "result": {} if token == "noname" else {"username": "tai_test_bot"}}))
if name == "getUpdates":
count = outer.polls[token] = outer.polls.get(token, 0) + 1
if count == 1:
return self.reply(200, json.dumps({"ok": True, "result": TG_UPDATES}))
return self.reply(502, "{}", "Bad Gateway")
if name == "getFile":
fid = json.loads(body).get("file_id")
if fid == "nofile":
return self.reply(200, json.dumps({"ok": True, "result": {}}))
if fid == "fbad":
return self.reply(500, "{}", "Internal Server Error")
if fid == "fmodel":
return self.reply(200, json.dumps({"ok": True, "result": {"file_path": "voice/fmodel.oga"}}))
if fid == "fmissingfile":
return self.reply(200, json.dumps({"ok": True, "result": {"file_path": "voice/gone.oga"}}))
return self.reply(200, json.dumps({"ok": True, "result": {"file_path": "voice/f1.oga"}}))
return self.reply(200, json.dumps({"ok": True, "result": {}}))
def do_POST(self):
self.handle_any("POST")
def do_GET(self):
self.handle_any("GET")
self.httpd = http.server.ThreadingHTTPServer(("127.0.0.1", 0), H)
self.port = self.httpd.server_address[1]
threading.Thread(target=self.httpd.serve_forever, daemon=True).start()
def stop(self):
self.httpd.shutdown()
self.httpd.server_close()
SERVER_SCENARIOS = {"telegram", "telegram_install"}
def normalize(text, root):
text = text.replace(root, "<ROOT>")
text = TS_RE.sub("<TS>", text)
text = STAMP_RE.sub("<STAMP>", text)
text = PID_RE.sub(".tmp-<PID>", text)
return text
def make_root(base, name, extra_bins):
root = os.path.join(base, name)
for sub in ("home/.tai", "proj", "bin"):
os.makedirs(os.path.join(root, sub), exist_ok=True)
os.symlink(sys.executable, os.path.join(root, "bin", "python3"))
for tool in extra_bins:
path = os.path.join(root, "bin", tool)
with open(path, "w") as handle:
handle.write("#!/bin/sh\nexit 0\n")
os.chmod(path, 0o755)
return root
def env_for(root):
return {
"HOME": os.path.join(root, "home"),
"TAI_HOME": os.path.join(root, "home", ".tai"),
"PATH": os.path.join(root, "bin"),
"TZ": TZ,
"LANG": "C.UTF-8",
"MISC_DATA_DIR": DATA,
"PYTHONIOENCODING": "utf-8",
"SHELL": "/bin/bash",
"MISC_TAI_PY": os.path.join(os.path.dirname(TAICPP), "tai.py"),
}
def tree(root):
found = {}
for dirpath, dirs, files in os.walk(root):
dirs.sort()
rel_dir = os.path.relpath(dirpath, root)
if rel_dir == "bin" or rel_dir.startswith("bin" + os.sep):
continue
if rel_dir.startswith(os.path.join("home", ".tai", "venv")):
continue # venv contents embed the invoking interpreter path; the report lines are compared instead
for d in dirs:
full = os.path.join(dirpath, d)
if os.path.islink(full):
found[os.path.relpath(full, root)] = "symlink -> " + normalize(os.readlink(full), root)
for f in files:
full = os.path.join(dirpath, f)
rel = os.path.relpath(full, root)
if os.path.islink(full):
found[rel] = "symlink -> " + normalize(os.readlink(full), root)
continue
with open(full, "rb") as handle:
raw = handle.read()
mode = oct(os.stat(full).st_mode & 0o777)
try:
body = normalize(raw.decode("utf-8"), root)
digest = hashlib.sha256(body.encode("utf-8")).hexdigest()[:16]
except UnicodeDecodeError:
digest = "bin-" + hashlib.sha256(raw).hexdigest()[:16]
if rel.endswith((".db", ".db-wal", ".db-shm")):
digest = "db"
found[normalize(rel, root)] = "%s %s" % (mode, digest)
return found
def run(cmd, root, extra_env=None):
env = env_for(root)
if extra_env:
env.update(extra_env)
done = subprocess.run(cmd, cwd=os.path.join(root, "proj"), env=env, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
start_new_session=True, timeout=600)
return done.returncode, done.stdout.decode("utf-8", "replace"), done.stderr.decode("utf-8", "replace")
def check(name, base, verbose):
root_py = make_root(base, name + "-py", EXTRA_BIN.get(name, ()))
code, _out, err = run([sys.executable, "-I", PYDRV, name, root_py, "prepare"], root_py)
if code != 0:
return False, "python prepare failed (%d): %s" % (code, err[-2000:])
root_cpp = os.path.join(base, name + "-cpp")
shutil.copytree(root_py, root_cpp, symlinks=True)
# copytree keeps absolute symlink targets; point the bin symlink at the same interpreter (already absolute)
def one(cmd, root):
if name not in SERVER_SCENARIOS:
return run(cmd, root)
srv = TgServer()
try:
extra = {"MISC_TG_API": "http://127.0.0.1:%d/bot" % srv.port, "MISC_TG_FILE": "http://127.0.0.1:%d/file/bot" % srv.port}
code, o, e = run(cmd, root, extra)
finally:
srv.stop()
o = o + "---- wire log\n" + "\n".join(l.replace(str(srv.port), "PORT") for l in srv.log)
if name == "telegram":
o += "\n---- stderr\n" + e
return code, o, ""
code_p, out_p, err_p = one([sys.executable, "-I", PYDRV, name, root_py], root_py)
code_c, out_c, err_c = one([DRIVER, name, root_cpp], root_cpp)
out_p = normalize(out_p, root_py)
out_c = normalize(out_c, root_cpp)
problems = []
if code_p != 0:
problems.append("python exit %d: %s" % (code_p, err_p[-2000:]))
if code_c != 0:
problems.append("cpp exit %d: %s" % (code_c, err_c[-2000:]))
if out_p != out_c:
diff = list(difflib.unified_diff(out_p.splitlines(), out_c.splitlines(), "python", "cpp", lineterm="", n=1))
problems.append("transcript differs (%d diff lines):\n%s" % (len(diff), "\n".join(diff[:60])))
tp, tc = tree(root_py), tree(root_cpp)
if tp != tc:
lines = []
for key in sorted(set(tp) | set(tc)):
if tp.get(key) != tc.get(key):
lines.append(" %s: py=%s cpp=%s" % (key, tp.get(key), tc.get(key)))
problems.append("file tree differs:\n%s" % "\n".join(lines[:60]))
if verbose:
sys.stdout.write("---- python transcript (%d lines)\n%s\n" % (len(out_p.splitlines()), out_p))
return not problems, "\n".join(problems), len(out_p.splitlines()), len(tp)
def main():
args = [a for a in sys.argv[1:] if not a.startswith("-")]
verbose = "-v" in sys.argv
if not os.path.isdir(DATA):
subprocess.run([sys.executable, "-I", os.path.join(HERE, "gen_misc_data.py")], check=True)
names = args or ORDER
base = tempfile.mkdtemp(prefix="misc-diff-")
failed = 0
try:
for name in names:
result = check(name, base, verbose)
ok, why = result[0], result[1]
if ok:
print("PASS %-14s transcript=%d lines, tree=%d files" % (name, result[2], result[3]))
else:
failed += 1
print("FAIL %s\n%s" % (name, why))
finally:
if "--keep" not in sys.argv:
shutil.rmtree(base, ignore_errors=True)
else:
print("kept %s" % base)
print("%d scenario(s), %d failed" % (len(names), failed))
return 1 if failed else 0
if __name__ == "__main__":
sys.exit(main())
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+29
View File
@@ -0,0 +1,29 @@
// Fast unit checks for the misc modules. The behavioral proof against tai.py is tests/misc_diff.py.
#include <cassert>
#include <cstdio>
#include "bundled.h"
#include "bundled_data.h"
#include "chunker.h"
#include "miscdatetime.h"
#include "miscjson.h"
#include "miscpy.h"
#include "miscsha256.h"
#include "schedtime.h"
#include "skillfile.h"
using namespace detz;
int main() {
assert(misc::Sha256::hex("abc") == "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
assert(misc::Sha256::hex("") == "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
assert(misc::Json::loads("{\"a\": [1, 2.5, \"\\u00e9\"]}").dumps() == "{\"a\": [1, 2.5, \"\\u00e9\"]}");
assert(misc::Json::float_repr(1e16) == "1e+16" && misc::Json::float_repr(0.0001) == "0.0001" && misc::Json::float_repr(1e-5) == "1e-05");
assert(misc::DateTime::fromisoformat("2026-10-08T09:00Z").isoformat() == "2026-10-08T09:00:00+00:00");
assert(sched::ScheduleTime::format_delay(3600) == "1h" && sched::ScheduleTime::format_delay(-1) == "overdue");
assert(*sched::ScheduleTime::parse_duration("2h") == 7200);
assert(rag::Chunker::chunk_lines("a\nb\nc", 2, 0, 100).size() == 2);
assert(skills::BundledData::files().size() == 6);
assert(skills::SkillFiles::skill_name_valid("deep-research") && !skills::SkillFiles::skill_name_valid("Bad"));
assert(skills::BundledSkills::names().size() == 6);
std::puts("misc_test ok");
return 0;
}