Merge worktree-typed: increment 2 — rings 2-4
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled

This commit is contained in:
2026-03-12 01:45:35 +00:00
2 changed files with 276 additions and 9 deletions

View File

@@ -64,6 +64,9 @@
(when (> (get stats "render-count") 0)
(span :class "bg-sky-100 text-sky-700 px-2 py-0.5 rounded"
(str (get stats "render-count") " render")))
(when (> (get stats "test-total") 0)
(span :class "bg-violet-100 text-violet-700 px-2 py-0.5 rounded"
(str (get stats "test-total") " tests")))
(span :class "bg-stone-100 text-stone-500 px-2 py-0.5 rounded"
(str (get stats "lines") " lines"))))
@@ -85,7 +88,7 @@
;; ---------------------------------------------------------------------------
;; Define card — one function/constant
;; Define card — one function/constant with all five rings
;; ---------------------------------------------------------------------------
(defcomp ~spec-explorer-define (&key d)
@@ -105,10 +108,22 @@
(when (not (empty? (get d "params")))
(~spec-param-list :params (get d "params")))
;; Translation panels
;; Ring 2: Translation panels (SX + Python + JavaScript + Z3)
(~spec-ring-translations
:source (get d "source")
:python (get d "python"))))
:python (get d "python")
:javascript (get d "javascript")
:z3 (get d "z3"))
;; Ring 3: Cross-references
(when (not (empty? (get d "refs")))
(~spec-ring-bridge :refs (get d "refs")))
;; Ring 4: Tests
(when (> (get d "test-count") 0)
(~spec-ring-runtime
:tests (get d "tests")
:test-count (get d "test-count")))))
;; ---------------------------------------------------------------------------
@@ -146,29 +161,76 @@
;; ---------------------------------------------------------------------------
;; Translation panels (Ring 2)
;; Ring 2: Translation panels (nucleus + bootstrapper)
;; ---------------------------------------------------------------------------
(defcomp ~spec-ring-translations (&key source python)
(defcomp ~spec-ring-translations (&key source python javascript z3)
(when (not (= source ""))
(div :class "mt-3 border border-stone-200 rounded-lg overflow-hidden"
;; SX source — always open
;; SX source — Ring 1: the nucleus (always open)
(details :open "true"
(summary :class "px-3 py-1.5 bg-stone-50 text-xs font-medium text-stone-600 cursor-pointer"
"SX")
(pre :class "text-xs p-3 overflow-x-auto bg-white"
(code (highlight source "sx"))))
;; Python
;; Python — Ring 2: bootstrapper
(when python
(details
(summary :class "px-3 py-1.5 bg-stone-50 text-xs font-medium text-stone-600 cursor-pointer border-t border-stone-200"
"Python")
(pre :class "text-xs p-3 overflow-x-auto bg-white"
(code (highlight python "python"))))))))
(code (highlight python "python")))))
;; JavaScript — Ring 2: bootstrapper
(when javascript
(details
(summary :class "px-3 py-1.5 bg-stone-50 text-xs font-medium text-stone-600 cursor-pointer border-t border-stone-200"
"JavaScript")
(pre :class "text-xs p-3 overflow-x-auto bg-white"
(code (highlight javascript "javascript")))))
;; Z3 / SMT-LIB — Ring 2: formal translation
(when z3
(details
(summary :class "px-3 py-1.5 bg-stone-50 text-xs font-medium text-stone-600 cursor-pointer border-t border-stone-200"
"Z3 / SMT-LIB")
(pre :class "text-xs p-3 overflow-x-auto bg-white"
(code (highlight z3 "lisp"))))))))
;; ---------------------------------------------------------------------------
;; Platform interface table (Ring 3)
;; Ring 3: Cross-references (bridge)
;; ---------------------------------------------------------------------------
(defcomp ~spec-ring-bridge (&key refs)
(div :class "mt-2"
(span :class "text-xs font-medium text-stone-500" "References")
(div :class "flex flex-wrap gap-1 mt-1"
(map (fn (ref)
(a :href (str "#fn-" ref)
:class "text-xs px-1.5 py-0.5 rounded bg-stone-100 text-stone-600 font-mono hover:bg-stone-200"
ref))
refs))))
;; ---------------------------------------------------------------------------
;; Ring 4: Tests (runtime)
;; ---------------------------------------------------------------------------
(defcomp ~spec-ring-runtime (&key tests test-count)
(div :class "mt-2"
(div :class "flex items-center gap-1"
(span :class "text-xs font-medium text-stone-500" "Tests")
(span :class "text-xs px-1.5 py-0.5 rounded bg-violet-100 text-violet-700"
(str test-count)))
(ul :class "mt-1 text-xs text-stone-500 list-none"
(map (fn (t)
(li :class "flex items-center gap-1"
(span :class "text-green-500 text-xs" "●")
(get t "name")))
tests))))
;; ---------------------------------------------------------------------------
;; Platform interface table (Ring 3 overview)
;; ---------------------------------------------------------------------------
(defcomp ~spec-platform-interface (&key items)

View File

@@ -172,6 +172,163 @@ def _read_spec_file(filename: str) -> str:
return ";; spec file not found"
# ---------------------------------------------------------------------------
# Spec explorer — translation + cross-reference helpers
# ---------------------------------------------------------------------------
_JS_SX_ENV = None # cached js.sx evaluator env
def _js_translate_define(expr: list, name: str) -> str | None:
"""Translate a single define expression to JavaScript via js.sx."""
global _JS_SX_ENV
if _JS_SX_ENV is None:
from shared.sx.ref.run_js_sx import load_js_sx
_JS_SX_ENV = load_js_sx()
from shared.sx.ref.sx_ref import evaluate
from shared.sx.types import Symbol
env = dict(_JS_SX_ENV)
env["_defines"] = [[name, expr]]
result = evaluate([Symbol("js-translate-file"), Symbol("_defines")], env)
if result and isinstance(result, str) and result.strip():
return result.strip()
return None
def _z3_translate_define(expr: list) -> str | None:
"""Translate a single define expression to SMT-LIB via z3.sx."""
from shared.sx.ref.reader_z3 import z3_translate
result = z3_translate(expr)
if result and isinstance(result, str) and result.strip():
return result.strip()
return None
_SPEC_INDEX: dict[str, str] | None = None # function name → spec slug
def _build_spec_index() -> dict[str, str]:
"""Build a global index mapping function names to spec file slugs."""
global _SPEC_INDEX
if _SPEC_INDEX is not None:
return _SPEC_INDEX
import os
import glob as globmod
from shared.sx.parser import parse_all
from shared.sx.types import Symbol, Keyword
ref_dir = os.path.join(os.path.dirname(__file__), "..", "..", "shared", "sx", "ref")
if not os.path.isdir(ref_dir):
ref_dir = "/app/shared/sx/ref"
index: dict[str, str] = {}
for fp in globmod.glob(os.path.join(ref_dir, "*.sx")):
basename = os.path.basename(fp)
if basename.startswith("test-"):
continue
slug = basename.replace(".sx", "")
try:
with open(fp, encoding="utf-8") as f:
content = f.read()
for expr in parse_all(content):
if not isinstance(expr, list) or len(expr) < 2:
continue
if not isinstance(expr[0], Symbol):
continue
head = expr[0].name
if head in ("define", "define-async"):
name = expr[1].name if isinstance(expr[1], Symbol) else str(expr[1])
index[name] = slug
except Exception:
continue
_SPEC_INDEX = index
return _SPEC_INDEX
# Test file → spec file mapping
_SPEC_TO_TEST = {
"signals.sx": "test-signals.sx",
"eval.sx": "test-eval.sx",
"parser.sx": "test-parser.sx",
"render.sx": "test-render.sx",
"engine.sx": "test-engine.sx",
"orchestration.sx": "test-orchestration.sx",
"router.sx": "test-router.sx",
"deps.sx": "test-deps.sx",
"adapter-sx.sx": "test-aser.sx",
"types.sx": "test-types.sx",
}
def _extract_tests_for_spec(filename: str) -> list[dict]:
"""Extract test suites/cases from the corresponding test file."""
import os
from shared.sx.parser import parse_all
from shared.sx.types import Symbol
test_file = _SPEC_TO_TEST.get(filename)
if not test_file:
return []
ref_dir = os.path.join(os.path.dirname(__file__), "..", "..", "shared", "sx", "ref")
if not os.path.isdir(ref_dir):
ref_dir = "/app/shared/sx/ref"
test_path = os.path.join(ref_dir, test_file)
try:
with open(test_path, encoding="utf-8") as f:
content = f.read()
exprs = parse_all(content)
except Exception:
return []
tests: list[dict] = []
for expr in exprs:
if not isinstance(expr, list) or len(expr) < 3:
continue
if not isinstance(expr[0], Symbol):
continue
if expr[0].name != "defsuite":
continue
suite_name = expr[1] if isinstance(expr[1], str) else str(expr[1])
test_names = []
for child in expr[2:]:
if isinstance(child, list) and len(child) >= 2:
if isinstance(child[0], Symbol) and child[0].name == "deftest":
tname = child[1] if isinstance(child[1], str) else str(child[1])
test_names.append(tname)
tests.append({"suite": suite_name, "tests": test_names})
return tests
def _match_tests_to_function(fn_name: str, all_tests: list[dict]) -> list[dict]:
"""Match test suites to a function by fuzzy name matching."""
matched = []
fn_lower = fn_name.lower().replace("-", " ").replace("!", "").replace("?", "")
fn_words = set(fn_lower.split())
for suite in all_tests:
suite_lower = suite["suite"].lower()
# Match if function name appears in suite name or suite name contains function
if fn_lower in suite_lower or any(w in suite_lower for w in fn_words if len(w) > 2):
matched.append(suite)
return matched
def _collect_symbols(expr) -> set[str]:
"""Recursively collect all Symbol names referenced in an expression."""
from shared.sx.types import Symbol
result: set[str] = set()
if isinstance(expr, Symbol):
result.add(expr.name)
elif isinstance(expr, list):
for item in expr:
result |= _collect_symbols(item)
elif isinstance(expr, dict):
for v in expr.values():
result |= _collect_symbols(v)
return result
def _spec_explorer_data(filename: str, title: str = "", desc: str = "") -> dict | None:
"""Parse a spec file into structured metadata for the spec explorer.
@@ -369,6 +526,34 @@ def _spec_explorer_data(filename: str, title: str = "", desc: str = "") -> dict
except Exception:
pass
# --- JavaScript translation ---
js_code = None
try:
js_code = _js_translate_define(expr, name)
except Exception:
pass
# --- Z3/SMT-LIB translation ---
z3_code = None
try:
z3_code = _z3_translate_define(expr)
except Exception:
pass
# --- Cross-references ---
refs = []
platform_deps = []
try:
spec_index = _build_spec_index()
body_symbols = _collect_symbols(expr)
own_names = {name}
for sym in body_symbols - own_names:
if sym in spec_index:
refs.append(sym)
# Symbols not in any spec file might be platform primitives
except Exception:
pass
define_entry = {
"name": name,
"kind": kind,
@@ -377,6 +562,11 @@ def _spec_explorer_data(filename: str, title: str = "", desc: str = "") -> dict
"source": src,
"line": line_num,
"python": py_code,
"javascript": js_code,
"z3": z3_code,
"refs": refs,
"tests": [],
"test-count": 0,
}
all_defines.append(define_entry)
@@ -401,6 +591,20 @@ def _spec_explorer_data(filename: str, title: str = "", desc: str = "") -> dict
target_section = s
target_section["defines"].append(d)
# --- Test matching ---
all_tests = _extract_tests_for_spec(filename)
test_total = 0
for d in all_defines:
matched = _match_tests_to_function(d["name"], all_tests)
if matched:
test_names = []
for suite in matched:
for t in suite["tests"]:
test_names.append({"name": t, "suite": suite["suite"]})
d["tests"] = test_names
d["test-count"] = len(test_names)
test_total += len(test_names)
# --- Stats ---
pure_count = sum(1 for d in all_defines if not d["effects"])
mutation_count = sum(1 for d in all_defines if "mutation" in d["effects"])
@@ -435,6 +639,7 @@ def _spec_explorer_data(filename: str, title: str = "", desc: str = "") -> dict
"io-count": io_count,
"render-count": render_count,
"lines": len(lines),
"test-total": test_total,
},
}