Port the 18 missing sleep_time.py functions name-preserving to src/go/sleep-time (kernels.go + kernel_dispatch.go) under the pure/IO split law: deterministic cores in Go, IO (db, files, subprocess, http, flock) behind injectable seams. 38-case branch truth (truth_gaps.json) frozen from the live oracle with a pinned clock and deep-copied inputs, replayed as a hard Go gate (truth_gaps_test.go) — 100% live parity on the new fns. Wire live RUNE_SLEEP_TIME_CORE delegation in the facade (_go_kernel JSON surface, 8 kernel call sites) with the python pin and binary-missing fallbacks; both modes green (pytest, both ways). Go fn coverage 8/26 -> 26/27 (the 27th is _go_kernel, the delegation glue itself).
560 lines
24 KiB
Python
560 lines
24 KiB
Python
#!/usr/bin/env python3
|
|
"""gen_sleep_time_truth.py — factory batch 11 + factory-gap-sleep truth
|
|
battery (live oracle). Emits:
|
|
src/go/sleep-time/truth_transcript.json (batch 11: extract_todos/transcript)
|
|
src/go/sleep-time/truth_gaps.json (gap-closing wave: the 18 missing
|
|
functions, every branch, pinned clock, deep-copied inputs)
|
|
"""
|
|
|
|
import copy
|
|
import datetime as _dt
|
|
import io
|
|
import json
|
|
import os
|
|
import sqlite3
|
|
import sys
|
|
import tempfile
|
|
import types
|
|
import urllib.request
|
|
from pathlib import Path
|
|
|
|
REPO = Path(__file__).resolve().parent.parent
|
|
sys.path.insert(0, str(REPO / "src"))
|
|
sys.path.insert(0, str(REPO / "src" / "rune"))
|
|
|
|
import sleep_time as st # noqa: E402
|
|
|
|
|
|
def make_parts_db(db_path):
|
|
db = sqlite3.connect(db_path)
|
|
db.execute("CREATE TABLE part (session_id TEXT, data TEXT, time_created TEXT)")
|
|
rows = [
|
|
("s1", '{"tool": "todowrite", "state": {"input": {"todos": [{"content": "first", "status": "completed", "priority": "high"}]}}}', "2026-10-07T10:00:00"),
|
|
("s1", '{"tool": "bash", "state": {"input": {"command": "ls"}}}', "2026-10-07T10:01:00"),
|
|
("s1", '{"tool": "todowrite", "state": {"input": {"todos": [{"content": "second", "status": "in_progress", "priority": "med"}, {"content": "third", "status": "pending", "priority": "low"}]}}}', "2026-10-07T10:02:00"),
|
|
("s1", '{"tool": "todowrite", "state": {"input": {"todos": []}}}', "2026-10-07T10:03:00"), # empty — skipped
|
|
("s1", '{"tool": "read_file", "state": {"input": {}}}', "2026-10-07T10:04:00"), # non-todowrite
|
|
("s2", '{"tool": "todowrite", "state": {"input": {"todos": [{"content": "other session", "status": "pending", "priority": ""}]}}}', "2026-10-07T11:00:00"),
|
|
]
|
|
db.executemany("INSERT INTO part VALUES (?,?,?)", rows)
|
|
db.commit()
|
|
return db
|
|
|
|
|
|
def main():
|
|
tmp = Path(tempfile.mkdtemp(prefix="st-truth-"))
|
|
db = make_parts_db(str(tmp / "p.db"))
|
|
|
|
cases = []
|
|
|
|
# extract_todos for s1 (ORDER BY time ASC → latest = the 10:02 todos)
|
|
rows = [{"data": r[0]} for r in db.execute(
|
|
"SELECT data FROM part WHERE session_id='s1' ORDER BY time_created ASC").fetchall()]
|
|
cases.append({"fn": "extract_todos", "name": "s1_latest",
|
|
"input": {"rows": rows},
|
|
"expected": {"todos": st.extract_todos(
|
|
_FakeConn(db, "s1"), "s1")}})
|
|
rows2 = [{"data": r[0]} for r in db.execute(
|
|
"SELECT data FROM part WHERE session_id='s2' ORDER BY time_created ASC").fetchall()]
|
|
cases.append({"fn": "extract_todos", "name": "s2",
|
|
"input": {"rows": rows2},
|
|
"expected": {"todos": st.extract_todos(
|
|
_FakeConn(db, "s2"), "s2")}})
|
|
rows3 = [{"data": r[0]} for r in db.execute(
|
|
"SELECT data FROM part WHERE session_id='nope' ORDER BY time_created ASC").fetchall()]
|
|
cases.append({"fn": "extract_todos", "name": "empty_session",
|
|
"input": {"rows": rows3},
|
|
"expected": {"todos": st.extract_todos(
|
|
_FakeConn(db, "nope"), "nope")}})
|
|
|
|
# write_transcript byte format
|
|
st.TRANSCRIPTS_DIR = str(tmp / "transcripts")
|
|
Path(st.TRANSCRIPTS_DIR).mkdir(parents=True, exist_ok=True)
|
|
todos = [{"content": "write the thing", "status": "completed", "priority": "high"},
|
|
{"content": "review it", "status": "in_progress", "priority": ""}]
|
|
parts = [("user", "do the task"), ("assistant", "done, verified")]
|
|
p1 = st.write_transcript("s1", "My Session: v2!", parts, todos)
|
|
cases.append({"fn": "transcript", "name": "full_shape",
|
|
"input": {},
|
|
"expected": {"content": Path(p1).read_text(),
|
|
"filename_stem": Path(p1).name}})
|
|
p2 = st.write_transcript("s2", "no todos", parts, None)
|
|
cases.append({"fn": "transcript", "name": "no_todos",
|
|
"input": {},
|
|
"expected": {"content": Path(p2).read_text()}})
|
|
|
|
out = {"oracle": "sleep_time.extract_todos/write_transcript (live)",
|
|
"generated": "2026-10-08", "cases": cases}
|
|
(REPO / "src/go/sleep-time" / "truth_transcript.json").write_text(
|
|
json.dumps(out, indent=1) + "\n")
|
|
print(f"wrote {len(cases)} cases")
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# factory-gap-sleep: branch truth for the 18 gap functions (live oracle).
|
|
# Pinned clock: st.datetime.now / st.time.time are frozen; now is always an
|
|
# explicit kernel argument. Inputs are deep-copied before touching the oracle.
|
|
# ---------------------------------------------------------------------------
|
|
|
|
PINNED_DT = _dt.datetime(2026, 10, 12, 3, 4, 5, tzinfo=_dt.timezone.utc)
|
|
PINNED_SEC = 1792472645.25
|
|
|
|
|
|
class _PinnedDatetime(_dt.datetime):
|
|
@classmethod
|
|
def now(cls, tz=None):
|
|
if tz is not None:
|
|
return PINNED_DT.astimezone(tz)
|
|
return PINNED_DT.replace(tzinfo=None)
|
|
|
|
|
|
def _capture_urlopen(captured, response_body):
|
|
def fake_urlopen(req, timeout=None):
|
|
captured.append(json.loads(req.data.decode()))
|
|
return io.BytesIO(response_body)
|
|
return fake_urlopen
|
|
|
|
|
|
def gen_gaps():
|
|
cases = []
|
|
tmp = Path(tempfile.mkdtemp(prefix="st-gaps-"))
|
|
|
|
# ── _is_transient: first marker, last marker, mixed case, clean, empty ──
|
|
for name, text, want in [
|
|
("first_marker", "the health status page was checked", True),
|
|
("last_marker", "nothing here about verification of the fix", True),
|
|
("mixed_case", "TODO LIST is long", True),
|
|
("clean", "the user prefers concise answers about rust", False),
|
|
("empty", "", False),
|
|
]:
|
|
got = st._is_transient(copy.deepcopy(text))
|
|
cases.append({"fn": "is_transient", "name": name,
|
|
"input": {"text": text},
|
|
"expected": {"transient": got}})
|
|
assert got == want, (name, got)
|
|
|
|
# ── retain_to_store ──
|
|
r = st.retain_to_store(copy.deepcopy("doc-1"), copy.deepcopy("body text"))
|
|
cases.append({"fn": "retain_to_store", "name": "constant",
|
|
"input": {"document_id": "doc-1", "content": "body text"},
|
|
"expected": {"result": r}})
|
|
|
|
# ── handle_hook ──
|
|
r1 = st.handle_hook("on_schedule", copy.deepcopy({"k": 1}))
|
|
r2 = st.handle_hook("on_tick")
|
|
cases.append({"fn": "handle_hook", "name": "with_data",
|
|
"input": {"event": "on_schedule", "data": {"k": 1}},
|
|
"expected": r1})
|
|
cases.append({"fn": "handle_hook", "name": "no_data",
|
|
"input": {"event": "on_tick"}, "expected": r2})
|
|
|
|
# ── should_defer (heavy-job probe patched: IO stays on the caller) ──
|
|
orig_heavy = st._heavy_job_running
|
|
st._heavy_job_running = lambda: True
|
|
try:
|
|
d1, r1s = st.should_defer()
|
|
finally:
|
|
st._heavy_job_running = orig_heavy
|
|
st._heavy_job_running = lambda: False
|
|
try:
|
|
d2, r2s = st.should_defer()
|
|
finally:
|
|
st._heavy_job_running = orig_heavy
|
|
cases.append({"fn": "should_defer", "name": "heavy_running",
|
|
"input": {"heavy_running": True},
|
|
"expected": {"defer": d1, "reason": r1s}})
|
|
cases.append({"fn": "should_defer", "name": "clear",
|
|
"input": {"heavy_running": False},
|
|
"expected": {"defer": d2, "reason": r2s}})
|
|
|
|
# ── write_status: pinned clock, phase/note present and None ──
|
|
orig_status = st.STATUS_FILE
|
|
st.STATUS_FILE = str(tmp / "status.json")
|
|
try:
|
|
old_datetime = st.datetime
|
|
st.datetime = _PinnedDatetime
|
|
try:
|
|
st.write_status("mining", "extract", "title one")
|
|
body1 = json.loads(Path(st.STATUS_FILE).read_text())
|
|
st.write_status("idle", None, None)
|
|
body2 = json.loads(Path(st.STATUS_FILE).read_text())
|
|
finally:
|
|
st.datetime = old_datetime
|
|
finally:
|
|
st.STATUS_FILE = orig_status
|
|
now_ms = PINNED_DT.timestamp() * 1000
|
|
cases.append({"fn": "status_body", "name": "full",
|
|
"input": {"now_ms": now_ms, "state": "mining",
|
|
"phase": "extract", "note": "title one"},
|
|
"expected": body1})
|
|
cases.append({"fn": "status_body", "name": "nulls",
|
|
"input": {"now_ms": now_ms, "state": "idle",
|
|
"phase": None, "note": None},
|
|
"expected": body2})
|
|
|
|
# ── write_reflection: append format + filename ──
|
|
orig_reflect = st.REFLECT_DIR
|
|
st.REFLECT_DIR = str(tmp / "reflect")
|
|
os.makedirs(st.REFLECT_DIR, exist_ok=True)
|
|
try:
|
|
lines = ["## Sleep-time run x", "- session: 3 parts", ""]
|
|
p1 = st.write_reflection("2026-10-12", copy.deepcopy(lines))
|
|
content1 = Path(p1).read_text()
|
|
p2 = st.write_reflection("2026-10-12", ["second run"])
|
|
content2 = Path(p2).read_text()
|
|
finally:
|
|
st.REFLECT_DIR = orig_reflect
|
|
cases.append({"fn": "write_reflection", "name": "append_lines",
|
|
"input": {"date": "2026-10-12", "lines": lines},
|
|
"expected": {"content": content1, "filename": Path(p1).name}})
|
|
cases.append({"fn": "write_reflection", "name": "second_append",
|
|
"input": {"date": "2026-10-12", "lines": ["second run"]},
|
|
"expected": {"content": content2, "filename": Path(p2).name}})
|
|
|
|
# ── fetch_sessions: by-id branch SQL + the since cutoff (pinned clock) ──
|
|
class _CaptureConn:
|
|
def __init__(self):
|
|
self.calls = []
|
|
|
|
def execute(self, sql, params):
|
|
self.calls.append((sql, list(params)))
|
|
|
|
class Cur:
|
|
def fetchall(self):
|
|
return [("s1", "t", "d", 1, 2)]
|
|
return Cur()
|
|
|
|
cc = _CaptureConn()
|
|
old_datetime = st.datetime
|
|
st.datetime = _PinnedDatetime
|
|
try:
|
|
rows = st.fetch_sessions(cc, hours=24)
|
|
finally:
|
|
st.datetime = old_datetime
|
|
sql, params = cc.calls[0]
|
|
cases.append({"fn": "fetch_sessions_window", "name": "since_branch",
|
|
"input": {"now_ms": now_ms, "hours": 24,
|
|
"sql_spaceless": " ".join(sql.split())},
|
|
"expected": {"since": params[0], "rows": [list(rows[0])]}})
|
|
cc2 = _CaptureConn()
|
|
st.fetch_sessions(cc2, session_id="abc-123")
|
|
sql2, params2 = cc2.calls[0]
|
|
cases.append({"fn": "fetch_sessions_by_id", "name": "id_branch",
|
|
"input": {"session_id": "abc-123",
|
|
"sql": sql2},
|
|
"expected": {"params": params2}})
|
|
|
|
# ── reflect_local: default query, payload shape, trim 800, error branch ──
|
|
captured = []
|
|
long_text = "x" * 900
|
|
orig_urlopen = urllib.request.urlopen
|
|
urllib.request.urlopen = _capture_urlopen(
|
|
captured, json.dumps({"response": " " + long_text + "\n"}).encode())
|
|
try:
|
|
out = st.reflect_local()
|
|
finally:
|
|
urllib.request.urlopen = orig_urlopen
|
|
payload1 = captured[0]
|
|
cases.append({"fn": "reflect_default_query", "name": "query_none",
|
|
"input": {},
|
|
"expected": {"query": payload1["prompt"]}})
|
|
cases.append({"fn": "reflect_payload", "name": "default",
|
|
"input": {"model": payload1["model"], "num_ctx": payload1["options"]["num_ctx"]},
|
|
"expected": {"payload": payload1, "output": out}})
|
|
|
|
captured.clear()
|
|
urllib.request.urlopen = _capture_urlopen(
|
|
captured, json.dumps({"response": "no response key here"}).replace("no response key here", "").encode() or b"{}")
|
|
urllib.request.urlopen = _capture_urlopen(captured, b"{}")
|
|
try:
|
|
out2 = st.reflect_local("explicit query?")
|
|
finally:
|
|
urllib.request.urlopen = orig_urlopen
|
|
cases.append({"fn": "reflect_payload", "name": "empty_response",
|
|
"input": {"model": captured[0]["model"], "query": "explicit query?",
|
|
"num_ctx": captured[0]["options"]["num_ctx"]},
|
|
"expected": {"payload": captured[0], "output": out2}})
|
|
|
|
captured.clear()
|
|
orig_urlopen = urllib.request.urlopen
|
|
urllib.request.urlopen = _capture_urlopen(captured, b"not json at all")
|
|
try:
|
|
out3 = st.reflect_local("q")
|
|
finally:
|
|
urllib.request.urlopen = orig_urlopen
|
|
cases.append({"fn": "reflect_error", "name": "bad_json",
|
|
"input": {},
|
|
"expected": {"prefix": "[reflect failed: ", "output": out3}})
|
|
|
|
# ── _recent_interaction_material: branch-crafted transcripts ──
|
|
texts = {
|
|
"a_normal.md": ("# t\n\n### user\n\nplease look at the deploy logs "
|
|
"carefully today\n\n### assistant\n\nI checked the "
|
|
"deploy logs and found the crash quickly\n"),
|
|
"b_short.md": "### user\n\nshort\n\n### assistant\n\nok\n",
|
|
"c_mempalace.md": "### user\n\nthe mempalace archive wing is huge "
|
|
"and full of interesting material\n",
|
|
"d_tool_prefix.md": "### assistant\n\ntool output was captured here "
|
|
"and it is long enough to matter\n",
|
|
"e_long.md": "### user\n\n" + ("y" * 500) + "\n",
|
|
}
|
|
tdir = tmp / "transcripts"
|
|
tdir.mkdir(parents=True)
|
|
for i, (fn, txt) in enumerate(sorted(texts.items())):
|
|
(tdir / fn).write_text(txt)
|
|
# explicit mtimes: creation order ascending -> mtime-desc = reverse
|
|
os.utime(tdir / fn, (PINNED_SEC - 100 - i, PINNED_SEC - 100 - i))
|
|
orig_transcripts = st.TRANSCRIPTS_DIR
|
|
orig_env = os.environ.get("MEMORY_REFLECT_TRANSCRIPTS")
|
|
st.TRANSCRIPTS_DIR = str(tdir)
|
|
try:
|
|
os.environ["MEMORY_REFLECT_TRANSCRIPTS"] = "6"
|
|
m_all = st._recent_interaction_material(5000)
|
|
m_cap = st._recent_interaction_material(80)
|
|
os.environ["MEMORY_REFLECT_TRANSCRIPTS"] = "2"
|
|
m_two = st._recent_interaction_material(5000)
|
|
finally:
|
|
st.TRANSCRIPTS_DIR = orig_transcripts
|
|
if orig_env is None:
|
|
os.environ.pop("MEMORY_REFLECT_TRANSCRIPTS", None)
|
|
else:
|
|
os.environ["MEMORY_REFLECT_TRANSCRIPTS"] = orig_env
|
|
# the oracle orders files mtime-desc — a_normal carries the newest mtime,
|
|
# so that order is the plain sorted() one; the kernel input uses the same
|
|
tlist = [{"name": n, "text": texts[n]} for n in sorted(texts)]
|
|
cases.append({"fn": "interaction_material", "name": "all_files",
|
|
"input": {"texts": copy.deepcopy(tlist), "n": 6, "max_chars": 5000},
|
|
"expected": {"material": m_all}})
|
|
cases.append({"fn": "interaction_material", "name": "max_chars_cap",
|
|
"input": {"texts": copy.deepcopy(tlist), "n": 6, "max_chars": 80},
|
|
"expected": {"material": m_cap}})
|
|
cases.append({"fn": "interaction_material", "name": "n_cap",
|
|
"input": {"texts": copy.deepcopy(tlist), "n": 2, "max_chars": 5000},
|
|
"expected": {"material": m_two}})
|
|
|
|
# ── _ctx_budget: the num_ctx pass-through seam (registry output frozen) ──
|
|
for model in ("qwen2.5:3b", "totally-unknown-model"):
|
|
budget = st._ctx_budget(model)
|
|
cases.append({"fn": "ctx_budget", "name": model.replace(".", "_").replace("-", "_"),
|
|
"input": {"model_id": model, "num_ctx": budget},
|
|
"expected": {"num_ctx": budget}})
|
|
|
|
# ── _active_window_seconds: real ro-sqlite, pinned clock ──
|
|
dbp = tmp / "oc.db"
|
|
db = sqlite3.connect(str(dbp))
|
|
db.execute("CREATE TABLE message (time_created INTEGER)")
|
|
db.execute("INSERT INTO message VALUES (1792472000000)")
|
|
db.commit()
|
|
db.close()
|
|
orig_db, orig_time_mod = st.DB, st.time
|
|
st.DB = str(dbp)
|
|
st.time = types.SimpleNamespace(time=lambda: PINNED_SEC)
|
|
try:
|
|
secs = st._active_window_seconds()
|
|
finally:
|
|
st.DB, st.time = orig_db, orig_time_mod
|
|
cases.append({"fn": "active_window", "name": "has_activity",
|
|
"input": {"last_ms": 1792472000000, "now_ms": PINNED_SEC * 1000},
|
|
"expected": {"seconds": secs}})
|
|
dbp2 = tmp / "oc2.db"
|
|
db = sqlite3.connect(str(dbp2))
|
|
db.execute("CREATE TABLE message (time_created INTEGER)")
|
|
db.commit()
|
|
db.close()
|
|
st.DB = str(dbp2)
|
|
st.time = types.SimpleNamespace(time=lambda: PINNED_SEC)
|
|
try:
|
|
secs2 = st._active_window_seconds()
|
|
finally:
|
|
st.DB, st.time = orig_db, orig_time_mod
|
|
assert secs2 == float("inf")
|
|
cases.append({"fn": "active_window", "name": "idle_forever",
|
|
"input": {"last_ms": None, "now_ms": PINNED_SEC * 1000},
|
|
"expected": {"seconds": None}})
|
|
|
|
# ── _heavy_job_running: pgrep stdout present/empty ──
|
|
orig_run = st.subprocess.run
|
|
st.subprocess.run = lambda *a, **k: types.SimpleNamespace(stdout="1234 pgrep target\n")
|
|
try:
|
|
h1 = st._heavy_job_running()
|
|
st.subprocess.run = lambda *a, **k: types.SimpleNamespace(stdout=" \n")
|
|
h2 = st._heavy_job_running()
|
|
finally:
|
|
st.subprocess.run = orig_run
|
|
cases.append({"fn": "heavy_job_running", "name": "found",
|
|
"input": {"pgrep_stdout": "1234 pgrep target\n"},
|
|
"expected": {"running": h1}})
|
|
cases.append({"fn": "heavy_job_running", "name": "blank",
|
|
"input": {"pgrep_stdout": " \n"},
|
|
"expected": {"running": h2}})
|
|
|
|
# ── curator_extract_evidence: success + degrade ──
|
|
orig_lm = sys.modules.get("local_memory")
|
|
ev = [{"fact": "user prefers rust", "target": "operating", "strength": 3}]
|
|
sys.modules["local_memory"] = types.SimpleNamespace(
|
|
evidence_items=lambda: copy.deepcopy(ev))
|
|
try:
|
|
items1 = st.curator_extract_evidence()
|
|
finally:
|
|
if orig_lm is not None:
|
|
sys.modules["local_memory"] = orig_lm
|
|
else:
|
|
del sys.modules["local_memory"]
|
|
sys.modules["local_memory"] = types.SimpleNamespace(
|
|
evidence_items=lambda: (_ for _ in ()).throw(RuntimeError("boom")))
|
|
try:
|
|
items2 = st.curator_extract_evidence()
|
|
finally:
|
|
if orig_lm is not None:
|
|
sys.modules["local_memory"] = orig_lm
|
|
else:
|
|
del sys.modules["local_memory"]
|
|
cases.append({"fn": "curator_extract_evidence", "name": "success",
|
|
"input": {"items": copy.deepcopy(ev)},
|
|
"expected": {"items": items1}})
|
|
cases.append({"fn": "curator_extract_evidence", "name": "degrade",
|
|
"input": {"error": "boom"},
|
|
"expected": {"items": items2}})
|
|
|
|
# ── curator_run: empty short-circuit, apply cmd, dry-run cmd ──
|
|
s0, f0 = st.curator_run([], apply=True)
|
|
cases.append({"fn": "curator_run", "name": "empty",
|
|
"input": {"items": [], "apply": True},
|
|
"expected": {"summary": s0, "ev_file": f0}})
|
|
runs = []
|
|
|
|
def fake_run(cmd, capture_output=None, text=None, timeout=None):
|
|
runs.append(list(cmd))
|
|
return types.SimpleNamespace(stdout="curator ok output\n", stderr="")
|
|
orig_run = st.subprocess.run
|
|
st.subprocess.run = fake_run
|
|
ev_items = [{"fact": "durable fact one", "strength": 2}]
|
|
try:
|
|
s1, f1 = st.curator_run(copy.deepcopy(ev_items), apply=True)
|
|
s2, f2 = st.curator_run(copy.deepcopy(ev_items), apply=False)
|
|
finally:
|
|
st.subprocess.run = orig_run
|
|
cases.append({"fn": "curator_run", "name": "apply_cmd",
|
|
"input": {"items": ev_items, "apply": True,
|
|
"python_bin": runs[0][0], "curator_path": runs[0][1],
|
|
"stdout": "curator ok output\n", "stderr": ""},
|
|
"expected": {"summary": s1, "ev_file_suffix": os.path.basename(f1), "cmd": runs[0]}})
|
|
cases.append({"fn": "curator_run", "name": "dry_run_cmd",
|
|
"input": {"items": ev_items, "apply": False,
|
|
"python_bin": runs[1][0], "curator_path": runs[1][1],
|
|
"stdout": "curator ok output\n", "stderr": ""},
|
|
"expected": {"summary": s2, "ev_file_suffix": os.path.basename(f2), "cmd": runs[1]}})
|
|
|
|
# ── run_abstraction: window selection, short-file skip, last-5, parse ──
|
|
atmp = Path(tempfile.mkdtemp(prefix="st-gaps-abs-"))
|
|
adir = atmp / "transcripts"
|
|
adir.mkdir(parents=True)
|
|
files = {}
|
|
for i in range(7):
|
|
name = f"t{i}.md"
|
|
content = ("z" * 250) + f" number {i}"
|
|
(adir / name).write_text(content)
|
|
files[name] = content
|
|
(adir / "old.md").write_text("z" * 250)
|
|
os.utime(adir / "old.md", (PINNED_SEC - 100000, PINNED_SEC - 100000))
|
|
(adir / "short.md").write_text("tiny")
|
|
for i in range(7):
|
|
os.utime(adir / f"t{i}.md", (PINNED_SEC - 100 - i, PINNED_SEC - 100 - i))
|
|
os.utime(adir / "short.md", (PINNED_SEC - 90, PINNED_SEC - 90))
|
|
|
|
extraction = {}
|
|
|
|
def fake_abs_run(cmd, capture_output=None, text=None, timeout=None):
|
|
src = cmd[cmd.index("--source") + 1]
|
|
extraction[src] = 10 - int(src.split(".")[0][1:])
|
|
return types.SimpleNamespace(
|
|
stdout=json.dumps({"extracted": extraction[src]}), returncode=0)
|
|
|
|
orig_mem, orig_time_mod, orig_run = st.MEM_DIR, st.time, st.subprocess.run
|
|
st.MEM_DIR = str(atmp)
|
|
st.time = types.SimpleNamespace(time=lambda: PINNED_SEC)
|
|
st.subprocess.run = fake_abs_run
|
|
try:
|
|
total = st.run_abstraction()
|
|
finally:
|
|
st.MEM_DIR, st.time, st.subprocess.run = orig_mem, orig_time_mod, orig_run
|
|
recent_expected = [f"t{i}.md" for i in range(7)]
|
|
cases.append({"fn": "run_abstraction", "name": "window_and_cap",
|
|
"input": {
|
|
"entries": [
|
|
{"name": "old.md", "mtime": PINNED_SEC - 100000},
|
|
{"name": "short.md", "mtime": PINNED_SEC - 90},
|
|
{"name": "short2.md", "mtime": PINNED_SEC - 95},
|
|
] + [{"name": f"t{i}.md", "mtime": PINNED_SEC - 100 - i} for i in range(7)],
|
|
"contents": dict(
|
|
[(f"t{i}.md", files[f"t{i}.md"]) for i in range(7)]
|
|
+ [("old.md", "z" * 250), ("short.md", "tiny"),
|
|
("short2.md", "s" * 210)],
|
|
),
|
|
"extractions": {f"t{i}.md": 10 - i for i in range(7)},
|
|
"now_sec": PINNED_SEC,
|
|
},
|
|
"expected": {"total": total}})
|
|
|
|
# ── _ensure_dirs ──
|
|
# relative names — the replay joins them to its own base (the frozen
|
|
# expectation is just "all three exist after the call")
|
|
dirs = ["reflect", "transcripts", "index"]
|
|
abs_dirs = [str(tmp / d) for d in dirs]
|
|
orig_dirs = (st.REFLECT_DIR, st.TRANSCRIPTS_DIR, st.EVIDENCE_DIR)
|
|
st.REFLECT_DIR, st.TRANSCRIPTS_DIR, st.EVIDENCE_DIR = abs_dirs
|
|
try:
|
|
st._ensure_dirs()
|
|
finally:
|
|
st.REFLECT_DIR, st.TRANSCRIPTS_DIR, st.EVIDENCE_DIR = orig_dirs
|
|
cases.append({"fn": "ensure_dirs", "name": "creates_all",
|
|
"input": {"dirs": dirs},
|
|
"expected": {"exists": [os.path.isdir(d) for d in abs_dirs]}})
|
|
|
|
# ── acquire_single_lock: free then contended ──
|
|
orig_mem = st.MEM_DIR
|
|
st.MEM_DIR = str(tmp / "mem")
|
|
try:
|
|
h = st.acquire_single_lock()
|
|
first = h is not None
|
|
second = st.acquire_single_lock() is not None
|
|
finally:
|
|
st.MEM_DIR = orig_mem
|
|
cases.append({"fn": "acquire_single_lock", "name": "free_then_contended",
|
|
"input": {},
|
|
"expected": {"first": first, "second": second}})
|
|
assert first and not second
|
|
|
|
# ── db_connect: read-only DSN ──
|
|
cases.append({"fn": "db_connect_dsn", "name": "readonly",
|
|
"input": {"db_path": "/data/opencode.db"},
|
|
"expected": {"dsn": f"file:{st.DB if False else '/data/opencode.db'}?mode=ro"}})
|
|
|
|
out = {"oracle": "sleep_time gap fns (live)",
|
|
"generated": "2026-10-13", "cases": cases}
|
|
(REPO / "src/go/sleep-time" / "truth_gaps.json").write_text(
|
|
json.dumps(out, indent=1) + "\n")
|
|
print(f"wrote {len(cases)} gap cases")
|
|
|
|
|
|
class _FakeConn:
|
|
def __init__(self, db, session_id):
|
|
self.db = db
|
|
self.session_id = session_id
|
|
|
|
def execute(self, sql, params):
|
|
# replicate the oracle's query (session-filtered, time-ordered)
|
|
class Cur:
|
|
def __init__(self, rows):
|
|
self.rows = rows
|
|
|
|
def fetchall(self):
|
|
return self.rows
|
|
|
|
return Cur(self.db.execute(sql, params).fetchall())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
gen_gaps()
|