;; ---------------------------------------------------------------------------
;; Content-Addressed Environment Images
;; ---------------------------------------------------------------------------

(defcomp ()
  (~docs/page :title "Content-Addressed Environment Images"

    (~docs/section :title "The Idea" :id "idea"
      (p "Every served SX endpoint should point back to its spec. The spec CIDs identify the exact evaluator, renderer, parser, and primitives that produced the output. This makes every endpoint " (strong "fully executable") " — anyone with the CIDs can independently reproduce the result.")
      (p "But evaluating spec files from source on every cold start is wasteful. The specs are pure — same source always produces the same evaluated environment. So we can serialize the " (em "evaluated") " environment as a content-addressed image: all defcomps, defmacros, bound symbols, resolved closures frozen into a single artifact. The image CID is a function of its contents. Load the image, skip evaluation, get the same result.")
      (p "The chain becomes:")
      (ol (~tw :tokens "list-decimal pl-5 text-stone-700 space-y-2")
        (li (strong "Served page") " → CID of the spec that defines its semantics")
        (li (strong "Spec CID") " → the evaluator, renderer, parser, primitives that any conforming host can execute")
        (li (strong "Image CID") " → the pre-evaluated environment, a cache of (2) that any conforming host can deserialize"))
      (p "The spec is the truth. The image is a verified cache. The bootstrapper that compiled the spec for a particular host is an implementation detail — irrelevant to the content address.")
      (div (~tw :tokens "rounded border border-violet-200 bg-violet-50 p-4 mt-4")
        (p (~tw :tokens "text-violet-900 font-medium") "Prior art")
        (p (~tw :tokens "text-violet-800") (a :href "https://github.com/KinaKnowledge/juno-lang" (~tw :tokens "underline") "Juno") " — a self-hosted Lisp-to-JS compiler — implements image persistence: serialize a running environment, restore it later, even bundle it as a standalone HTML document. Their Seedling IDE saves/restores entire development sessions as images. SX can do this more rigorously because our images are content-addressed (Juno's are not) and our components are boundary-enforced pure (Juno's are not).")))

    ;; -----------------------------------------------------------------------
    ;; What gets serialized
    ;; -----------------------------------------------------------------------

    (~docs/section :title "What Gets Serialized" :id "what"
      (p "An environment image is a snapshot of everything produced by evaluating the spec files. Not the source — the result.")

      (div (~tw :tokens "overflow-x-auto rounded border border-stone-200 mb-4")
        (table (~tw :tokens "w-full text-left text-sm")
          (thead (tr (~tw :tokens "border-b border-stone-200 bg-stone-100")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Category")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Contents")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Source")))
          (tbody
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Components")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "All " (code "defcomp") " definitions — name, params, body AST, closure bindings, CID, deps, css_classes")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "Service .sx files + shared/sx/templates/"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Macros")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "All " (code "defmacro") " definitions — name, params, body AST, closure")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "Spec files"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Bindings")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Top-level " (code "define") " values — constants, lookup tables, configuration")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "Spec files + service .sx"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Primitives")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Registry of pure primitive names (not implementations — those are host-specific)")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "primitives.sx, boundary.sx"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Spec provenance")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "CIDs of the spec files that produced this image")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "eval.sx, render.sx, parser.sx, ...")))))

      (p "Notably " (strong "absent") " from the image:")
      (ul (~tw :tokens "list-disc pl-5 text-stone-700 space-y-1")
        (li (strong "IO primitive implementations") " — these are host-specific. The image records their " (em "names") " (for boundary enforcement) but not their code.")
        (li (strong "Page helpers") " — same reason. " (code "fetch-data") ", " (code "app-url") " etc. are registered by the host app at startup.")
        (li (strong "Runtime state") " — no request context, no DB connections, no session data. The image is a pure function's result, not a running process snapshot.")))

    ;; -----------------------------------------------------------------------
    ;; Image format
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Image Format" :id "format"
      (p "The image is itself an s-expression — the same format the spec is written in. This means the image can be parsed by the same parser, inspected by the same tools, and content-addressed by the same canonical serializer.")

      (~docs/code :src (highlight "(sx-image\n  :version 1\n  :spec-cids {:eval   \"bafy...eval\"\n              :render \"bafy...render\"\n              :parser \"bafy...parser\"\n              :primitives \"bafy...prims\"\n              :boundary   \"bafy...boundary\"\n              :signals    \"bafy...signals\"}\n\n  :components (\n    (defcomp ~plans/environment-images/card (&key title subtitle &rest children)\n      (div :class \"card\" (h2 title) (when subtitle (p subtitle)) children))\n    (defcomp ~plans/environment-images/nav (&key items current)\n      (nav :class \"nav\" (map (fn (item) ...) items)))\n    ;; ... all registered components\n  )\n\n  :macros (\n    (defmacro when (test &rest body)\n      (list 'if test (cons 'begin body) nil))\n    ;; ... all macros\n  )\n\n  :bindings (\n    (define void-elements (list \"area\" \"base\" \"br\" \"col\" ...))\n    (define boolean-attrs (list \"checked\" \"disabled\" ...))\n    ;; ... all top-level defines\n  )\n\n  :primitive-names (\"str\" \"+\" \"-\" \"*\" \"/\" \"=\" \"<\" \">\" ...)\n  :io-names (\"fetch-data\" \"call-action\" \"app-url\" ...))" "lisp"))

      (p "The " (code ":spec-cids") " field is the key. It links this image back to the exact spec that produced it. Anyone can verify the image by:")
      (ol (~tw :tokens "list-decimal pl-5 text-stone-700 space-y-1")
        (li "Fetch the spec files by CID")
        (li "Evaluate them with a conforming evaluator")
        (li "Serialize the resulting environment")
        (li "Compare — it must produce the same image")))

    ;; -----------------------------------------------------------------------
    ;; Image CID
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Image CID" :id "image-cid"
      (p "The image CID is computed by canonical-serializing the entire " (code "(sx-image ...)") " form and hashing it. Same process as component CIDs, just applied to the whole environment.")
      (p "The relationship between spec CIDs and image CID is deterministic:")

      (~docs/code :src (highlight ";; The image CID is a pure function of the spec CIDs\n;; (assuming a deterministic evaluator, which SX guarantees)\n(define image-cid-from-specs\n  (fn (spec-cids)\n    ;; 1. Fetch each spec file by CID\n    ;; 2. Evaluate all specs in a fresh environment\n    ;; 3. Extract components, macros, bindings\n    ;; 4. Build (sx-image ...) form\n    ;; 5. Canonical serialize\n    ;; 6. Hash → CID\n    ))" "lisp"))

      (p "This means you can compute the expected image CID from the spec CIDs " (em "without") " having the image. If someone hands you an image claiming to be from spec " (code "bafy...eval") ", you can verify it by re-evaluating the spec and comparing CIDs. The image is a verifiable cache.")
      (p "In practice, you'd only do this verification once per spec version. After that, the image CID is trusted by content-addressing — same bytes, same hash, forever."))

    ;; -----------------------------------------------------------------------
    ;; Endpoint provenance
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Endpoint Provenance" :id "provenance"
      (p "Every served page gains a provenance header linking it to the spec that rendered it:")

      (~docs/code :src (highlight "HTTP/1.1 200 OK\nContent-Type: text/html\nSX-Spec: bafy...eval,bafy...render,bafy...parser,bafy...prims\nSX-Image: bafy...image\nSX-Page-Components: ~plans/environment-images/card:bafy...card,~plans/environment-images/nav:bafy...nav" "http"))

      (p "Three levels of verification:")
      (div (~tw :tokens "overflow-x-auto rounded border border-stone-200 mb-4")
        (table (~tw :tokens "w-full text-left text-sm")
          (thead (tr (~tw :tokens "border-b border-stone-200 bg-stone-100")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Level")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "What you verify")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Trust assumption")))
          (tbody
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-semibold text-stone-800") "Component")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Fetch " (code "~plans/environment-images/card") " by CID, verify hash")
              (td (~tw :tokens "px-3 py-2 text-stone-600") "Trust the evaluator"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-semibold text-stone-800") "Image")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Fetch image by CID, deserialize, re-render page")
              (td (~tw :tokens "px-3 py-2 text-stone-600") "Trust the image producer"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-semibold text-stone-800") "Spec")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Fetch specs by CID, re-evaluate, compare image CID")
              (td (~tw :tokens "px-3 py-2 text-stone-600") "Trust only the hash function")))))

      (p "Level 3 is the nuclear option — full independent verification from source. It's expensive but proves the entire chain. Most consumers will operate at level 1 (component verification) or level 2 (image verification)."))

    ;; -----------------------------------------------------------------------
    ;; Cold start optimization
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Cold Start: Images as Cache" :id "cold-start"
      (p "The practical motivation: evaluating all spec files + service components on every server restart is slow. An image eliminates this.")

      (~docs/subsection :title "Server Startup"
        (ol (~tw :tokens "list-decimal pl-5 text-stone-700 space-y-2")
          (li "Check if a cached image exists for the current spec CIDs")
          (li "If yes: deserialize the image (fast — parsing a single file, no evaluation)")
          (li "If no: evaluate spec files from source, build image, cache it")
          (li "Register IO primitives and page helpers (host-specific, not in image)")
          (li "Ready to serve"))
        (~docs/code :src (highlight "(define load-environment\n  (fn (spec-cids image-cache-dir)\n    (let ((expected-image-cid (image-cid-for-specs spec-cids))\n          (cached-path (str image-cache-dir \"/\" expected-image-cid \".sx\")))\n      (if (file-exists? cached-path)\n        ;; Fast path: deserialize\n        (let ((image (parse (read-file cached-path))))\n          (if (= (verify-image-cid image) expected-image-cid)\n            (deserialize-image image)\n            ;; Cache corrupted — rebuild\n            (build-and-cache-image spec-cids image-cache-dir)))\n        ;; Cold path: evaluate from source\n        (build-and-cache-image spec-cids image-cache-dir)))))" "lisp")))

      (~docs/subsection :title "Client Boot"
        (p "The client already caches component definitions in localStorage keyed by bundle hash. Images extend this: cache the entire evaluated environment, not just individual components.")
        (ol (~tw :tokens "list-decimal pl-5 text-stone-700 space-y-1")
          (li "Page ships " (code "SX-Image") " header with image CID")
          (li "Client checks localStorage for " (code "sx-image:{cid}"))
          (li "If hit: deserialize and boot (no component-by-component parsing)")
          (li "If miss: fetch image from origin or IPFS, deserialize, cache")
          (li "Same cache-forever semantics as component CIDs — content can't be stale"))
        (p "First visit to any SX-powered site: one image fetch. Every subsequent visit: instant boot from cache. Cross-site: if two sites share the same spec CIDs, the image is shared too.")))

    ;; -----------------------------------------------------------------------
    ;; Standalone HTML
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Standalone HTML Bundles" :id "standalone"
      (p "An image can be inlined into a single HTML document, producing a fully self-contained application with no server dependency:")

      (~docs/code :src (highlight "<!doctype html>\n<html>\n<head>\n  <script type=\"text/sx-image\">\n    (sx-image\n      :version 1\n      :spec-cids {...}\n      :components (...)\n      :macros (...)\n      :bindings (...))\n  </script>\n  <script type=\"text/sx-pages\">\n    (defpage home :path \"/\" :content (~home-page))\n  </script>\n  <script src=\"sx-ref.js\"></script>\n</head>\n<body>\n  <div id=\"app\"></div>\n  <script>\n    // Deserialize image, register components, render\n    Sx.bootFromImage(document.querySelector('[type=\"text/sx-image\"]'))\n  </script>\n</body>\n</html>" "html"))

      (p "This document is its own CID. Pin it to IPFS and it's a permanent, executable, verifiable application. No origin server, no CDN, no DNS. The content network is the deployment target.")

      (div (~tw :tokens "rounded border border-amber-200 bg-amber-50 p-4 mt-4")
        (p (~tw :tokens "text-amber-900 font-medium") "Juno comparison")
        (p (~tw :tokens "text-amber-800") "Juno's Seedling IDE already does this — export a running environment as a standalone HTML file. But their images are opaque JavaScript blobs serialized by the runtime. SX images are " (strong "s-expressions") " — parseable, inspectable, content-addressable. You can diff two SX images and see exactly what changed. You can extract a single component from an image by CID. You can merge images from different sources by composing their component lists. The format IS the tooling.")))

    ;; -----------------------------------------------------------------------
    ;; Namespace scoping
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Namespaced Environments" :id "namespaces"
      (p "As the component library grows across services, a flat environment risks name collisions. Images provide a natural boundary for namespace scoping.")

      (~docs/code :src (highlight "(sx-image\n  :version 1\n  :namespace \"market\"\n  :spec-cids {...}\n  :extends \"bafy...shared-image\"  ;; inherits shared components\n  :components (\n    ;; market-specific components\n    (defcomp ~plans/environment-images/product-card ...)\n    (defcomp ~plans/environment-images/price-tag ...)\n  ))" "lisp"))

      (p "Resolution: " (code "market/~plans/environment-images/product-card") " → look in market image first, then fall through to the shared image (via " (code ":extends") "). Each service produces its own image, layered on top of the shared base.")

      (div (~tw :tokens "overflow-x-auto rounded border border-stone-200 mb-4")
        (table (~tw :tokens "w-full text-left text-sm")
          (thead (tr (~tw :tokens "border-b border-stone-200 bg-stone-100")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Image")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Contents")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Extends")))
          (tbody
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "bafy...shared")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "~plans/environment-images/card, ~plans/environment-images/nav, ~nav-data/section-nav, ~docs/page, ~docs/code — shared components from " (code "shared/sx/templates/"))
              (td (~tw :tokens "px-3 py-2 text-stone-600") "None (root)"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "bafy...blog")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "~shared:cards/post-card, ~post-body, ~tag-list — blog-specific from " (code "blog/sx/"))
              (td (~tw :tokens "px-3 py-2 text-stone-600") "bafy...shared"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "bafy...market")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "~plans/environment-images/product-card, ~plans/environment-images/price-tag, ~shared:fragments/cart-mini — market-specific from " (code "market/sx/"))
              (td (~tw :tokens "px-3 py-2 text-stone-600") "bafy...shared"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "bafy...sx-docs")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "~docs/section, ~examples/source, plans, essays — sx docs from " (code "sx/sx/"))
              (td (~tw :tokens "px-3 py-2 text-stone-600") "bafy...shared")))))

      (p "The " (code ":extends") " field is a CID, not a name. Image composition is content-addressed: changing the shared image produces a new shared CID, which invalidates all service images that extend it. Exactly the right cascading behavior."))

    ;; -----------------------------------------------------------------------
    ;; Spec → Image → Page chain
    ;; -----------------------------------------------------------------------

    (~docs/section :title "The Verification Chain" :id "chain"
      (p "The full provenance chain from served page back to source:")

      (~docs/code :src (highlight ";; 1. Page served with provenance headers\n;;\n;; SX-Spec: bafy...eval,bafy...render,...\n;; SX-Image: bafy...market-image\n;; SX-Page: (defpage product :path \"/products/<slug>\" ...)\n;;\n;; 2. Verify image → spec\n;;\n;; Fetch specs by CID → evaluate → build image → compare CID\n;; If match: the image was correctly produced from these specs\n;;\n;; 3. Verify page → image\n;;\n;; Deserialize image → evaluate page defn → render\n;; If output matches served HTML: the page was correctly rendered\n;;\n;; 4. Trust chain terminates at the spec\n;;\n;; The spec is self-hosting (eval.sx evaluates itself)\n;; The spec's CID is its identity\n;; No external trust anchor needed beyond the hash function" "lisp"))

      (p "This is stronger than code signing. Code signing says " (em "\"this entity vouches for this binary.\"") " Content addressing says " (em "\"this binary is the deterministic output of this source.\"") " No entity needed. No certificate authority. No revocation lists. Just math."))

    ;; -----------------------------------------------------------------------
    ;; Implementation phases
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Implementation" :id "implementation"

      (~docs/subsection :title "Phase 1: Image Serialization"
        (p "Spec module " (code "image.sx") " — serialize and deserialize evaluated environments.")
        (ul (~tw :tokens "list-disc pl-5 text-stone-700 space-y-1")
          (li (code "serialize-environment") " — walk the env, extract components/macros/bindings, produce " (code "(sx-image ...)") " form")
          (li (code "deserialize-image") " — parse image, reconstitute components/macros/bindings into env")
          (li (code "image-cid") " — canonical-serialize the image form, hash → CID")
          (li "Must handle closure serialization — component closures reference other components by name, which must be re-linked on deserialization")))

      (~docs/subsection :title "Phase 2: Spec Provenance"
        (p "Compute CIDs for all spec files at startup. Attach to environment metadata.")
        (ul (~tw :tokens "list-disc pl-5 text-stone-700 space-y-1")
          (li "Hash each spec file's canonical source at load time")
          (li "Store in env metadata as " (code ":spec-cids") " dict")
          (li "Include in image serialization")))

      (~docs/subsection :title "Phase 3: Server-Side Caching"
        (p "Cache images on disk keyed by spec CIDs. Skip evaluation on warm restart.")
        (ul (~tw :tokens "list-disc pl-5 text-stone-700 space-y-1")
          (li "On startup: compute spec CIDs → derive expected image CID → check cache")
          (li "Cache hit: deserialize (parse only, no eval)")
          (li "Cache miss: evaluate specs, serialize image, write cache")
          (li "Any spec file change → new spec CID → new image CID → cache miss → rebuild")))

      (~docs/subsection :title "Phase 4: Client Images"
        (p "Ship image CID in response headers. Client caches full env in localStorage.")
        (ul (~tw :tokens "list-disc pl-5 text-stone-700 space-y-1")
          (li (code "SX-Image") " response header with image CID")
          (li "Client boot checks localStorage for cached image")
          (li "Cache hit: deserialize, skip per-component fetch/parse")
          (li "Cache miss: fetch image (single request), deserialize, cache")))

      (~docs/subsection :title "Phase 5: Standalone Export"
        (p "Generate self-contained HTML with inlined image. Pin to IPFS.")
        (ul (~tw :tokens "list-disc pl-5 text-stone-700 space-y-1")
          (li "Inline " (code "(sx-image ...)") " as " (code "<script type=\"text/sx-image\">"))
          (li "Inline page definitions as " (code "<script type=\"text/sx-pages\">"))
          (li "Include sx-ref.js (or link to its CID)")
          (li "The resulting HTML is a complete application — pin its CID to IPFS")))

      (~docs/subsection :title "Phase 6: Namespaced Images"
        (p "Per-service images with " (code ":extends") " for layered composition.")
        (ul (~tw :tokens "list-disc pl-5 text-stone-700 space-y-1")
          (li "Shared image: components from " (code "shared/sx/templates/"))
          (li "Service images: extend shared, add service-specific components")
          (li "Resolution: service image → shared image → primitives")
          (li "Image merge: combine two images with conflict detection"))))

    ;; -----------------------------------------------------------------------
    ;; Dependencies
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Dependencies" :id "dependencies"
      (p "What must exist before this plan can execute:")
      (div (~tw :tokens "overflow-x-auto rounded border border-stone-200 mb-4")
        (table (~tw :tokens "w-full text-left text-sm")
          (thead (tr (~tw :tokens "border-b border-stone-200 bg-stone-100")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Dependency")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Status")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Plan")))
          (tbody
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Canonical serialization")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (span (~tw :tokens "text-red-700 font-medium") "Not started"))
              (td (~tw :tokens "px-3 py-2") (a :href "/sx/(etc.(plan.content-addressed-components))" (~tw :tokens "text-violet-700 underline") "Content-Addressed Components") " Phase 1"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Component CIDs")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (span (~tw :tokens "text-red-700 font-medium") "Not started"))
              (td (~tw :tokens "px-3 py-2") (a :href "/sx/(etc.(plan.content-addressed-components))" (~tw :tokens "text-violet-700 underline") "Content-Addressed Components") " Phase 2"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Purity verification")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (span (~tw :tokens "text-green-700 font-medium") "Complete"))
              (td (~tw :tokens "px-3 py-2 text-stone-600") "deps.sx + boundary.py"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Self-hosting spec")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (span (~tw :tokens "text-green-700 font-medium") "Complete"))
              (td (~tw :tokens "px-3 py-2 text-stone-600") "eval.sx, render.sx, parser.sx, ..."))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Self-hosting bootstrappers")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (span (~tw :tokens "text-green-700 font-medium") "Complete"))
              (td (~tw :tokens "px-3 py-2 text-stone-600") "py.sx, js.sx — G0 == G1"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "IPFS infrastructure")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (span (~tw :tokens "text-green-700 font-medium") "Exists"))
              (td (~tw :tokens "px-3 py-2 text-stone-600") "artdag L1/L2, IPFSPin model")))))

      (div (~tw :tokens "rounded border border-amber-200 bg-amber-50 p-3 mt-2")
        (p (~tw :tokens "text-amber-800 text-sm") (strong "Builds on: ") (a :href "/sx/(etc.(plan.content-addressed-components))" (~tw :tokens "underline") "Content-Addressed Components") " (canonical serialization + CIDs), " (a :href "/sx/(etc.(plan.self-hosting-bootstrapper))" (~tw :tokens "underline") "self-hosting bootstrappers") " (spec-first architecture). " (strong "Enables: ") (a :href "/sx/(etc.(plan.sx-activity))" (~tw :tokens "underline") "SX-Activity") " (serverless applications on IPFS).")))))
