Rename all 1,169 components to path-based names with namespace support
Component names now reflect filesystem location using / as path separator and : as namespace separator for shared components: ~sx-header → ~layouts/header ~layout-app-body → ~shared:layout/app-body ~blog-admin-dashboard → ~admin/dashboard 209 files, 4,941 replacements across all services. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,15 +2,15 @@
|
||||
;; SX-Activity: Federated SX over ActivityPub
|
||||
;; ---------------------------------------------------------------------------
|
||||
|
||||
(defcomp ~plan-sx-activity-content ()
|
||||
(~doc-page :title "SX-Activity"
|
||||
(defcomp ~plans/sx-activity/plan-sx-activity-content ()
|
||||
(~docs/page :title "SX-Activity"
|
||||
|
||||
(~doc-section :title "Context" :id "context"
|
||||
(~docs/section :title "Context" :id "context"
|
||||
(p "The web is six incompatible formats duct-taped together: HTML for structure, CSS for style, JavaScript for behavior, JSON for data, server languages for backend logic, build tools for compilation. Moving anything between layers requires serialization, template languages, API contracts, and glue code. Federation (ActivityPub) adds a seventh — JSON-LD — which is inert data that every consumer must interpret from scratch and wrap in their own UI.")
|
||||
(p "SX is already one evaluable format that does all six. A component definition is simultaneously structure, style (components apply classes and respond to data), behavior (event handlers), data (the AST " (em "is") " data), server-renderable (Python evaluator), and client-renderable (JS evaluator). The pieces already exist: content-addressed DAG execution (artdag), IPFS storage with CIDs, OpenTimestamps Bitcoin anchoring, boundary-enforced sandboxing.")
|
||||
(p "SX-Activity wires these together into a new web. Everything — content, UI components, markdown parsers, syntax highlighters, validation logic, media, processing pipelines — is the same executable format, stored on a content-addressed network, running within each participant's own security context. " (strong "The wire format is the programming language is the component system is the package manager.")))
|
||||
|
||||
(~doc-section :title "Current State" :id "current-state"
|
||||
(~docs/section :title "Current State" :id "current-state"
|
||||
(ul :class "space-y-2 text-stone-700 list-disc pl-5"
|
||||
(li (strong "ActivityPub: ") "Full implementation — virtual per-app actors, HTTP signatures, webfinger, inbox/outbox, followers/following, delivery with idempotent logging.")
|
||||
(li (strong "Activity bus: ") "Unified event bus with NOTIFY/LISTEN wakeup, at-least-once delivery, handler registry keyed by (activity_type, object_type).")
|
||||
@@ -23,28 +23,28 @@
|
||||
;; Phase 1: SX Wire Format for Activities
|
||||
;; -----------------------------------------------------------------------
|
||||
|
||||
(~doc-section :title "Phase 1: SX Wire Format for Activities" :id "phase-1"
|
||||
(~docs/section :title "Phase 1: SX Wire Format for Activities" :id "phase-1"
|
||||
|
||||
(div :class "rounded border border-violet-200 bg-violet-50 p-4 mb-4"
|
||||
(p :class "text-violet-900 font-medium" "What it enables")
|
||||
(p :class "text-violet-800" "Activities expressed as s-expressions instead of JSON-LD. Same semantics as ActivityStreams, but compact, parseable, and directly evaluable. Dual-format support for backward compatibility with existing AP servers."))
|
||||
|
||||
(~doc-subsection :title "The Problem"
|
||||
(~docs/subsection :title "The Problem"
|
||||
(p "JSON-LD activities are verbose and require context resolution:")
|
||||
(~doc-code :code (highlight "{\"@context\": \"https://www.w3.org/ns/activitystreams\",\n \"type\": \"Create\",\n \"actor\": \"https://example.com/users/alice\",\n \"object\": {\n \"type\": \"Note\",\n \"content\": \"<p>Hello world</p>\",\n \"attributedTo\": \"https://example.com/users/alice\"\n }}" "json"))
|
||||
(~docs/code :code (highlight "{\"@context\": \"https://www.w3.org/ns/activitystreams\",\n \"type\": \"Create\",\n \"actor\": \"https://example.com/users/alice\",\n \"object\": {\n \"type\": \"Note\",\n \"content\": \"<p>Hello world</p>\",\n \"attributedTo\": \"https://example.com/users/alice\"\n }}" "json"))
|
||||
(p "Every consumer parses JSON, resolves @context, extracts fields, then builds their own UI around the raw data. The content is HTML embedded in a JSON string — two formats nested, neither evaluable."))
|
||||
|
||||
(~doc-subsection :title "SX Activity Format"
|
||||
(~docs/subsection :title "SX Activity Format"
|
||||
(p "The same activity as SX:")
|
||||
(~doc-code :code (highlight "(Create\n :actor \"https://example.com/users/alice\"\n :published \"2026-03-06T12:00:00Z\"\n :object (Note\n :attributed-to \"https://example.com/users/alice\"\n :content (p \"Hello world\")\n :media-type \"text/sx\"))" "lisp"))
|
||||
(~docs/code :code (highlight "(Create\n :actor \"https://example.com/users/alice\"\n :published \"2026-03-06T12:00:00Z\"\n :object (Note\n :attributed-to \"https://example.com/users/alice\"\n :content (p \"Hello world\")\n :media-type \"text/sx\"))" "lisp"))
|
||||
(p "The content isn't a string containing markup — it " (em "is") " markup. The receiving server can evaluate it directly. The Note's content is a renderable SX expression."))
|
||||
|
||||
(~doc-subsection :title "Approach"
|
||||
(~docs/subsection :title "Approach"
|
||||
(div :class "space-y-4"
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "1. Activity vocabulary in SX")
|
||||
(p "Map ActivityStreams types to SX symbols. Activities are lists with a type head and keyword properties:")
|
||||
(~doc-code :code (highlight ";; Core activity types\n(Create :actor ... :object ...)\n(Update :actor ... :object ...)\n(Delete :actor ... :object ...)\n(Follow :actor ... :object ...)\n(Like :actor ... :object ...)\n(Announce :actor ... :object ...)\n\n;; Object types\n(Note :content ... :attributed-to ...)\n(Article :name ... :content ... :summary ...)\n(Image :url ... :media-type ... :cid ...)\n(Collection :total-items ... :items ...)" "lisp")))
|
||||
(~docs/code :code (highlight ";; Core activity types\n(Create :actor ... :object ...)\n(Update :actor ... :object ...)\n(Delete :actor ... :object ...)\n(Follow :actor ... :object ...)\n(Like :actor ... :object ...)\n(Announce :actor ... :object ...)\n\n;; Object types\n(Note :content ... :attributed-to ...)\n(Article :name ... :content ... :summary ...)\n(Image :url ... :media-type ... :cid ...)\n(Collection :total-items ... :items ...)" "lisp")))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "2. Content negotiation")
|
||||
@@ -58,7 +58,7 @@
|
||||
(h4 :class "font-semibold text-stone-700" "4. HTTP Signatures over SX")
|
||||
(p "Same RSA signature mechanism. Digest header computed over the SX body. Existing keypair infrastructure unchanged."))))
|
||||
|
||||
(~doc-subsection :title "Verification"
|
||||
(~docs/subsection :title "Verification"
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li "Round-trip: SX → JSON-LD → SX produces identical output")
|
||||
(li "Legacy AP servers receive valid JSON-LD (Mastodon can display the post)")
|
||||
@@ -69,28 +69,28 @@
|
||||
;; Phase 2: Content-Addressed Components on IPFS
|
||||
;; -----------------------------------------------------------------------
|
||||
|
||||
(~doc-section :title "Phase 2: Content-Addressed Components on IPFS" :id "phase-2"
|
||||
(~docs/section :title "Phase 2: Content-Addressed Components on IPFS" :id "phase-2"
|
||||
|
||||
(div :class "rounded border border-violet-200 bg-violet-50 p-4 mb-4"
|
||||
(p :class "text-violet-900 font-medium" "What it enables")
|
||||
(p :class "text-violet-800" "Component definitions stored on IPFS, referenced by CID. Any server can publish components. Any browser can fetch them. No central registry — content addressing IS the registry."))
|
||||
|
||||
(~doc-subsection :title "The Insight"
|
||||
(~docs/subsection :title "The Insight"
|
||||
(p "SX components are pure functions — they take data and return markup. They can't do IO (boundary enforcement guarantees this). That means they're " (strong "safe to load from any source") ". And if they're content-addressed, the CID " (em "is") " the identity — you don't need to trust the source, you just verify the hash.")
|
||||
(p "Currently, component definitions travel with each page via " (code "<script type=\"text/sx\" data-components>") ". Each server bundles its own. With IPFS, components become shared infrastructure — define once, use everywhere."))
|
||||
|
||||
(~doc-subsection :title "Approach"
|
||||
(~docs/subsection :title "Approach"
|
||||
(div :class "space-y-4"
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "1. Component CID computation")
|
||||
(p "Each " (code "defcomp") " definition gets a content address:")
|
||||
(~doc-code :code (highlight ";; Component source\n(defcomp ~card (&key title &rest children)\n (div :class \"border rounded p-4\"\n (h2 title) children))\n\n;; CID = SHA3-256 of canonical serialized form\n;; → bafy...abc123\n;; Stored: ipfs://bafy...abc123 → component source" "lisp"))
|
||||
(~docs/code :code (highlight ";; Component source\n(defcomp ~plans/sx-activity/card (&key title &rest children)\n (div :class \"border rounded p-4\"\n (h2 title) children))\n\n;; CID = SHA3-256 of canonical serialized form\n;; → bafy...abc123\n;; Stored: ipfs://bafy...abc123 → component source" "lisp"))
|
||||
(p "Canonical form: normalize whitespace, sort keyword args alphabetically, strip comments. Same component always produces same CID regardless of formatting."))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "2. Component references in activities")
|
||||
(p "Activities declare which components they need by CID:")
|
||||
(~doc-code :code (highlight "(Create\n :actor \"https://rose-ash.com/users/alice\"\n :requires (list\n \"bafy...card\" ;; ~card component\n \"bafy...avatar\") ;; ~avatar component\n :object (Note\n :content (~card :title \"Hello\"\n (~avatar :src \"ipfs://bafy...photo\")\n (p \"This renders with the card component.\"))))" "lisp"))
|
||||
(~docs/code :code (highlight "(Create\n :actor \"https://rose-ash.com/users/alice\"\n :requires (list\n \"bafy...card\" ;; ~plans/sx-activity/card component\n \"bafy...avatar\") ;; ~shared:misc/avatar component\n :object (Note\n :content (~plans/sx-activity/card :title \"Hello\"\n (~shared:misc/avatar :src \"ipfs://bafy...photo\")\n (p \"This renders with the card component.\"))))" "lisp"))
|
||||
(p "The receiving browser fetches missing components from IPFS, verifies CIDs, registers them, then renders the content."))
|
||||
|
||||
(div
|
||||
@@ -106,9 +106,9 @@
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "4. Component publication")
|
||||
(p "Server-side: on component registration, compute CID and pin to IPFS. Track in " (code "IPFSPin") " model (already exists). Publish component availability via AP outbox:")
|
||||
(~doc-code :code (highlight "(Create\n :actor \"https://rose-ash.com/apps/market\"\n :object (SxComponent\n :name \"~product-card\"\n :cid \"bafy...productcard\"\n :version \"1.0.0\"\n :deps (list \"bafy...card\" \"bafy...price-tag\")))" "lisp")))))
|
||||
(~docs/code :code (highlight "(Create\n :actor \"https://rose-ash.com/apps/market\"\n :object (SxComponent\n :name \"~product-card\"\n :cid \"bafy...productcard\"\n :version \"1.0.0\"\n :deps (list \"bafy...card\" \"bafy...price-tag\")))" "lisp")))))
|
||||
|
||||
(~doc-subsection :title "Verification"
|
||||
(~docs/subsection :title "Verification"
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li "Component pinned to IPFS → fetchable via gateway → CID verifies")
|
||||
(li "Browser renders federated post using IPFS-fetched components")
|
||||
@@ -119,32 +119,32 @@
|
||||
;; Phase 3: Federated Media & Content Store
|
||||
;; -----------------------------------------------------------------------
|
||||
|
||||
(~doc-section :title "Phase 3: Federated Media & Content Store" :id "phase-3"
|
||||
(~docs/section :title "Phase 3: Federated Media & Content Store" :id "phase-3"
|
||||
|
||||
(div :class "rounded border border-violet-200 bg-violet-50 p-4 mb-4"
|
||||
(p :class "text-violet-900 font-medium" "What it enables")
|
||||
(p :class "text-violet-800" "All media (images, video, audio, DAG outputs) stored content-addressed on IPFS. Activities reference media by CID. No hotlinking, no broken links, no dependence on the origin server staying online."))
|
||||
|
||||
(~doc-subsection :title "Current Mechanism"
|
||||
(~docs/subsection :title "Current Mechanism"
|
||||
(p "artdag already content-addresses all DAG outputs with SHA3-256 and tracks IPFS CIDs in " (code "IPFSPin") ". But media in the web platform (blog images, product photos, event banners) is stored as regular files on the origin server. Federated posts include " (code "url") " fields pointing to the origin — if the server goes down, the media is gone."))
|
||||
|
||||
(~doc-subsection :title "Approach"
|
||||
(~docs/subsection :title "Approach"
|
||||
(div :class "space-y-4"
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "1. Media CID pipeline")
|
||||
(p "On upload: hash content → pin to IPFS → store CID in database. Activities reference media by CID alongside URL fallback:")
|
||||
(~doc-code :code (highlight "(Image\n :cid \"bafy...photo123\"\n :url \"https://rose-ash.com/media/photo.jpg\" ;; fallback\n :media-type \"image/jpeg\"\n :width 1200 :height 800)" "lisp")))
|
||||
(~docs/code :code (highlight "(Image\n :cid \"bafy...photo123\"\n :url \"https://rose-ash.com/media/photo.jpg\" ;; fallback\n :media-type \"image/jpeg\"\n :width 1200 :height 800)" "lisp")))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "2. DAG output federation")
|
||||
(p "artdag processing results (rendered video, processed images) already have CIDs. Federate them as activities:")
|
||||
(~doc-code :code (highlight "(Create\n :actor \"https://rose-ash.com/users/alice\"\n :object (Artwork\n :name \"Sunset Remix\"\n :cid \"bafy...artwork\"\n :dag-cid \"bafy...dag\" ;; full DAG for reproduction\n :media-type \"video/mp4\"\n :sources (list\n (Image :cid \"bafy...src1\" :attribution \"...\")\n (Image :cid \"bafy...src2\" :attribution \"...\"))))" "lisp"))
|
||||
(~docs/code :code (highlight "(Create\n :actor \"https://rose-ash.com/users/alice\"\n :object (Artwork\n :name \"Sunset Remix\"\n :cid \"bafy...artwork\"\n :dag-cid \"bafy...dag\" ;; full DAG for reproduction\n :media-type \"video/mp4\"\n :sources (list\n (Image :cid \"bafy...src1\" :attribution \"...\")\n (Image :cid \"bafy...src2\" :attribution \"...\"))))" "lisp"))
|
||||
(p "The " (code ":dag-cid") " lets anyone re-execute the processing pipeline. The artwork is both a result and a reproducible recipe."))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "3. Shared SX content store")
|
||||
(p "Not just components and media — full page content can be content-addressed. An Article's body is SX, pinned to IPFS:")
|
||||
(~doc-code :code (highlight "(Article\n :name \"Why S-Expressions\"\n :content-cid \"bafy...article-body\" ;; SX source on IPFS\n :requires (list \"bafy...doc-page\" \"bafy...code-block\")\n :summary \"Why SX uses s-expressions instead of HTML.\")" "lisp"))
|
||||
(~docs/code :code (highlight "(Article\n :name \"Why S-Expressions\"\n :content-cid \"bafy...article-body\" ;; SX source on IPFS\n :requires (list \"bafy...doc-page\" \"bafy...code-block\")\n :summary \"Why SX uses s-expressions instead of HTML.\")" "lisp"))
|
||||
(p "The content outlives the server. Anyone with the CID can fetch, parse, and render the article with its original components."))
|
||||
|
||||
(div
|
||||
@@ -156,7 +156,7 @@
|
||||
(li "Large media uses IPFS streaming (chunked CIDs)")
|
||||
(li "Integrates with Phase 6 of isomorphic plan (streaming/suspense)")))))
|
||||
|
||||
(~doc-subsection :title "Verification"
|
||||
(~docs/subsection :title "Verification"
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li "Origin server offline → content still resolvable via IPFS gateway")
|
||||
(li "DAG CID → re-executing DAG produces identical output")
|
||||
@@ -166,23 +166,23 @@
|
||||
;; Phase 4: Component Registry & Discovery
|
||||
;; -----------------------------------------------------------------------
|
||||
|
||||
(~doc-section :title "Phase 4: Component Registry & Discovery" :id "phase-4"
|
||||
(~docs/section :title "Phase 4: Component Registry & Discovery" :id "phase-4"
|
||||
|
||||
(div :class "rounded border border-violet-200 bg-violet-50 p-4 mb-4"
|
||||
(p :class "text-violet-900 font-medium" "What it enables")
|
||||
(p :class "text-violet-800" "Federated component discovery. Servers publish component collections. Other servers follow component feeds. Like npm, but federated, content-addressed, and the packages are safe to run (pure functions, no IO)."))
|
||||
|
||||
(~doc-subsection :title "Approach"
|
||||
(~docs/subsection :title "Approach"
|
||||
(div :class "space-y-4"
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "1. Component collections as AP actors")
|
||||
(p "Each server exposes a component registry actor:")
|
||||
(~doc-code :code (highlight "(Service\n :id \"https://rose-ash.com/sx-registry\"\n :type \"SxComponentRegistry\"\n :name \"Rose Ash Components\"\n :outbox \"https://rose-ash.com/sx-registry/outbox\"\n :followers \"https://rose-ash.com/sx-registry/followers\")" "lisp"))
|
||||
(~docs/code :code (highlight "(Service\n :id \"https://rose-ash.com/sx-registry\"\n :type \"SxComponentRegistry\"\n :name \"Rose Ash Components\"\n :outbox \"https://rose-ash.com/sx-registry/outbox\"\n :followers \"https://rose-ash.com/sx-registry/followers\")" "lisp"))
|
||||
(p "Follow the registry to receive component updates. The outbox is a chronological feed of Create/Update/Delete activities for components."))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "2. Component metadata")
|
||||
(~doc-code :code (highlight "(SxComponent\n :name \"~data-table\"\n :cid \"bafy...datatable\"\n :version \"2.1.0\"\n :deps (list \"bafy...sortable\" \"bafy...paginator\")\n :params (list\n (dict :name \"rows\" :type \"list\" :required true)\n (dict :name \"columns\" :type \"list\" :required true)\n (dict :name \"sortable\" :type \"boolean\" :default false))\n :css-atoms (list :border :rounded :p-4 :text-sm)\n :preview-cid \"bafy...screenshot\"\n :license \"MIT\")" "lisp"))
|
||||
(~docs/code :code (highlight "(SxComponent\n :name \"~data-table\"\n :cid \"bafy...datatable\"\n :version \"2.1.0\"\n :deps (list \"bafy...sortable\" \"bafy...paginator\")\n :params (list\n (dict :name \"rows\" :type \"list\" :required true)\n (dict :name \"columns\" :type \"list\" :required true)\n (dict :name \"sortable\" :type \"boolean\" :default false))\n :css-atoms (list :border :rounded :p-4 :text-sm)\n :preview-cid \"bafy...screenshot\"\n :license \"MIT\")" "lisp"))
|
||||
(p "Dependencies are transitive CID references. CSS atoms declare which CSSX rules the component needs. Preview CID is a screenshot for registry browsing."))
|
||||
|
||||
(div
|
||||
@@ -197,9 +197,9 @@
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "4. Version resolution")
|
||||
(p "Components are immutable (CID = identity). \"Updating\" a component publishes a new CID. Activities reference specific CIDs, so old content always renders correctly. The registry tracks version history:")
|
||||
(~doc-code :code (highlight "(Update\n :actor \"https://rose-ash.com/sx-registry\"\n :object (SxComponent\n :name \"~card\"\n :cid \"bafy...card-v2\" ;; new version\n :replaces \"bafy...card-v1\" ;; previous version\n :changelog \"Added subtitle slot\"))" "lisp")))))
|
||||
(~docs/code :code (highlight "(Update\n :actor \"https://rose-ash.com/sx-registry\"\n :object (SxComponent\n :name \"~card\"\n :cid \"bafy...card-v2\" ;; new version\n :replaces \"bafy...card-v1\" ;; previous version\n :changelog \"Added subtitle slot\"))" "lisp")))))
|
||||
|
||||
(~doc-subsection :title "Verification"
|
||||
(~docs/subsection :title "Verification"
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li "Follow registry → receive component Create activities → components available locally")
|
||||
(li "Render post using component from foreign registry → works")
|
||||
@@ -209,16 +209,16 @@
|
||||
;; Phase 5: Bitcoin-Anchored Provenance
|
||||
;; -----------------------------------------------------------------------
|
||||
|
||||
(~doc-section :title "Phase 5: Bitcoin-Anchored Provenance" :id "phase-5"
|
||||
(~docs/section :title "Phase 5: Bitcoin-Anchored Provenance" :id "phase-5"
|
||||
|
||||
(div :class "rounded border border-violet-200 bg-violet-50 p-4 mb-4"
|
||||
(p :class "text-violet-900 font-medium" "What it enables")
|
||||
(p :class "text-violet-800" "Cryptographic proof that content existed at a specific time, authored by a specific actor. Leverages the existing APAnchor/OpenTimestamps infrastructure. Unforgeable, independently verifiable, survives server shutdown."))
|
||||
|
||||
(~doc-subsection :title "Current Mechanism"
|
||||
(~docs/subsection :title "Current Mechanism"
|
||||
(p "The " (code "APAnchor") " model already batches activities into Merkle trees, stores the tree on IPFS, creates an OpenTimestamps proof, and records the Bitcoin txid. This runs but isn't surfaced to users or integrated with the full activity lifecycle."))
|
||||
|
||||
(~doc-subsection :title "Approach"
|
||||
(~docs/subsection :title "Approach"
|
||||
(div :class "space-y-4"
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "1. Automatic anchoring pipeline")
|
||||
@@ -232,7 +232,7 @@
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "2. Provenance chain in activities")
|
||||
(~doc-code :code (highlight "(Create\n :actor \"https://rose-ash.com/users/alice\"\n :object (Note :content (p \"Hello\") :cid \"bafy...note\")\n :provenance (Anchor\n :tree-cid \"bafy...merkle-tree\"\n :leaf-index 42\n :ots-cid \"bafy...ots-proof\"\n :btc-txid \"abc123...def\"\n :btc-block 890123\n :anchored-at \"2026-03-06T12:00:00Z\"))" "lisp"))
|
||||
(~docs/code :code (highlight "(Create\n :actor \"https://rose-ash.com/users/alice\"\n :object (Note :content (p \"Hello\") :cid \"bafy...note\")\n :provenance (Anchor\n :tree-cid \"bafy...merkle-tree\"\n :leaf-index 42\n :ots-cid \"bafy...ots-proof\"\n :btc-txid \"abc123...def\"\n :btc-block 890123\n :anchored-at \"2026-03-06T12:00:00Z\"))" "lisp"))
|
||||
(p "Any party can verify: fetch the OTS proof from IPFS, check the Merkle path from the activity's CID to the tree root, confirm the tree root is committed in the Bitcoin block."))
|
||||
|
||||
(div
|
||||
@@ -246,9 +246,9 @@
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "4. Verification UI")
|
||||
(p "Client-side provenance badge on federated content:")
|
||||
(~doc-code :code (highlight "(defcomp ~provenance-badge (&key anchor)\n (when anchor\n (details :class \"inline text-xs text-stone-400\"\n (summary \"✓ Anchored\")\n (dl :class \"mt-1 space-y-1\"\n (dt \"Bitcoin block\") (dd (get anchor \"btc-block\"))\n (dt \"Timestamp\") (dd (get anchor \"anchored-at\"))\n (dt \"Proof\") (dd (a :href (str \"ipfs://\" (get anchor \"ots-cid\"))\n \"OTS proof\"))))))" "lisp")))))
|
||||
(~docs/code :code (highlight "(defcomp ~plans/sx-activity/provenance-badge (&key anchor)\n (when anchor\n (details :class \"inline text-xs text-stone-400\"\n (summary \"✓ Anchored\")\n (dl :class \"mt-1 space-y-1\"\n (dt \"Bitcoin block\") (dd (get anchor \"btc-block\"))\n (dt \"Timestamp\") (dd (get anchor \"anchored-at\"))\n (dt \"Proof\") (dd (a :href (str \"ipfs://\" (get anchor \"ots-cid\"))\n \"OTS proof\"))))))" "lisp")))))
|
||||
|
||||
(~doc-subsection :title "Verification"
|
||||
(~docs/subsection :title "Verification"
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li "Activity anchored → OTS proof fetchable from IPFS → Merkle path validates → txid confirms in Bitcoin")
|
||||
(li "Tampered activity → Merkle proof fails → provenance badge shows ✗")
|
||||
@@ -258,18 +258,18 @@
|
||||
;; Phase 6: The Evaluable Web
|
||||
;; -----------------------------------------------------------------------
|
||||
|
||||
(~doc-section :title "Phase 6: The Evaluable Web" :id "phase-6"
|
||||
(~docs/section :title "Phase 6: The Evaluable Web" :id "phase-6"
|
||||
|
||||
(div :class "rounded border border-violet-200 bg-violet-50 p-4 mb-4"
|
||||
(p :class "text-violet-900 font-medium" "What this really is")
|
||||
(p :class "text-violet-800" "Not ActivityPub-with-SX. A new web. One where everything — content, components, parsers, renderers, server logic, client logic — is the same executable format, shared on a content-addressed network, running within each participant's own security context."))
|
||||
|
||||
(~doc-subsection :title "The insight"
|
||||
(~docs/subsection :title "The insight"
|
||||
(p "The web has six layers that don't talk to each other: HTML (structure), CSS (style), JavaScript (behavior), JSON (data interchange), server frameworks (backend logic), and build tools (compilation). Each has its own syntax, its own semantics, its own ecosystem. Moving data between them requires serialization, deserialization, template languages, API contracts, type coercion, and an endless parade of glue code.")
|
||||
(p "SX collapses all six into one evaluable format. A component definition is simultaneously structure, style (components apply classes and respond to data), behavior (event handlers), data (the AST is data), server-renderable (Python evaluator), and client-renderable (JS evaluator). There is no boundary between \"data\" and \"program\" — s-expressions are both.")
|
||||
(p "Once that's true, " (strong "everything becomes shareable.") " Not just UI components — markdown parsers, syntax highlighters, date formatters, validation logic, layout algorithms, color systems, animation curves. Any pure function over data. All content-addressed, all on IPFS, all executable within your own security context."))
|
||||
|
||||
(~doc-subsection :title "What travels on the network"
|
||||
(~docs/subsection :title "What travels on the network"
|
||||
(div :class "space-y-4"
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "Content")
|
||||
@@ -282,7 +282,7 @@
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "Parsers and transforms")
|
||||
(p "A markdown parser is just an SX function: takes a string, returns an SX tree. Publish it to IPFS. Now anyone can use your markdown dialect. Same for: syntax highlighters, BBCode parsers, wiki markup, LaTeX subsets, CSV-to-table converters, JSON-to-SX adapters. " (strong "The parser ecosystem becomes shared infrastructure."))
|
||||
(~doc-code :code (highlight ";; A markdown parser, published to IPFS\n;; CID: bafy...md-parser\n(define parse-markdown\n (fn (source)\n ;; tokenize → build AST → return SX tree\n ;; (parse-markdown \"# Hello\\n**bold**\")\n ;; → (h1 \"Hello\") (p (strong \"bold\"))\n ...))\n\n;; Anyone can use it in their components\n(defcomp ~blog-post (&key markdown-source)\n (div :class \"prose\"\n (parse-markdown markdown-source)))" "lisp")))
|
||||
(~docs/code :code (highlight ";; A markdown parser, published to IPFS\n;; CID: bafy...md-parser\n(define parse-markdown\n (fn (source)\n ;; tokenize → build AST → return SX tree\n ;; (parse-markdown \"# Hello\\n**bold**\")\n ;; → (h1 \"Hello\") (p (strong \"bold\"))\n ...))\n\n;; Anyone can use it in their components\n(defcomp ~plans/sx-activity/blog-post (&key markdown-source)\n (div :class \"prose\"\n (parse-markdown markdown-source)))" "lisp")))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "Server-side and client-side logic")
|
||||
@@ -292,7 +292,7 @@
|
||||
(h4 :class "font-semibold text-stone-700" "Media and processing pipelines")
|
||||
(p "Images, video, audio — all content-addressed on IPFS. But also the " (em "processing pipelines") " that created them. artdag DAGs are SX. Publish a DAG CID alongside the output CID and anyone can verify the provenance, re-render at different resolution, or fork the pipeline for their own work."))))
|
||||
|
||||
(~doc-subsection :title "The security model"
|
||||
(~docs/subsection :title "The security model"
|
||||
(p "This only works because of boundary enforcement. Every piece of SX fetched from the network runs within the receiver's security context:")
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li (strong "Pure functions can't do IO. ") "A component from IPFS can produce markup — it cannot read your cookies, make network requests, access localStorage, or call any IO primitive. The boundary spec (boundary.sx) is enforced at registration time. This isn't a policy — it's structural. The evaluator literally doesn't have IO primitives available when running untrusted code.")
|
||||
@@ -302,7 +302,7 @@
|
||||
(li (strong "Provenance proves authorship. ") "Bitcoin-anchored timestamps prove who published what and when. Not \"trust me\" — independently verifiable against the Bitcoin blockchain."))
|
||||
(p "This is the opposite of the npm model. npm packages run with full access to your system — a malicious package can exfiltrate secrets, install backdoors, modify the filesystem. SX components are structurally sandboxed. The worst a malicious component can do is render a " (code "(div \"haha got you\")") "."))
|
||||
|
||||
(~doc-subsection :title "What this replaces"
|
||||
(~docs/subsection :title "What this replaces"
|
||||
(div :class "overflow-x-auto rounded border border-stone-200 mb-4"
|
||||
(table :class "w-full text-left text-sm"
|
||||
(thead (tr :class "border-b border-stone-200 bg-stone-100"
|
||||
@@ -347,10 +347,10 @@
|
||||
(td :class "px-3 py-2 text-stone-700" "IPFS CID")
|
||||
(td :class "px-3 py-2 text-stone-600" "Entire applications are content-addressed, no infrastructure needed"))))))
|
||||
|
||||
(~doc-subsection :title "Serverless applications on IPFS"
|
||||
(~docs/subsection :title "Serverless applications on IPFS"
|
||||
(p "The logical conclusion: " (strong "entire web applications hosted on IPFS with no server at all."))
|
||||
(p "An SX application is a tree of content-addressed artifacts: a root page definition, component dependencies, media, stylesheets, parsers, transforms. Pin the root CID to IPFS and the application is live. No server, no DNS, no hosting provider, no deployment pipeline. Someone gives you a CID, you paste it into an SX-aware browser, and the application runs.")
|
||||
(~doc-code :code (highlight ";; An entire blog — one CID\n;; ipfs://bafy...my-blog\n(defpage blog-home\n :path \"/\"\n :requires (list\n \"bafy...article-layout\" ;; layout component\n \"bafy...md-parser\" ;; markdown parser\n \"bafy...syntax-highlight\" ;; code highlighting\n \"bafy...nav-component\") ;; navigation\n :content\n (~article-layout\n :title \"My Blog\"\n :nav (~nav-component\n :items (list\n (dict :label \"Post 1\" :cid \"bafy...post-1\")\n (dict :label \"Post 2\" :cid \"bafy...post-2\")))\n :body (~markdown-page\n :source-cid \"bafy...homepage-md\")))" "lisp"))
|
||||
(~docs/code :code (highlight ";; An entire blog — one CID\n;; ipfs://bafy...my-blog\n(defpage blog-home\n :path \"/\"\n :requires (list\n \"bafy...article-layout\" ;; layout component\n \"bafy...md-parser\" ;; markdown parser\n \"bafy...syntax-highlight\" ;; code highlighting\n \"bafy...nav-component\") ;; navigation\n :content\n (~article-layout\n :title \"My Blog\"\n :nav (~nav-component\n :items (list\n (dict :label \"Post 1\" :cid \"bafy...post-1\")\n (dict :label \"Post 2\" :cid \"bafy...post-2\")))\n :body (~markdown-page\n :source-cid \"bafy...homepage-md\")))" "lisp"))
|
||||
(p "What this looks like in practice:")
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li (strong "Personal sites: ") "A portfolio or blog is a handful of SX files + media. Pin to IPFS. Share the CID. No hosting costs, no domain renewal, no SSL certificates. The site is permanent.")
|
||||
@@ -361,7 +361,7 @@
|
||||
(p "For applications that " (em "do") " need a server — user accounts, payments, real-time collaboration, database queries — the server provides IO primitives via the existing boundary system. The SX application fetches data from the server's IO endpoints, but the application itself (all the rendering, routing, component logic) lives on IPFS. The server is a " (em "data service") ", not an application host.")
|
||||
(p "This inverts the current model. Today: server hosts the application, client is a thin renderer. SX web: IPFS hosts the application, server is an optional IO provider. " (strong "The application is the content. The content is the application. Both are just s-expressions.")))
|
||||
|
||||
(~doc-subsection :title "The end state"
|
||||
(~docs/subsection :title "The end state"
|
||||
(p "A browser with an SX evaluator and an IPFS gateway is a complete web platform. Given a CID — for a page, a post, an application — it can:")
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li "Fetch the content from IPFS")
|
||||
@@ -378,30 +378,30 @@
|
||||
;; Cross-Cutting Concerns
|
||||
;; -----------------------------------------------------------------------
|
||||
|
||||
(~doc-section :title "Cross-Cutting Concerns" :id "cross-cutting"
|
||||
(~docs/section :title "Cross-Cutting Concerns" :id "cross-cutting"
|
||||
|
||||
(~doc-subsection :title "Security"
|
||||
(~docs/subsection :title "Security"
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li (strong "Boundary enforcement is the foundation. ") "IPFS-fetched components are parsed and registered like any other component. SX_BOUNDARY_STRICT ensures they can't call IO primitives. A malicious component can produce ugly markup but can't exfiltrate data or make network requests.")
|
||||
(li (strong "CID verification: ") "Content fetched from IPFS is hashed and compared to the expected CID before use. Tampered content is rejected.")
|
||||
(li (strong "Signature chain: ") "Actor signatures (RSA/HTTP Signatures) prove authorship. Bitcoin anchors prove timing. Together they establish non-repudiable provenance.")
|
||||
(li (strong "Resource limits: ") "Evaluation of untrusted components runs with step limits (max eval steps, max recursion depth). Infinite loops are caught and terminated.")))
|
||||
|
||||
(~doc-subsection :title "Backward Compatibility"
|
||||
(~docs/subsection :title "Backward Compatibility"
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li "Content negotiation ensures legacy AP servers always receive valid JSON-LD")
|
||||
(li "SX-Activity is strictly opt-in — servers that don't understand it get standard AP")
|
||||
(li "Existing internal activity bus unchanged — SX format is for federation, not internal events")
|
||||
(li "URL fallbacks on all media references — CID is preferred, URL is fallback")))
|
||||
|
||||
(~doc-subsection :title "Performance"
|
||||
(~docs/subsection :title "Performance"
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li "Component CIDs cached in localStorage forever (content-addressed = immutable)")
|
||||
(li "IPFS gateway responses cached with long TTL (content can't change)")
|
||||
(li "Local IPFS node (if present) eliminates gateway latency")
|
||||
(li "Provenance verification is lazy — badge shows unverified until user clicks to verify")))
|
||||
|
||||
(~doc-subsection :title "Integration with Isomorphic Architecture"
|
||||
(~docs/subsection :title "Integration with Isomorphic Architecture"
|
||||
(p "SX-Activity builds on the isomorphic architecture plan:")
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li "Phase 1 (component distribution) → IPFS replaces per-server bundles")
|
||||
@@ -413,7 +413,7 @@
|
||||
;; Critical Files
|
||||
;; -----------------------------------------------------------------------
|
||||
|
||||
(~doc-section :title "Critical Files" :id "critical-files"
|
||||
(~docs/section :title "Critical Files" :id "critical-files"
|
||||
(div :class "overflow-x-auto rounded border border-stone-200"
|
||||
(table :class "w-full text-left text-sm"
|
||||
(thead (tr :class "border-b border-stone-200 bg-stone-100"
|
||||
|
||||
Reference in New Issue
Block a user