Add Semantics geography pages: capabilities, modules, eval-rules
Three new documentation pages under Geography > Semantics: - Capabilities: abstract evaluation contexts, capability primitives, standard capabilities, why not phases - Modules: the (use) form, what it enables, semantics - Eval Rules: machine-readable rule set, sx_explain tool, rule structure Navigation: semantics-nav-items with 3 entries, linked from geography nav tree after CEK Machine. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
52
sx/sx/geography/capabilities.sx
Normal file
52
sx/sx/geography/capabilities.sx
Normal file
@@ -0,0 +1,52 @@
|
||||
(defcomp ~geography/capabilities-content ()
|
||||
(~docs/page :title "Capabilities"
|
||||
(p :class "text-stone-500 text-sm italic mb-8"
|
||||
"Abstract evaluation contexts — what an expression is allowed to do, without prescribing where it runs.")
|
||||
|
||||
(~docs/section :title "The model" :id "model"
|
||||
(p "SX expressions evaluate in contexts that provide named capabilities. A capability is a permission to perform a class of side effect: " (code "io") " for network/filesystem, " (code "mutation") " for mutable state, " (code "dom") " for browser DOM, " (code "render") " for rendering operations.")
|
||||
(p "The key insight: capabilities are abstract. " (code "io") " doesn't mean 'server' — it means 'this context can perform input/output.' A server, an edge worker, and a browser tab can all provide " (code "io") ". The language doesn't care where the code runs, only what it's allowed to do.")
|
||||
(~docs/code :src (str "(with-capabilities (list \"pure\" \"mutation\")\n (fn ()\n (has-capability? \"io\") ;; false\n (has-capability? \"pure\") ;; true\n (require-capability! \"io\") ;; ERROR: Capability 'io' not available\n ))")))
|
||||
|
||||
(~docs/section :title "Capability primitives" :id "primitives"
|
||||
(table :class "min-w-full text-sm mb-6"
|
||||
(thead
|
||||
(tr
|
||||
(th :class "text-left pr-4 pb-2 font-semibold text-stone-700" "Primitive")
|
||||
(th :class "text-left pb-2 font-semibold text-stone-700" "Purpose")))
|
||||
(tbody :class "text-stone-600"
|
||||
(tr
|
||||
(td :class "pr-4 py-1 font-mono text-xs" "with-capabilities")
|
||||
(td :class "py-1" "Restrict capabilities for a body. Takes a list of capability names and a thunk."))
|
||||
(tr
|
||||
(td :class "pr-4 py-1 font-mono text-xs" "has-capability?")
|
||||
(td :class "py-1" "Check if a capability is available. Returns true in unrestricted contexts."))
|
||||
(tr
|
||||
(td :class "pr-4 py-1 font-mono text-xs" "require-capability!")
|
||||
(td :class "py-1" "Assert a capability. Error with a clear message if not available."))
|
||||
(tr
|
||||
(td :class "pr-4 py-1 font-mono text-xs" "current-capabilities")
|
||||
(td :class "py-1" "Return the current capability set, or nil if unrestricted.")))))
|
||||
|
||||
(~docs/section :title "Effect annotations" :id "effects"
|
||||
(p "Every function can declare its effect requirements:")
|
||||
(~docs/code :src (str "(define fetch-user :effects (io)\n (fn (id) (http-get (str \"/users/\" id))))\n\n(define format-name :effects ()\n (fn (user) (str (get user \"first\") \" \" (get user \"last\"))))"))
|
||||
(p (code "format-name") " is pure — it can run anywhere. " (code "fetch-user") " requires " (code "io") " — it can only run in a context that provides that capability. The " (em "where") " is decided by the host, not the language."))
|
||||
|
||||
(~docs/section :title "Standard capabilities" :id "standard"
|
||||
(table :class "min-w-full text-sm mb-6"
|
||||
(thead
|
||||
(tr
|
||||
(th :class "text-left pr-4 pb-2 font-semibold text-stone-700" "Capability")
|
||||
(th :class "text-left pb-2 font-semibold text-stone-700" "What it permits")))
|
||||
(tbody :class "text-stone-600"
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "pure") (td :class "py-1" "No side effects. Deterministic. Cacheable. Runnable anywhere."))
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "mutation") (td :class "py-1" "Mutable state: set!, append!, dict-set!, signal mutation."))
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "io") (td :class "py-1" "External I/O: network, filesystem, timers, promises."))
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "dom") (td :class "py-1" "Browser DOM operations: create elements, set attributes, event listeners."))
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "render") (td :class "py-1" "Rendering operations: component expansion, HTML generation, DOM patching.")))))
|
||||
|
||||
(~docs/section :title "Why not phases?" :id "why-not-phases"
|
||||
(p "Many frameworks hard-code evaluation phases: 'server' vs 'client', 'build time' vs 'runtime'. This bakes in assumptions about deployment topology.")
|
||||
(p "SX might run on a server, in a browser, at an edge node, in a WebAssembly sandbox, on another peer's machine, or in a context that doesn't exist yet. Capabilities are the right abstraction because they describe " (em "what") " an expression needs, not " (em "where") " it runs.")
|
||||
(p "A 'server' is just a context that provides " (code "(pure mutation io)") ". A 'browser' provides " (code "(pure mutation io dom render)") ". An edge worker might provide " (code "(pure io)") " but not " (code "mutation") ". The evaluator doesn't need to know — it just checks capabilities."))))
|
||||
36
sx/sx/geography/eval-rules.sx
Normal file
36
sx/sx/geography/eval-rules.sx
Normal file
@@ -0,0 +1,36 @@
|
||||
(defcomp ~geography/eval-rules-content ()
|
||||
(~docs/page :title "Evaluation Rules"
|
||||
(p :class "text-stone-500 text-sm italic mb-8"
|
||||
"Machine-readable SX semantics — a non-circular reference for how the language evaluates expressions.")
|
||||
|
||||
(~docs/section :title "Why rules as data" :id "why"
|
||||
(p "The SX spec is self-hosting: SX defines SX. This is elegant for bootstrapping but circular for understanding — you need to know SX to read the spec that defines SX.")
|
||||
(p "The evaluation rules break this circularity. Each rule is a data structure describing one dispatch case in the CEK evaluator: name, pattern, semantics, effects, and examples. Tools and LLMs can query these rules without reading the evaluator source.")
|
||||
(~docs/code :src (str ";; Ask the MCP server to explain a form\nsx_explain name=\"let\"\n\nlet\n Category: special-form\n Pattern: (let ((name val) ...) body ...)\n Effects: (none)\n\nCreate new scope. Evaluate each val sequentially,\nbind name. Last body form is in tail position.\n\nExamples:\n (let ((x 1) (y 2)) (+ x y)) → 3")))
|
||||
|
||||
(~docs/section :title "Rule categories" :id "categories"
|
||||
(table :class "min-w-full text-sm mb-6"
|
||||
(thead
|
||||
(tr
|
||||
(th :class "text-left pr-4 pb-2 font-semibold text-stone-700" "Category")
|
||||
(th :class "text-left pr-4 pb-2 font-semibold text-stone-700" "Count")
|
||||
(th :class "text-left pb-2 font-semibold text-stone-700" "What it covers")))
|
||||
(tbody :class "text-stone-600"
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "literal") (td :class "pr-4 py-1" "6") (td :class "py-1" "Numbers, strings, booleans, nil, keywords, dicts"))
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "lookup") (td :class "pr-4 py-1" "1") (td :class "py-1" "Symbol resolution: env → primitives → error"))
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "special-form") (td :class "pr-4 py-1" "13") (td :class "py-1" "if, when, cond, case, let, letrec, lambda, define, set!, begin, quote, quasiquote, ->"))
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "definition") (td :class "pr-4 py-1" "3") (td :class "py-1" "defcomp, defisland, defmacro"))
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "higher-order") (td :class "pr-4 py-1" "6") (td :class "py-1" "map, filter, reduce, some, every?, for-each"))
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "scope") (td :class "pr-4 py-1" "5") (td :class "py-1" "scope, provide, context, emit!, emitted"))
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "continuation") (td :class "pr-4 py-1" "2") (td :class "py-1" "reset, shift (delimited continuations)"))
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "reactive") (td :class "pr-4 py-1" "1") (td :class "py-1" "deref (signal reading)"))
|
||||
(tr (td :class "pr-4 py-1 font-mono text-xs" "call") (td :class "pr-4 py-1" "1") (td :class "py-1" "General function call dispatch")))))
|
||||
|
||||
(~docs/section :title "The sx_explain tool" :id "tool"
|
||||
(p "Query rules by name or category:")
|
||||
(~docs/code :src (str ";; Explain a specific form\nsx_explain name=\"if\"\n\n;; List all forms in a category\nsx_explain name=\"higher-order\"\n\n;; The rules live in spec/eval-rules.sx as SX data"))
|
||||
(p "The rules file is loaded by the MCP server at startup. It's plain SX — you can extend it with new rules for custom forms."))
|
||||
|
||||
(~docs/section :title "Rule structure" :id "structure"
|
||||
(~docs/code :src (str ";; Each rule is a dict with:\n{:name \"let\" ;; form name\n :category \"special-form\" ;; dispatch category\n :pattern \"(let ...)\" ;; syntax pattern\n :rule \"description\" ;; evaluation semantics\n :effects () ;; required capabilities\n :examples \"...\"} ;; input → output"))
|
||||
(p "The " (code ":effects") " field connects rules to the capability system. A rule with " (code ":effects \"mutation\"") " (like " (code "set!") ") can only be evaluated in contexts that provide the " (code "mutation") " capability."))))
|
||||
30
sx/sx/geography/modules.sx
Normal file
30
sx/sx/geography/modules.sx
Normal file
@@ -0,0 +1,30 @@
|
||||
(defcomp ~geography/modules-content ()
|
||||
(~docs/page :title "Modules"
|
||||
(p :class "text-stone-500 text-sm italic mb-8"
|
||||
"Declaring what a file needs — for documentation, static analysis, and tooling.")
|
||||
|
||||
(~docs/section :title "The use form" :id "use-form"
|
||||
(p "A " (code "(use module-name)") " declaration at the top of an " (code ".sx") " file says: this file depends on definitions from that module.")
|
||||
(~docs/code :src (str "(use signals) ;; needs signal, deref, reset!, swap!, computed\n(use web-signals) ;; needs resource, emit-event, on-event\n\n(defisland ~demo ()\n (let ((data (resource (fn () (promise-delayed 1000 42)))))\n (div (deref data))))"))
|
||||
(p (code "use") " is purely declarative — it doesn't load anything. The glob loader still loads all " (code ".sx") " files. The declaration documents intent and enables static checking."))
|
||||
|
||||
(~docs/section :title "What use enables" :id "what-it-enables"
|
||||
(h4 :class "font-semibold text-stone-700 mt-6 mb-2" "Dependency visibility")
|
||||
(p "The " (code "sx_deps") " tool reports both referenced symbols and declared modules. If a file references " (code "resource") " but doesn't " (code "(use web-signals)") ", the tool flags the gap.")
|
||||
(h4 :class "font-semibold text-stone-700 mt-6 mb-2" "Build pipeline validation")
|
||||
(p "The " (code "sx_build_manifest") " tool shows which modules are in the current build. Cross-referencing with " (code "use") " declarations catches missing build modules — exactly the bug that caused the " (code "resource") " island hydration failure.")
|
||||
(h4 :class "font-semibold text-stone-700 mt-6 mb-2" "Documentation")
|
||||
(p "For humans and LLMs reading a file: " (code "use") " declarations immediately show what the file depends on, without grep."))
|
||||
|
||||
(~docs/section :title "Semantics" :id "semantics"
|
||||
(p (code "(use name)") " is a no-op at evaluation time. It does not:")
|
||||
(ul :class "space-y-1 text-stone-600 ml-4"
|
||||
(li "Load any files")
|
||||
(li "Modify the environment")
|
||||
(li "Affect evaluation order")
|
||||
(li "Create any runtime cost"))
|
||||
(p "It " (em "does") ":")
|
||||
(ul :class "space-y-1 text-stone-600 ml-4"
|
||||
(li "Appear in the parsed tree for static analysis")
|
||||
(li "Get reported by " (code "sx_deps"))
|
||||
(li "Enable future tooling (unused-import warnings, auto-import suggestions)")))))
|
||||
@@ -14,3 +14,13 @@
|
||||
|
||||
(define marshes-examples-nav-items (list {:href "/sx/(geography.(marshes.hypermedia-feeds))" :label "Hypermedia Feeds State"} {:href "/sx/(geography.(marshes.server-signals))" :label "Server Writes to Signals"} {:href "/sx/(geography.(marshes.on-settle))" :label "sx-on-settle"} {:href "/sx/(geography.(marshes.signal-triggers))" :label "Signal-Bound Triggers"} {:href "/sx/(geography.(marshes.view-transform))" :label "Reactive View Transform"}))
|
||||
|
||||
|
||||
(define semantics-nav-items
|
||||
(list
|
||||
(dict :label "Capabilities" :href "/sx/(geography.(capabilities))"
|
||||
:summary "Abstract evaluation contexts — what an expression can do, not where it runs.")
|
||||
(dict :label "Modules" :href "/sx/(geography.(modules))"
|
||||
:summary "The (use) form — declaring dependencies for documentation and static analysis.")
|
||||
(dict :label "Eval Rules" :href "/sx/(geography.(eval-rules))"
|
||||
:summary "Machine-readable SX semantics — 35 rules as queryable data.")))
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
(defcomp ~nav-data/section-nav (&key items current) (<> (map (fn (item) (~shared:layout/nav-link :href (get item "href") :label (get item "label") :is-selected (when (= (get item "label") current) "true") :select-colours "aria-selected:bg-violet-200 aria-selected:text-violet-900")) items)))
|
||||
|
||||
(define sx-nav-tree {:href "/sx/" :children (list {:href "/sx/(geography)" :children (list {:href "/sx/(geography.(reactive))" :children reactive-islands-nav-items :label "Reactive Islands"} {:href "/sx/(geography.(hypermedia))" :children (list {:href "/sx/(geography.(hypermedia.(reference)))" :children reference-nav-items :label "Reference"} {:href "/sx/(geography.(hypermedia.(example)))" :children examples-nav-items :label "Examples"}) :label "Hypermedia Lakes"} {:href "/sx/(geography.(scopes))" :summary "The unified primitive beneath provide, collect!, spreads, and islands. Named scope with downward value, upward accumulation, and a dedup flag." :label "Scopes"} {:href "/sx/(geography.(provide))" :summary "Sugar for scope-with-value. Render-time dynamic scope — the substrate beneath spreads, CSSX, and script collection." :label "Provide / Emit!"} {:href "/sx/(geography.(spreads))" :summary "Child-to-parent communication across render boundaries — spread, collect!, reactive-spread, built on scopes." :label "Spreads"} {:href "/sx/(geography.(marshes))" :children marshes-examples-nav-items :summary "Where reactivity and hypermedia interpenetrate — server writes to signals, reactive transforms reshape server content, client state modifies how hypermedia is interpreted." :label "Marshes"} {:href "/sx/(geography.(isomorphism))" :children isomorphism-nav-items :label "Isomorphism"} {:href "/sx/(geography.(cek))" :children cek-nav-items :label "CEK Machine"}) :label "Geography"} {:href "/sx/(language)" :children (list {:href "/sx/(language.(doc))" :children docs-nav-items :label "Docs"} {:href "/sx/(language.(spec))" :children specs-nav-items :label "Specs"} {:href "/sx/(language.(spec.(explore.evaluator)))" :label "Spec Explorer"} {:href "/sx/(language.(bootstrapper))" :children bootstrappers-nav-items :label "Bootstrappers"} {:href "/sx/(language.(test))" :children testing-nav-items :label "Testing"}) :label "Language"} {:href "/sx/(applications)" :children (list {:href "/sx/(applications.(sx-urls))" :label "SX URLs"} {:href "/sx/(applications.(cssx))" :children cssx-nav-items :label "CSSX"} {:href "/sx/(applications.(protocol))" :children protocols-nav-items :label "Protocols"} {:href "/sx/(applications.(sx-pub))" :label "sx-pub"} {:href "/sx/(applications.(reactive-runtime))" :children reactive-runtime-nav-items :label "Reactive Runtime"}) :label "Applications"} {:href "/sx/(tools)" :children tools-nav-items :label "Tools"} {:href "/sx/(etc)" :children (list {:href "/sx/(etc.(essay))" :children essays-nav-items :label "Essays"} {:href "/sx/(etc.(philosophy))" :children philosophy-nav-items :label "Philosophy"} {:href "/sx/(etc.(plan))" :children plans-nav-items :label "Plans"}) :label "Etc"}) :label "sx"})
|
||||
(define sx-nav-tree {:href "/sx/" :children (list {:href "/sx/(geography)" :children (list {:href "/sx/(geography.(reactive))" :children reactive-islands-nav-items :label "Reactive Islands"} {:href "/sx/(geography.(hypermedia))" :children (list {:href "/sx/(geography.(hypermedia.(reference)))" :children reference-nav-items :label "Reference"} {:href "/sx/(geography.(hypermedia.(example)))" :children examples-nav-items :label "Examples"}) :label "Hypermedia Lakes"} {:href "/sx/(geography.(scopes))" :summary "The unified primitive beneath provide, collect!, spreads, and islands. Named scope with downward value, upward accumulation, and a dedup flag." :label "Scopes"} {:href "/sx/(geography.(provide))" :summary "Sugar for scope-with-value. Render-time dynamic scope — the substrate beneath spreads, CSSX, and script collection." :label "Provide / Emit!"} {:href "/sx/(geography.(spreads))" :summary "Child-to-parent communication across render boundaries — spread, collect!, reactive-spread, built on scopes." :label "Spreads"} {:href "/sx/(geography.(marshes))" :children marshes-examples-nav-items :summary "Where reactivity and hypermedia interpenetrate — server writes to signals, reactive transforms reshape server content, client state modifies how hypermedia is interpreted." :label "Marshes"} {:href "/sx/(geography.(isomorphism))" :children isomorphism-nav-items :label "Isomorphism"} {:href "/sx/(geography.(cek))" :children cek-nav-items :label "CEK Machine"} {:href "/sx/(geography.(capabilities))" :children semantics-nav-items :label "Semantics"}) :label "Geography"} {:href "/sx/(language)" :children (list {:href "/sx/(language.(doc))" :children docs-nav-items :label "Docs"} {:href "/sx/(language.(spec))" :children specs-nav-items :label "Specs"} {:href "/sx/(language.(spec.(explore.evaluator)))" :label "Spec Explorer"} {:href "/sx/(language.(bootstrapper))" :children bootstrappers-nav-items :label "Bootstrappers"} {:href "/sx/(language.(test))" :children testing-nav-items :label "Testing"}) :label "Language"} {:href "/sx/(applications)" :children (list {:href "/sx/(applications.(sx-urls))" :label "SX URLs"} {:href "/sx/(applications.(cssx))" :children cssx-nav-items :label "CSSX"} {:href "/sx/(applications.(protocol))" :children protocols-nav-items :label "Protocols"} {:href "/sx/(applications.(sx-pub))" :label "sx-pub"} {:href "/sx/(applications.(reactive-runtime))" :children reactive-runtime-nav-items :label "Reactive Runtime"}) :label "Applications"} {:href "/sx/(tools)" :children tools-nav-items :label "Tools"} {:href "/sx/(etc)" :children (list {:href "/sx/(etc.(essay))" :children essays-nav-items :label "Essays"} {:href "/sx/(etc.(philosophy))" :children philosophy-nav-items :label "Philosophy"} {:href "/sx/(etc.(plan))" :children plans-nav-items :label "Plans"}) :label "Etc"}) :label "sx"})
|
||||
|
||||
(define has-descendant-href? (fn (node path) (let ((children (get node "children"))) (when children (some (fn (child) (or (= (get child "href") path) (has-descendant-href? child path))) children)))))
|
||||
|
||||
|
||||
@@ -69,3 +69,9 @@
|
||||
(define philosophy (fn (slug) (if (nil? slug) (quote (~essays/philosophy-index/content)) (case slug "sx-manifesto" (quote (~essay-sx-manifesto)) "godel-escher-bach" (quote (~essays/godel-escher-bach/essay-godel-escher-bach)) "wittgenstein" (quote (~essays/sx-and-wittgenstein/essay-sx-and-wittgenstein)) "dennett" (quote (~essays/sx-and-dennett/essay-sx-and-dennett)) "existentialism" (quote (~essays/s-existentialism/essay-s-existentialism)) "platonic-sx" (quote (~essays/platonic-sx/essay-platonic-sx)) :else (quote (~essays/philosophy-index/content))))))
|
||||
|
||||
(define plan (make-page-fn "~plans/index/plans-index-content" "~plans/" "/plan-" "-content"))
|
||||
|
||||
(define capabilities (fn (&key title &rest args) (quasiquote (~geography/capabilities-content))))
|
||||
|
||||
(define modules (fn (&key title &rest args) (quasiquote (~geography/modules-content))))
|
||||
|
||||
(define eval-rules (fn (&key title &rest args) (quasiquote (~geography/eval-rules-content))))
|
||||
|
||||
Reference in New Issue
Block a user