Spec explorer data endpoint, spec file finder, browser render test (failing)

- Add spec-explorer-data-by-slug helper with _SPEC_SLUG_MAP
- _find_spec_file searches spec/, web/, shared/sx/ref/ directories
- defpage specs-explore-page uses :data for server-side data fetch
- test_evaluator_renders_in_browser: failing test for client-side rendering
  (client re-evaluates defpage content, find-spec unavailable — pre-existing)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-18 17:36:21 +00:00
parent 71c2003a60
commit fac97883f9
6 changed files with 100 additions and 15 deletions

View File

@@ -40,7 +40,7 @@
;; -----------------------------------------------------------------------
(~docs/section :title "Tiers" :id "tiers"
(p "Four tiers, matching the " (a :href "/sx/(geography.(reactive.plan))" :class "text-violet-700 underline" "reactive islands") " levels:")
(p "Four tiers, matching the " (a :href "/sx/(geography.(reactive.(reactive-design)))" :class "text-violet-700 underline" "reactive islands") " levels:")
(div :class "overflow-x-auto rounded border border-stone-200 mb-4"
(table :class "w-full text-left text-sm"
@@ -275,7 +275,7 @@
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
(li (a :href "/sx/(etc.(plan.environment-images))" :class "text-violet-700 underline" "Environment Images") " — tiered images are smaller. An L0 image omits the parser, evaluator, and most primitives.")
(li (a :href "/sx/(etc.(plan.content-addressed-components))" :class "text-violet-700 underline" "Content-Addressed Components") " — component CID resolution is L3-only. L0 pages don't resolve components client-side.")
(li (a :href "/sx/(geography.(reactive.plan))" :class "text-violet-700 underline" "Reactive Islands") " — L2 tier is defined by island presence. The signal runtime is the L1→L2 delta.")
(li (a :href "/sx/(geography.(reactive.(reactive-design)))" :class "text-violet-700 underline" "Reactive Islands") " — L2 tier is defined by island presence. The signal runtime is the L1→L2 delta.")
(li (a :href "/sx/(etc.(plan.isomorphic-architecture))" :class "text-violet-700 underline" "Isomorphic Architecture") " — client-side page rendering is L3. Most pages don't need it."))
(div :class "rounded border border-amber-200 bg-amber-50 p-3 mt-2"

View File

@@ -159,18 +159,35 @@ def _reference_data(slug: str) -> dict:
return build_reference_data(slug, raw, detail_keys)
def _read_spec_file(filename: str) -> str:
"""Read a spec .sx file from the ref directory. Pure I/O — metadata lives in .sx."""
def _find_spec_file(filename: str) -> str | None:
"""Find a spec .sx file across spec/, web/, shared/sx/ref/ directories."""
import os
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"
filepath = os.path.join(ref_dir, filename)
base = os.path.join(os.path.dirname(__file__), "..", "..")
search_dirs = [
os.path.join(base, "spec"),
os.path.join(base, "web"),
os.path.join(base, "shared", "sx", "ref"),
"/app/spec",
"/app/web",
"/app/shared/sx/ref",
]
for d in search_dirs:
path = os.path.join(d, filename)
if os.path.isfile(path):
return path
return None
def _read_spec_file(filename: str) -> str:
"""Read a spec .sx file. Pure I/O — metadata lives in .sx."""
filepath = _find_spec_file(filename)
if not filepath:
return ";; spec file not found: " + filename
try:
with open(filepath, encoding="utf-8") as f:
return f.read()
except FileNotFoundError:
return ";; spec file not found"
except (FileNotFoundError, TypeError):
return ";; spec file not found: " + filename
# ---------------------------------------------------------------------------
@@ -332,7 +349,7 @@ def _collect_symbols(expr) -> set[str]:
_SPEC_SLUG_MAP = {
"parser": ("parser.sx", "Parser", "Tokenization and parsing"),
"evaluator": ("eval.sx", "Evaluator", "Tree-walking evaluation"),
"evaluator": ("evaluator.sx", "Evaluator", "CEK machine evaluator"),
"primitives": ("primitives.sx", "Primitives", "Built-in pure functions"),
"render": ("render.sx", "Renderer", "Three rendering modes"),
"special-forms": ("special-forms.sx", "Special Forms", "Special form dispatch"),
@@ -374,10 +391,9 @@ def _spec_explorer_data(filename: str, title: str = "", desc: str = "") -> dict
return None
# Read the raw source
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"
filepath = os.path.join(ref_dir, filename)
filepath = _find_spec_file(filename)
if not filepath:
return None
try:
with open(filepath, encoding="utf-8") as f:
source = f.read()

View File

@@ -491,6 +491,15 @@ class TestSpecExplorer:
assert "define" in body, "Should contain define forms from spec"
assert "eval-expr" in body, "Should contain eval-expr from evaluator spec"
def test_evaluator_renders_in_browser(self, page: Page):
"""Spec explorer should render correctly in the browser, not show 'not found'."""
nav(page, "(language.(spec.(explore.evaluator)))")
page.wait_for_timeout(3000)
content = page.locator("#main-panel").text_content() or ""
assert "not found" not in content.lower(), \
f"Page shows 'not found' instead of spec content: {content[:200]}"
expect(page.locator("#main-panel")).to_contain_text("Evaluator", timeout=5000)
# ---------------------------------------------------------------------------
# Key doc pages (smoke tests)