;; SX Protocol — A Proposal
;; S-expressions as a universal protocol for networked hypermedia.

(defcomp ()
  (~docs/page :title "SX Protocol — A Proposal"

    (~docs/section :title "Abstract" :id "abstract"
      (p "SX is a Lisp dialect and a proposed universal protocol for networked hypermedia. "
         "It replaces URLs, HTTP verbs, query strings, API query languages, and rendering layers "
         "with a single unified concept: " (strong "the s-expression") ".")
      (p "Everything is an expression. Everything is evaluable. Everything is composable."))

    (~docs/section :title "The Problem With the Current Web" :id "problem"
      (p "The modern web stack has accumulated layers of incompatible syntax to express "
         "what are fundamentally the same things:")
      (table (~tw :tokens "w-full text-sm border-collapse mb-4")
        (thead
          (tr (~tw :tokens "border-b border-stone-300")
            (th (~tw :tokens "text-left py-2 pr-4") "Concern")
            (th (~tw :tokens "text-left py-2 pr-4") "Current Syntax")
            (th (~tw :tokens "text-left py-2") "Example")))
        (tbody
          (tr (~tw :tokens "border-b border-stone-100")
            (td (~tw :tokens "py-2 pr-4") "Resource path")
            (td (~tw :tokens "py-2 pr-4") "URL segments")
            (td (~tw :tokens "py-2 font-mono text-xs") "/users/123/posts"))
          (tr (~tw :tokens "border-b border-stone-100")
            (td (~tw :tokens "py-2 pr-4") "Query parameters")
            (td (~tw :tokens "py-2 pr-4 font-mono text-xs") "?key=value")
            (td (~tw :tokens "py-2 font-mono text-xs") "?filter=published&sort=date"))
          (tr (~tw :tokens "border-b border-stone-100")
            (td (~tw :tokens "py-2 pr-4") "API queries")
            (td (~tw :tokens "py-2 pr-4") "GraphQL / REST")
            (td (~tw :tokens "py-2 font-mono text-xs") "{ posts(filter: \"published\") { title } }"))
          (tr (~tw :tokens "border-b border-stone-100")
            (td (~tw :tokens "py-2 pr-4") "Network verb")
            (td (~tw :tokens "py-2 pr-4") "HTTP method")
            (td (~tw :tokens "py-2 font-mono text-xs") "GET, POST, PUT"))
          (tr (~tw :tokens "border-b border-stone-100")
            (td (~tw :tokens "py-2 pr-4") "Real-time")
            (td (~tw :tokens "py-2 pr-4") "WebSocket URL")
            (td (~tw :tokens "py-2 font-mono text-xs") "wss://site.com/live"))
          (tr
            (td (~tw :tokens "py-2 pr-4") "Rendering")
            (td (~tw :tokens "py-2 pr-4") "HTML + CSS + JS")
            (td (~tw :tokens "py-2") "Three separate languages"))))
      (p "Each layer invented its own syntax. None of them compose. None of them are executable. "
         "None of them are data."))

    (~docs/section :title "The SX Approach" :id "approach"

      (h3 (~tw :tokens "text-lg font-semibold mt-6 mb-2") "URLs as S-Expressions")
      (p "A conventional URL:")
      (~docs/code :src (highlight "https://site.com/blog/my-post?filter=published&sort=date" "text"))
      (p "As an SX expression:")
      (~docs/code :src (highlight "(get.site.com.(blog.(my-post.(filter.published.sort.date))))" "lisp"))
      (ul
        (li "The protocol/verb is the first atom: " (code "get"))
        (li "The domain follows: " (code "site.com"))
        (li "Path and parameters collapse into " (strong "one unified nested structure"))
        (li "No " (code "?") ", no " (code "&") ", no " (code "/") " — just lists"))

      (h3 (~tw :tokens "text-lg font-semibold mt-6 mb-2") "Dots, Not Spaces")
      (p "Lisp conventionally uses spaces as separators. In URLs, spaces become " (code "%20")
         ". SX uses dots instead, which are URL-safe and semantically meaningful — a dot between "
         "two atoms is a " (strong "cons pair") ", the fundamental unit of Lisp structure.")
      (~docs/code :src (highlight ";; Clean, URL-safe, valid Lisp\n(blog.(filter.published).(sort.date.desc))" "lisp"))

      (h3 (~tw :tokens "text-lg font-semibold mt-6 mb-2") "Verbs Are Just Atoms")
      (p "HTTP methods are not special syntax — they are simply the first element of the expression:")
      (~docs/code :src (highlight "(get.site.com.(post.my-first-post))        ; read\n(post.site.com.(submit-post.(title.hello))) ; write\n(ws.site.com.(live-feed))                  ; websocket / subscribe" "lisp"))
      (p "No special protocol prefixes. No " (code "https://") " vs " (code "wss://")
         ". The verb is data, like everything else."))

    (~docs/section :title "Graph-SX: Hypermedia Queries" :id "graph-sx"
      (p "GraphQL was a major advance over REST, but it made two compromises:")
      (ol
        (li "Queries are sent as POST bodies, sacrificing cacheability and shareability")
        (li "Responses are dead data — JSON that must be separately rendered"))
      (p (strong "Graph-SX") " addresses both.")

      (h3 (~tw :tokens "text-lg font-semibold mt-6 mb-2") "Queries Are URLs")
      (p "Because SX expressions are URLs, every query is a GET request:")
      (~docs/code :src (highlight ";; This is a URL and a query simultaneously\n(get.site.com.(blog.(filter.(tag.lisp)).(limit.10)))" "lisp"))
      (ul
        (li "Fully cacheable by CDNs")
        (li "Bookmarkable and shareable")
        (li "No POST body required for reads")
        (li "Browser back button works correctly"))

      (h3 (~tw :tokens "text-lg font-semibold mt-6 mb-2") "Responses Include Rendering")
      (p "GraphQL returns data. Graph-SX returns " (strong "hypermedia")
         " — data and its presentation in the same expression:")
      (~docs/code :src (highlight ";; GraphQL response (dead data)\n{\"title\": \"My Post\", \"body\": \"Hello world\"}\n\n;; Graph-SX response (live hypermedia)\n(article\n  (h1 \"My Post\")\n  (p \"Hello world\")\n  (a (href (get.site.com.(post.next-post))) \"Next\"))" "lisp"))
      (p "The server returns what the resource " (strong "is") " and how to "
         (strong "present") " it in one unified structure. There is no separate rendering layer.")

      (h3 (~tw :tokens "text-lg font-semibold mt-6 mb-2") "Queries Are Transformations")
      (p "Because SX is a full programming language, the query and the transformation "
         "are the same expression:")
      (~docs/code :src (highlight ";; Fetch, filter, and transform in one expression\n(map (lambda (p) (title p))\n     (filter published?\n             (posts (after \"2025\"))))" "lisp"))
      (p "No separate processing step. No client-side data manipulation layer."))

    (~docs/section :title "Components" :id "components"
      (p "SX supports server-side composable components via the " (code "~") " prefix convention:")
      (~docs/code :src (highlight "(~get.everything-under-the-sun)" "lisp"))
      (p "A " (code "~component") " is a named server-side function that:")
      (ol
        (li "Receives the expression as arguments")
        (li "Makes onward queries as needed")
        (li "Processes and composes results")
        (li "Returns hypermedia"))
      (p "Components compose naturally:")
      (~docs/code :src (highlight "(~page.home\n  (~hero.banner)\n  (~get.latest-posts.(limit.5))\n  (~get.featured.(filter.pinned)))" "lisp"))
      (p "This is equivalent to React Server Components — but without a framework, "
         "without a build step, and without leaving Lisp."))

    (~docs/section :title "Cross-Domain Composition" :id "cross-domain"
      (p "Because domain and verb are just atoms, cross-domain queries are structurally "
         "identical to local ones:")
      (~docs/code :src (highlight ";; Local\n(post.my-first-post)\n\n;; Remote — identical structure, qualified\n(get.site.com.(post.my-first-post))\n\n;; Composed across domains\n(~render\n  (get.site.com.(post.my-first-post))\n  (get.cdn.com.(image.hero)))" "lisp"))
      (p "Network calls are function calls. Remote resources are just namespaced expressions."))

    (~docs/section :title "Self-Describing and Introspectable" :id "introspectable"
      (p "Because the site is implemented in SX and served as SX, every page is introspectable:")
      (~docs/code :src (highlight "(get.sx.dev.(about))               ; the about page\n(get.sx.dev.(source.(about)))      ; the SX source for the about page\n(get.sx.dev.(eval.(source.about))) ; re-evaluate it live" "lisp"))
      (p "The site is its own documentation. The source is always one expression away."))

    (~docs/section :title "Comparison" :id "comparison"
      (table (~tw :tokens "w-full text-sm border-collapse mb-4")
        (thead
          (tr (~tw :tokens "border-b border-stone-300")
            (th (~tw :tokens "text-left py-2 pr-4") "Feature")
            (th (~tw :tokens "text-left py-2 pr-4") "REST")
            (th (~tw :tokens "text-left py-2 pr-4") "GraphQL")
            (th (~tw :tokens "text-left py-2") "Graph-SX")))
        (tbody
          (tr (~tw :tokens "border-b border-stone-100")
            (td (~tw :tokens "py-2 pr-4") "Reads are GETs")
            (td (~tw :tokens "py-2 pr-4 text-green-700") "Yes")
            (td (~tw :tokens "py-2 pr-4 text-red-700") "No (POST)")
            (td (~tw :tokens "py-2 text-green-700") "Yes"))
          (tr (~tw :tokens "border-b border-stone-100")
            (td (~tw :tokens "py-2 pr-4") "CDN cacheable")
            (td (~tw :tokens "py-2 pr-4 text-green-700") "Yes")
            (td (~tw :tokens "py-2 pr-4 text-red-700") "No")
            (td (~tw :tokens "py-2 text-green-700") "Yes"))
          (tr (~tw :tokens "border-b border-stone-100")
            (td (~tw :tokens "py-2 pr-4") "Nested queries")
            (td (~tw :tokens "py-2 pr-4 text-red-700") "No")
            (td (~tw :tokens "py-2 pr-4 text-green-700") "Yes")
            (td (~tw :tokens "py-2 text-green-700") "Yes"))
          (tr (~tw :tokens "border-b border-stone-100")
            (td (~tw :tokens "py-2 pr-4") "Response includes rendering")
            (td (~tw :tokens "py-2 pr-4 text-red-700") "No")
            (td (~tw :tokens "py-2 pr-4 text-red-700") "No")
            (td (~tw :tokens "py-2 text-green-700") "Yes"))
          (tr (~tw :tokens "border-b border-stone-100")
            (td (~tw :tokens "py-2 pr-4") "Query is a transformation")
            (td (~tw :tokens "py-2 pr-4 text-red-700") "No")
            (td (~tw :tokens "py-2 pr-4 text-red-700") "No")
            (td (~tw :tokens "py-2 text-green-700") "Yes"))
          (tr (~tw :tokens "border-b border-stone-100")
            (td (~tw :tokens "py-2 pr-4") "Composable across domains")
            (td (~tw :tokens "py-2 pr-4 text-red-700") "No")
            (td (~tw :tokens "py-2 pr-4 text-red-700") "No")
            (td (~tw :tokens "py-2 text-green-700") "Yes"))
          (tr (~tw :tokens "border-b border-stone-100")
            (td (~tw :tokens "py-2 pr-4") "One syntax for everything")
            (td (~tw :tokens "py-2 pr-4 text-red-700") "No")
            (td (~tw :tokens "py-2 pr-4 text-red-700") "No")
            (td (~tw :tokens "py-2 text-green-700") "Yes"))
          (tr (~tw :tokens "border-b border-stone-100")
            (td (~tw :tokens "py-2 pr-4") "Bookmarkable deep links")
            (td (~tw :tokens "py-2 pr-4 text-green-700") "Yes")
            (td (~tw :tokens "py-2 pr-4 text-red-700") "No")
            (td (~tw :tokens "py-2 text-green-700") "Yes"))
          (tr
            (td (~tw :tokens "py-2 pr-4") "Self-hosting / introspectable")
            (td (~tw :tokens "py-2 pr-4 text-red-700") "No")
            (td (~tw :tokens "py-2 pr-4 text-stone-500") "Partial")
            (td (~tw :tokens "py-2 text-green-700") "Yes")))))

    (~docs/section :title "Future Direction" :id "future"
      (p "The logical conclusion of SX is a " (strong "new internet protocol")
         " in which the URL, the HTTP verb, the query language, the response format, "
         "and the rendering layer are all unified under one evaluable expression format.")
      (~docs/code :src (highlight ";; The entire network request — protocol, domain, verb, query, all one expression\n(get.sx.dev.(blog.(filter.(tag.lisp)).(limit.10)))" "lisp"))
      (p "HTTP becomes one possible implementation of a more general principle:")
      (blockquote (~tw :tokens "border-l-4 border-violet-300 pl-4 italic text-stone-600 my-4")
        (p (strong "Evaluate this expression. Return an expression."))))

    (~docs/section :title "Reference Implementation" :id "reference"
      (p "SX is implemented in SX. The reference implementation is self-hosting and available at:")
      (~docs/code :src (highlight "(get.sx.dev.(source.evaluator))" "lisp"))
      (p (~tw :tokens "text-sm text-stone-500 mt-4 italic")
        "This proposal was written in conversation with Claude (Anthropic). The ideas are the author's own."))))
