From 6dafc97e7f1fc9e03ec7769698e2bf45fa724712 Mon Sep 17 00:00:00 2001 From: xNet Test Date: Tue, 14 Jul 2026 04:27:36 +0200 Subject: [PATCH 1/5] docs(exploration): explore lego for all data on the web MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Blog post #15 plan: xNet as LEGO for data — the frozen coupling (universal node fields, xnet:// SchemaIRI namespace, one merge rule, one authz algebra) plus clutch power as the permissions half. Covers what composable permissioned data enables, how silos and drawbridge APIs limited us, and the six limits that remain. Co-Authored-By: Claude Fable 5 Signed-off-by: xNet Test --- ..._BLOG_POST_LEGO_FOR_ALL_DATA_ON_THE_WEB.md | 681 ++++++++++++++++++ 1 file changed, 681 insertions(+) create mode 100644 docs/explorations/0319_[_]_BLOG_POST_LEGO_FOR_ALL_DATA_ON_THE_WEB.md diff --git a/docs/explorations/0319_[_]_BLOG_POST_LEGO_FOR_ALL_DATA_ON_THE_WEB.md b/docs/explorations/0319_[_]_BLOG_POST_LEGO_FOR_ALL_DATA_ON_THE_WEB.md new file mode 100644 index 000000000..e5aceeb21 --- /dev/null +++ b/docs/explorations/0319_[_]_BLOG_POST_LEGO_FOR_ALL_DATA_ON_THE_WEB.md @@ -0,0 +1,681 @@ +# Blog Post: LEGO for All Data on the Web + +> The genius of the 1958 brick was never the brick. It was the coupling. + +## Problem Statement + +The user wants a blog post framing xNet as **LEGO for all data on the web**: +a universal namespace for any and all data that syncs peer-to-peer and +preserves strong access controls and permissions — *you control who and what +gets to play with your legos*. The brief asks three questions the essay must +answer in order: + +1. **What new forms of software, tooling, and interaction does a universal, + composable, permissioned data substrate enable?** +2. **How were we limited by prior siloed, non-composable forms of data on + the internet?** +3. **What limits still remain, even in xNet?** (The honest section — the one + that buys credibility for the other two.) + +The hard constraint is series overlap. The blog already has fourteen essays, +and two of them own adjacent ground: + +- **#10, "The Workshop and the Walled Garden"** owns *moddability* and + capability-scoped third-party code. +- **#11, "The Vault and the View"** owns the *vertical* axis: apps as + disposable views over a durable data substrate, the Codd→Solid→local-first + lineage, and the AI-cheap-views inversion. + +This essay must therefore claim the **horizontal axis**: not "the app is a +view over the data" but "**every datum can snap to every other datum**" — +the connection standard itself. LEGO is the right metaphor precisely because +LEGO's genius is not the brick (any company can mould plastic) but the +**frozen coupling geometry** — the stud-and-tube interface patented on +28 January 1958 — plus the *System of Play*: every set, every theme, every +decade, one interface. A brick moulded in 1958 still snaps to a brick moulded +today. And, crucially for this essay, the metaphor's neglected half: +**clutch power is friction, not weld**. Bricks hold firmly *and come apart +by hand*. That is what permissions are — composability with consent. + +The failure mode to avoid: a breathless "everything connects to everything" +manifesto. The Semantic Web already wrote that one, and §"External Research" +below documents where it went. Every claim needs a repo receipt, and the +limits section needs real teeth. + +## Executive Summary + +- **The essay's spine: the coupling, not the brick.** xNet's answer to "what + is the stud geometry of data?" is concrete and citable: every node has + exactly four universal fields (`id`, `schemaId`, `createdAt`, `createdBy`, + per [docs/specs/protocol/02-data-model.md](../specs/protocol/02-data-model.md)); + every schema lives in one namespace + (`xnet://authority/Name@semver` — the `SchemaIRI`, + [packages/data/src/schema/node.ts](../../packages/data/src/schema/node.ts)); + every mutation is a signed change folded by one merge rule (LWW with a + grinding-resistant tiebreak, + [packages/core/src/lww.ts](../../packages/core/src/lww.ts)); every + access decision runs one authorization algebra declared *on the data + itself* ([docs/specs/protocol/04-authorization.md](../specs/protocol/04-authorization.md)). + Four frozen interfaces. Everything else — schemas, views, apps, agents — + is a brick that snaps onto them. +- **The namespace is genuinely universal, not aspirational.** The + `SchemaIRI` authority can be `xnet.fyi` (the ~60 built-in schema modules: + pages, tasks, CRM, ledger, chat, canvas…), a domain, or *any DID* — + `xnet://did:key:z6Mk…/Recipe@1.0.0` means anyone can mint types without + asking anyone. Identity is `did:key` (self-sovereign), content addressing + is BLAKE3 `cid:`s, and foreign data gets landing schemas + (`ExternalReference`, `feed-item`, importers, the Slack-compat package) so + even other people's silos become bricks. +- **The permissions half is the differentiator.** Prior "LEGO for software" + essays (and prior universal-data attempts) skip the question the user's + brief centres: *who gets to play?* xNet's answer has three interlocking + mechanisms, all data-native: schema authorization blocks with roles, + actions, and deny-wins expressions; `Grant` nodes and UCAN delegation + chains (attenuable capabilities — hand someone three bricks, not the + crate); and E2E encryption where **the ability to decrypt is the access + control** — per-recipient key wraps in + [packages/crypto/src/envelope.ts](../../packages/crypto/src/envelope.ts). + Enforcement happens at the sync boundary, so the rules travel with the + data, not with any app. +- **Question 1 (what it enables) has live receipts:** cross-schema relations + (`relation` properties point at *any* node); sidecars — your private + annotations riding on data you don't own + ([packages/data/src/schema/sidecar.ts](../../packages/data/src/schema/sidecar.ts)); + overlays — extending someone else's schema without permission or forking + ([packages/data/src/schema/extension.ts](../../packages/data/src/schema/extension.ts)); + agents as first-class players via the MCP surface + ([packages/cli/src/commands/mcp.ts](../../packages/cli/src/commands/mcp.ts)) + and capability-scoped connectors + ([packages/plugins/src/connectors/define-connector.ts](../../packages/plugins/src/connectors/define-connector.ts)); + and the user-side network effect: every datum you add makes *all* your + tools better, instead of making one platform's moat deeper. +- **Question 2 (how we were limited) is a documented history**, not + editorialising: mashup-era APIs opened (Flickr 2004) and then slammed shut + once graphs became the asset — Facebook's Friends API (30 April 2015), + Twitter's free API (9 February 2023, ~a week's notice), Reddit's + $0.24/1k-call pricing that killed Apollo (2023). Below the API layer: + Plaid built a company on screen-scraping bank logins because no first-class + data-sharing primitive existed; GDPR Article 20 grants a right to + portability but no format, so "portability" means a ZIP file no other + software can parse. Copy-paste remains the web's only universal connector. +- **Question 3 (remaining limits) is the essay's credibility engine.** Six + honest limits, each with a receipt: reading is copying (no revocation of + what's been seen — clutch power holds, it doesn't imprison); schema + agreement is social, not technical (lenses make disagreement *cheap*, they + don't make coordination free); frozen interfaces have a real maintenance + bill (the protocol-v4 tiebreak change rippled through four conformance + kernels); a generic substrate pays a performance tax the silo never pays + (our own query-perf sagas are the invoice); somebody still hosts the relay + (Moxie's "people do not want to run their own servers" is conceded, hub as + optional relay is the answer, economics still real); and moderation / + discovery in a permissioned p2p world remains per-space and unsolved at + network scale. +- **Recommendation:** ship blog post #15 as **"Clutch Power"** — bricks that + hold *and* come apart — cold-opening on the 1958 patent and a 68-year-old + brick snapping onto a new set, closing on the difference between a weld + and a grip. `.astro` page + `posts[]` entry, tags + `['essay', 'protocol', 'decentralization', 'philosophy']`, authors + `['crs48', 'claude']`, ~14 min read, en-GB, vendored assets only. + +## Current State In The Repository + +### The four frozen interfaces (the essay's "stud geometry") + +| LEGO | xNet | Receipt | +| --- | --- | --- | +| One brick footprint | Four universal node fields: `id`, `schemaId`, `createdAt`, `createdBy` | [docs/specs/protocol/02-data-model.md](../specs/protocol/02-data-model.md) §1; [packages/data/src/schema/node.ts](../../packages/data/src/schema/node.ts) | +| One catalogue of parts | `SchemaIRI = xnet://authority/Name@semver`; authority may be a DID | [02-data-model.md](../specs/protocol/02-data-model.md) §4; `parseSchemaIRI` in [node.ts](../../packages/data/src/schema/node.ts) | +| One way bricks join | Signed, hash-chained `Change` log folded by LWW (+ BLAKE3 tiebreak, protocol v4) | [packages/sync/src/change.ts](../../packages/sync/src/change.ts); [packages/core/src/lww.ts](../../packages/core/src/lww.ts) | +| One rule for whose hands | Authorization declared on schemas/nodes, evaluated identically everywhere, enforced at the sync boundary | [docs/specs/protocol/04-authorization.md](../specs/protocol/04-authorization.md); [packages/data/src/auth/evaluator.ts](../../packages/data/src/auth/evaluator.ts) | + +The protocol spec ([docs/specs/protocol/00-overview.md](../specs/protocol/00-overview.md)) +is normative and layered (L0 primitives → L1 data model → L2 replication → +L3 authorization), with golden vectors in `conformance/vectors/` so an +independent implementation in another language can prove it moulds +compatible bricks — that *is* the System of Play, stated as RFC-2119 +conformance clauses. + +### The namespace, end to end + +- **Identity:** `did:key` over Ed25519 + ([packages/identity/src/did.ts](../../packages/identity/src/did.ts); + type in [packages/core/src/auth-types.ts](../../packages/core/src/auth-types.ts)). + Names are minted, not granted. +- **Content:** `cid:blake3:…` content ids + ([packages/core/src/content.ts](../../packages/core/src/content.ts), + [hashing.ts](../../packages/core/src/hashing.ts)). +- **Nodes:** opaque nanoid ids, ~126 bits + ([packages/data/src/schema/node.ts](../../packages/data/src/schema/node.ts)). +- **Schemas:** `SchemaRegistry` singleton + ([packages/data/src/schema/registry.ts](../../packages/data/src/schema/registry.ts)) + lazy-loading ~60 built-in schema modules from + [packages/data/src/schema/schemas/](../../packages/data/src/schema/schemas/) + — Page, Task, the full CRM set, ledger accounts, Channel/ChatMessage, + Canvas, Map, Meeting. (Blog phrasing: "dozens of built-in schemas"; + the raw registry map holds 168 IRI entries but many are versioned + aliases — don't quote that number.) +- **Property vocabulary** (the stud *types*): `text`, `number`, `relation`, + `person` (a DID), `rollup`, `formula`, `file`, … in + [packages/data/src/schema/types.ts](../../packages/data/src/schema/types.ts). + `relation` is the load-bearing one for the essay: it can point at any node + of any schema — a CRM deal can relate to a chat message can relate to a + canvas. +- **Groups/boundaries:** Spaces (`xnet://xnet.fyi/Space@1.0.0`, + [space.ts](../../packages/data/src/schema/schemas/space.ts)) nest, carry a + `private|unlisted|public` dial, and act as the security boundary the + cascade inherits from. + +### The permissions machinery ("who plays with your legos") + +- **Actions** `read, create, update, write, delete, share, admin`, with + create/update as refinements of write (exploration 0304) — spec + [04-authorization.md](../specs/protocol/04-authorization.md) §1. +- **Roles + expressions:** four role-resolver kinds (`creator`, `property`, + `relation`, `membership`), deny-wins expression AST, presets + (`private()`, `publicRead()`, `spaceCascadeAuthorization()`) in + [packages/data/src/auth/presets.ts](../../packages/data/src/auth/presets.ts). +- **Grants + UCAN:** `Grant` nodes + ([grant.ts](../../packages/data/src/schema/schemas/grant.ts)) with + issuer/grantee/resource/actions/expiry/revocation; UCAN 1.0 delegation + chains in [packages/identity/src/ucan.ts](../../packages/identity/src/ucan.ts). + Attenuation is the "hand over three bricks, not the crate" beat. +- **E2E encryption as read control:** per-recipient X25519 key wraps, + XChaCha20-Poly1305 payloads + ([packages/crypto/src/envelope.ts](../../packages/crypto/src/envelope.ts)); + a `PUBLIC` sentinel recipient unifies the public/private code paths. + For an unauthorised party the brick *physically doesn't snap*. +- **Share links:** the link's private key rides in the URL fragment (never + sent to servers), claimed as a UCAN delegation — + [packages/identity/src/sharing/link-delegation.ts](../../packages/identity/src/sharing/link-delegation.ts). +- **Enforcement point:** the hub authorizes every `subscribe`/`publish` + before relaying ([docs/specs/protocol/03-replication.md](../specs/protocol/03-replication.md) §6; + [packages/hub/src/server.ts](../../packages/hub/src/server.ts)). + +### The composability surfaces (question 1's receipts) + +- **Overlay / sidecar / promote** (exploration 0188): extend anyone's + schema without forking (`ext:` keys, + [extension.ts](../../packages/data/src/schema/extension.ts)); attach your + *own* private data to nodes you don't own, under your own authz + ([sidecar.ts](../../packages/data/src/schema/sidecar.ts), deterministic + `sidecarId`); graduate an overlay into a core property via a lens + ([lens-builders.ts](../../packages/data/src/schema/lens-builders.ts)). +- **Cross-version coexistence:** bidirectional lenses after Cambria, additive + minor versions, unknown-field round-tripping — + [docs/specs/protocol/05-schema-evolution.md](../specs/protocol/05-schema-evolution.md). + This is the "1958 brick still snaps in 2026" mechanism, stated normatively. +- **Views:** `table|board|list|gallery|calendar|timeline|form` as first-class + nodes ([packages/data/src/database/view-types.ts](../../packages/data/src/database/view-types.ts)) + — one sentence in the essay, then a pointer to #11 (its territory). +- **Hooks:** `useQuery`/`useMutate`/`useCan` + ([packages/react/src/hooks/](../../packages/react/src/hooks/)) — one + sentence, pointer to #8 ("The Tip of the Hook"). +- **Agents as players:** `xnet mcp serve` exposes the workspace to any MCP + client over stdio or hardened loopback HTTP + ([packages/cli/src/commands/mcp.ts](../../packages/cli/src/commands/mcp.ts)); + connectors contribute `agentTools` + ([packages/plugins/src/agent-tools.ts](../../packages/plugins/src/agent-tools.ts)); + the devkit bridge sits on port 31416 + ([packages/devkit/src/bridge.ts](../../packages/devkit/src/bridge.ts)). + (Two ports: 31416 = devkit bridge, 31415 = agent/MCP local API — don't + conflate in the essay.) +- **Connectors:** `defineConnector` requires declared `schemaWrite` IRIs and + an explicit `network` host allowlist — capabilities enforced, closed by + default; the runner stamps the target `space` so the cascade holds + ([define-connector.ts](../../packages/plugins/src/connectors/define-connector.ts)). +- **Foreign bricks:** CSV/JSON import-export + ([packages/data/src/database/import/](../../packages/data/src/database/import/)), + Slack-compat ([packages/slack-compat/src/](../../packages/slack-compat/src/)), + landing schemas `ExternalReference`/`external-item`/`feed-item`. JMAP email + is exploration-stage only (0308, `[_]`) — do not claim it as shipped. + +### Overlap audit against the existing series + +| Essay | Its claim | #15's distinct claim | +| --- | --- | --- | +| #11 The Vault and the View | Vertical: apps are disposable views; data is the heirloom | Horizontal: **data snaps to data**; the coupling standard + permissions | +| #10 Workshop / Walled Garden | Third-party *code* is safe when scoped | One paragraph hand-off for plugin scoping; #15 focuses on *data-to-data* and *person-to-person* composition | +| #8 The Tip of the Hook | The developer surface (hooks) | Cited, not re-explained | +| #7 The Loom You Can Read | The change log internals | Cited, not re-explained | +| #12 Timeout | Presence/absence semantics | Untouched | +| #2 Data Should Work Like Soil | Ecology metaphor for the substrate | Different metaphor family; no mechanism overlap | + +The seam: #11 argued the data should outlive the app. #15 argues the data +should *compose* — with other data, other people, and other people's +software — and that composition without permission control is how you get +strip-mined (the lesson of the open-API era). + +## External Research + +(Verified by web research during this exploration; URLs in References.) + +### The metaphor's load-bearing facts + +- LEGO patented the **stud-and-tube** coupling on **28 January 1958**; the + hollow tubes under the top studs are what create **clutch power** — grip + strong enough to hold a model together, gentle enough that a child can + take it apart. Bricks moulded in 1958 still interlock with current + production: one frozen interface, seven decades of compatible parts, the + "System of Play." +- The sceptic's rebuttal exists and should be pre-empted, not dodged: + "LEGO as a Metaphor for Software Reuse — Does the Data Stack Up?" + (Safety Dave, 2021) argues software recombines far less cleanly than + bricks because interfaces evolve. Exactly — which is why the essay's + centre of gravity is the *frozen* interface set (four universal fields, + one merge rule) plus a *specified* evolution mechanism (additive minors, + lenses), not vibes about modularity. +- Trademark note: "LEGO" is a fiercely defended trademark. Editorial, + nominative use is fine; the LEGO Group's own style guidance prefers + "LEGO bricks" over "Legos." Recommended: title avoids the mark + ("Clutch Power"), body uses "LEGO bricks" for the metaphor with plain + nominative references, no logos or set imagery in the hero. + +### The lineage of universal-data attempts (question 2's history) + +- **Unix pipes** — McIlroy's 1964 memo, Thompson's 1973 `|`; "expect the + output of every program to become the input to another, as yet unknown, + program" (published 1978). Composability's clearest historical win — for + *streams of bytes* between programs one user already trusts. No namespace, + no permissions, no sync: the trivial case, and still the high-water mark. +- **Xanadu (1960–2014)** — Nelson's docuverse and transclusion: universal + addressing proposed, never shipped at scale; *Wired* (1995) called it the + longest-running vaporware in computing. Lesson: a universal namespace + without a working substrate is a manifesto. +- **OpenDoc vs OLE (1992–1997)** — compound documents; died when it required + every vendor to rewrite apps around a shared substrate that the platform + incumbent had no reason to bless. Lesson: composability must arrive + *inside* software people already want (a lesson local-first re-learned and + xNet inherits). +- **Semantic Web / RDF (2001–~2010)** — Berners-Lee's agents-reasoning-over- + the-web vision; stalled on the economics of annotation, ontology + coordination, and a steep stack. By 2006 Berners-Lee himself pivoted to + "Linked Data" — less ontology, more data. Its afterlife (schema.org, + Wikidata) fed the Knowledge Graph — i.e. recentralised one layer up. +- **The open-API era and its shutdown** — Flickr's REST API (Aug 2004) + begat mashup culture; then platforms discovered the graph was the asset: + Facebook Friends API closed 30 April 2015; Twitter ended free API access + 9 February 2023 with roughly a week's notice; Reddit's 2023 pricing + ($0.24/1k calls, ~$2M/month for Apollo) killed the third-party clients + and triggered the subreddit blackout. An API is a drawbridge: composability + at the platform's pleasure, revocable at a week's notice. +- **RSS** — ubiquitous by the late 2000s, Google Reader killed 1 July 2013; + survives as podcasting's unmediated backbone. Proof that open composability + can *persist* where no single owner can revoke it. +- **Screen-scraping economy** — Mint (2006) and Plaid (2013) built on users + handing over bank passwords for HTML scraping, because no first-class + data-sharing primitive existed. The market priced the missing primitive + at billions. +- **GDPR Article 20** — a right to portability with no format; studies of + real-world requests document widespread partial/incomplete responses. + Portability without composability is a ZIP file. + +### The contemporary cohort (and the gap xNet aims at) + +- **Solid** — pods with per-resource ACLs; stewardship moved to the Open + Data Institute in October 2024; Project Liberty integration talks + disclosed March 2025. Alive, enterprise/pilot-stage; still fighting the + OpenDoc adoption problem. +- **ATProto / Bluesky** — the closest thing to a shipped universal + namespace: user repos (PDS) + Lexicon, a federated schema registry under + reverse-DNS authorities. But the firehose model is **public-by-default**; + private data / auth scopes are still at the proposal/working-group stage. + The sharpest available proof that *a shared namespace and user-controlled + permissions are different features*, and most shipped systems have only + the first. This is xNet's precise differentiation and deserves a full + paragraph. +- **IPFS/IPLD** — content addressing solves integrity/durability, not + access control or liveness. +- **Matrix / ActivityPub** — working federation; scoped to chat/social; + moderation per-instance with defederation as the only (blunt) lever. +- **Local-first (Ink & Switch, Onward! 2019)** — the seven ideals; ideal #5 + (longevity) and #7 (user control) are this essay's ancestors. #11 already + owns this citation; #15 references it once. +- **CRDTs** — Yjs (~920k weekly downloads) vs Automerge (~85k): the merge + machinery is commoditising; the differentiators have moved up-stack to + namespace + authz — convenient framing for why xNet's spec spends its + normativity on L1/L3. +- **UCAN** — delegable, attenuable capability tokens; the "hand over three + bricks, not the crate" mechanism, shipped in xNet. +- **Google Zanzibar (USENIX ATC 2019)** — relationship-tuple authz backing + Drive/Photos/YouTube: >2 trillion ACL checks, 95% under 10ms. Existence + proof that fine-grained relationship-based authorization works at + planetary scale — *inside one company's fence*. The open problem xNet + takes on is the same semantics with nobody owning the graph, which is + why L3's decision semantics are normative (two implementations must reach + identical allow/deny on the same graph). + +### Honest-limits research (question 3's backbone) + +- **Reading is copying.** No cryptographic scheme prevents a legitimate + reader from copying decrypted data out of the system. Capability systems + mitigate confused-deputy delegation abuse; they cannot un-show something. + Revocation stops *future* reads only. The essay must say this plainly — + it is also the metaphor's grace note: clutch power grips, it doesn't weld, + and a system that promised weld-strength control over shared data would + be promising DRM. +- **Ontology coordination is social.** No single party can model the world; + competing ontologies recreate silos (semantic-web literature's own + finding; schema.org absorbing GoodRelations in 2012 is the rare + convergence). Lenses/overlays make disagreement cheap; they do not make + agreement free. +- **Moderation/discovery in p2p** — per-instance moderation with + defederation as the only lever is documented as structurally weak + (Carnegie 2025; ACM "Will Admins Cope?"). xNet's spaces are the + moderation boundary today; network-scale discovery and abuse handling are + open. +- **Hosting economics** — someone pays to keep bytes available; p2p storage + networks need proof-of-storage machinery consumer systems don't build. + xNet's stance: local replica primary, hub as optional paid relay. +- **The frozen-interface bill** — LEGO froze one physical coupling and + iterates everything else. Protocols pay for that continuously: xNet's own + protocol-v4 LWW tiebreak change (hash-grinding mitigation, exploration + 0305) rippled through four conformance kernels and the serializer + registry. Freezing the interface is a standing engineering commitment, + not a one-time patent. + +## Key Findings + +1. **The essay's fresh contribution is the second half of the metaphor.** + "LEGO for software" is a worn trope; every prior use is about + modularity. None is about *clutch power* — the grip that holds without + welding, i.e. composability that preserves the owner's ability to take + the model apart, refuse a hand, or leave the table. Framing permissions + as a *property of the coupling itself* (authz declared on data, enforced + at sync, encryption as the snap) is the argument the sources don't make. +2. **ATProto is the perfect foil.** It shipped the universal namespace and + proved demand; its public-by-default firehose shows namespace ≠ + permissions. One respectful paragraph does more differentiation work + than any amount of silo-bashing. +3. **The three brief questions map cleanly onto essay movements** — + (2) history first (silos → drawbridge APIs → scraping → ZIP-file + portability), (1) then what the coupling enables (with repo receipts), + (3) then the six honest limits. History-first keeps it from reading as + a product pitch. +4. **Every enabling claim has a shipped receipt** except JMAP email + (exploration-stage) and anything security-sensitive from exploration + 0307 (see Risks). The essay should only claim what's on `main`. +5. **The series' fact-check discipline applies** (exploration 0247): all + dates and quotes above came from live web verification during this + exploration; re-verify any *new* quote added at draft time. en-GB prose, + `.astro` page, vendored hero, nothing third-party on the page. + +## Options And Tradeoffs + +### Framing options + +| Option | Shape | Pros | Cons | +| --- | --- | --- | --- | +| **A. Coupling-first** ("the stud, not the brick") | 1958 patent → the four frozen interfaces → what snaps on → who gets to play → limits | Distinct from #10/#11; mechanism-rich; metaphor earns its keep | Needs discipline to keep LEGO from becoming a gimmick | +| B. History-first polemic | Silo era → API betrayals → xNet | Emotionally strong openings (Apollo's death) | Overlaps #11's Google Reader cold open; angrier than the series' register | +| C. "New software" catalogue | Lead with what becomes possible | Concrete, optimistic | Reads as a feature tour; weakest thesis | +| D. Permissions-first ("who plays") | Lead with consent/control | The freshest half | Buries the composability half the user's brief leads with | + +**A, with B compressed into one movement and D as the essay's second act.** +The brief's three questions become acts 2, 1→3 ordering inside frame A +(history as act one, enablement as act two, limits as act three). + +### Title options + +| Title | Notes | +| --- | --- | +| **"Clutch Power"** ✅ | The metaphor's payload in two words: grip without weld = composability with consent. Avoids the trademark in the title. Series-compatible (cf. "Timeout", "Weights You Can Hold") | +| "The Stud and the Tube" | Series pair-form; the tube (hidden half, = permissions) is elegant but the phrase reads oddly cold | +| "A Box of Bricks" | Warm but generic; weak on the permissions half | +| "Bricks That Still Snap" | Good backwards-compat hook; misses permissions | + +### Cold-open options + +1. **The 1958 patent + the 68-year-old brick** ✅ — a brick moulded the + year before the moon race still snaps onto a set bought this morning; + what was patented was not a brick but a *coupling*; pivot: the web never + patented its coupling for data. +2. Apollo-app shutdown day (2023) — strong but angry, and #11 already + cold-opened on a platform death (Google Reader). +3. A child's brick bin — every set ever bought, one bin, everything + combines — warm, but slower to the thesis. + +## Recommendation + +Write **blog post #15, "Clutch Power"**, framing A: + +1. **Cold open:** 28 January 1958 — the stud-and-tube patent. The genius + was never the brick; it was the coupling — and the grip that holds + firmly yet yields to a child's fingers. Sixty-eight years of parts, + one interface. Then the turn: the web never standardised a coupling for + *data* — so every app moulded bricks that only fit its own set. +2. **Act one — the bin we never got** (question 2): silos as sets that + don't combine; the API era as drawbridges (Flickr 2004 → Facebook 2015 / + Twitter 2023 / Reddit 2023); Plaid pricing the missing primitive in the + billions; GDPR's ZIP-file portability; copy-paste as the web's only + universal connector. One paragraph nods to Xanadu/OpenDoc/Semantic Web: + universal data has been proposed for sixty years; what was always + missing was a shipped coupling *with a permission model*. +3. **Act two — the coupling** (question 1): the four frozen interfaces + (universal node fields, `xnet://` SchemaIRI namespace anyone — even a + DID — can mint into, one merge rule, one authz algebra), then what + snaps on once they exist: relations across schemas; overlays on data you + don't own; sidecars carrying *your* private notes on *their* nodes; + lenses letting a 2026 client edit a 1958 document; agents as + first-class players through the MCP surface; connectors that turn Slack + exports and CSVs into bricks. Then the second half: **who gets to + play** — authorization as data (grants are nodes that sync like + everything else), UCAN attenuation (three bricks, not the crate), + encryption as the snap itself, share links whose secret never touches a + server, enforcement at the sync boundary so the rules travel with the + data. The user-side network effect closes the act: in a silo, your data + compounds the platform's moat; on a common coupling, it compounds *your* + toolbox. +4. **Act three — what the coupling cannot do** (question 3): six limits, + plainly. Reading is copying — revocation stops future reads, never past + ones, and anything stronger would be DRM, which the grip deliberately + isn't. Schema agreement stays social — lenses cheapen disagreement, they + don't abolish coordination. Frozen interfaces bill forever — the + protocol-v4 ripple as receipt. Generic substrates pay a performance tax + — our query-perf sagas as invoice. Somebody hosts — Moxie conceded, hub + as optional relay, economics not hand-waved. Moderation and discovery + are per-space, unsolved at network scale. +5. **Close:** the difference between a weld and a grip. A weld is a + platform: strong, permanent, and you don't get to take it apart. A grip + is a protocol: it holds because the geometry is right, and it lets go + because the bricks are yours. Build accordingly. + +Mechanics: `site/src/pages/blog/clutch-power.astro` + `posts[]` entry in +[site/src/data/blog.ts](../../site/src/data/blog.ts), tags +`['essay', 'protocol', 'decentralization', 'philosophy']`, authors +`['crs48', 'claude']`, bespoke vendored hero (abstract stud-grid motif — +no LEGO imagery), one Mermaid diagram, one `CodeFigure`, ~14 min read, +en-GB, changelog fragment via `scripts/changelog/new.mjs`, `skip-changelog` +not applicable (site change → Changelog Check applies; no changeset — site +is not a publishable package). + +```mermaid +flowchart TB + subgraph coupling["The coupling (frozen, normative)"] + N["Node: id · schemaId · createdAt · createdBy"] + IRI["Namespace: xnet://authority/Name@semver
(authority may be any DID)"] + LWW["One merge rule: signed change log → LWW fold"] + AUTHZ["One authz algebra: roles · actions · grants · UCAN
enforced at the sync boundary"] + end + subgraph bricks["Bricks (open-ended)"] + T["Task"] ; C["Contact"] ; M["ChatMessage"] ; X["ext: overlay
on someone else's node"] + S["sidecar: your private notes
on their data"] ; F["ExternalReference
(imported silo data)"] + end + subgraph players["Players"] + APP["Apps (views — see essay #11)"] + AGT["Agents (MCP surface)"] + PPL["People (DIDs, share links)"] + end + bricks -->|snap onto| coupling + players -->|"play, if permitted"| coupling +``` + +```mermaid +sequenceDiagram + participant O as Owner (DID) + participant H as Hub (relay) + participant G as Guest (DID) + O->>O: create node (E2E encrypted,
key wrapped per recipient) + O->>H: publish signed change + Note over H: no grant for Guest →
not relayed; no key → no snap + O->>G: share link (secret in URL fragment) + G->>H: claim → UCAN delegation (attenuated: read only) + H-->>G: relay changes for that resource + G->>G: unwrap key, decrypt — the brick snaps + O->>O: revoke grant + Note over G: future changes stop.
What was already read is already copied —
the grip is not a weld. +``` + +## Example Code + +The essay's central exhibit — composition across ownership boundaries +without forking or asking (real APIs from +[extension.ts](../../packages/data/src/schema/extension.ts) / +[sidecar.ts](../../packages/data/src/schema/sidecar.ts)): + +```typescript +// Their brick: a Contact node someone else created and governs. +// Your stud: an overlay attribute in your authority's namespace, +// riding on the node, syncing and merging like any property. +await mutate.update(contactId, { + [extKey('yourapp.example', 'vip')]: true +}) + +// Your private brick on their public one: a sidecar — a separate +// node with ITS OWN authorization (they never see your notes), +// deterministically addressed so every device finds the same one. +const noteId = sidecarId('yourapp.example', contactId) +await mutate.create(SidecarSchema, { + id: noteId, + target: contactId, // relation → any node, any schema + body: 'Met at the 1958 patent anniversary. Buys bricks in bulk.' +}) +``` + +## Risks And Open Questions + +- **Do not publish security specifics from exploration 0307.** The audit + found real authorization gaps (wildcard-UCAN handling, unwired + `authEvaluator` paths). The essay's limits section must stay at design + level ("enforcement is only as strong as the relay's evaluation, and we + are still hardening it") and must not describe unfixed weaknesses or + their mechanics. Check 0307's remediation status at draft time; if the + gaps are closed, a "we audited ourselves and fixed X" line is *stronger* + than silence. +- **Trademark.** Nominative use of "LEGO" is fine; keep it out of the + title (done — "Clutch Power"), use "LEGO bricks" in prose, vendored + abstract hero only, no sets/logos/minifigures. Do not title the post + "Legos for Data." +- **Metaphor fatigue.** The series already runs on extended metaphors + (looms, furnaces, soil). Guard: the metaphor must earn each appearance by + mapping to a mechanism (coupling→node fields, catalogue→SchemaIRI, + clutch→permissions, 1958-brick→lenses); cut any paragraph where it's + only decoration. +- **Overlap discipline.** #11 owns apps-as-views and the local-first canon; + #10 owns plugin scoping; #8 owns the hooks; #7 owns the log internals. + #15 links each once and never re-argues. The overlap-audit table above is + the contract. +- **Overclaim watch.** "Universal namespace" is true of the *protocol*; + network-scale claims (discovery, a public schema commons, cross-org + authority resolution beyond `xnet/1.0`'s rules) are roadmap. Keep verbs + honest: the coupling is shipped; the worldwide bin of bricks is the bet. +- **Performance receipts without self-sabotage.** Cite "our query + performance work" generically; don't quote raw cliff numbers from + exploration 0318 (internal measurements of unreleased paths). +- Open question for draft time: does the essay show one small end-to-end + "two apps, one datum, one permission grant" narrative vignette (a CRM + and a chat app sharing a Contact)? Likely yes — it dramatises question 1 + in 150 words — but cut if length exceeds ~15 min read. + +## Implementation Checklist + +- [ ] Re-verify at draft time: 0307 remediation status (gates how the + hardening limit is phrased); JMAP still exploration-only; the ~60 + built-in schema-module count. +- [ ] Write `site/src/pages/blog/clutch-power.astro` following series + conventions (Byline, SeriesNav, Mermaid, CodeFigure, `tok-*` + helpers, `prose` body, en-GB, nothing third-party). +- [ ] Bespoke vendored hero under `site/src/components/blog/` — abstract + stud-grid motif, no LEGO trade dress. +- [ ] Add the `posts[]` entry in `site/src/data/blog.ts` (slug + `clutch-power`, tags + `['essay','protocol','decentralization','philosophy']`, authors + `['crs48','claude']`, honest `readingMinutes`). +- [ ] Body structure per Recommendation: cold open (1958 patent) → the bin + we never got → the coupling & who gets to play → six limits → the + weld and the grip. +- [ ] Every mechanism claim carries its repo receipt (paths as listed in + Current State); external dates/quotes only from the verified set in + External Research; any new quote re-verified against the live source + (0247 discipline). +- [ ] `CodeFigure` uses the real `extKey`/`sidecarId` APIs (no invented + fields); Mermaid diagrams adapted from this exploration. +- [ ] Cross-link essays #7, #8, #10, #11 once each; link the protocol spec + (`docs/specs/protocol/`) as the "System of Play" receipt. +- [ ] Changelog fragment via `scripts/changelog/new.mjs`; no changeset + (site is not a publishable package). +- [ ] Conventional commits, header ≤72 chars; PR to `main`; let CI run + (no `--admin`); merge-commit per repo policy. + +## Validation Checklist + +- [ ] Site build passes (verify via full build — astro dev has hung on + some pages before); post renders with hero, byline, diagrams, code + figure in light and dark. +- [ ] Post appears on `/blog` index and in `rss.xml`; `seriesNeighbors` + links #14 ↔ #15 correctly. +- [ ] Network tab clean — no third-party requests on the page. +- [ ] Fact pass: every date (1958, 2015, 2023, 2013, 2004, 2019, 2024) + matches the sources in References; every repo path in the essay + exists on `main` at publish time. +- [ ] Security pass: nothing in the limits section describes an unfixed + vulnerability or its mechanics (0307 check). +- [ ] Trademark pass: no "Legos", no LEGO imagery, nominative references + only. +- [ ] Overlap pass: a reader of #10/#11 finds a new argument in every + section (the coupling framing, the ATProto foil, the clutch-power + permissions half, the six limits). + +## References + +- LEGO stud-and-tube patent (28 Jan 1958) — · + +- Safety Dave, _LEGO as a Metaphor for Software Reuse_ (2021) — + +- Doug McIlroy / Unix pipes history — + +- Project Xanadu — +- Why OpenDoc failed — +- Berners-Lee, _Linked Data_ design note — +- Facebook Friends API shutdown (2015) — +- Twitter free-API shutdown (2023) — +- Reddit API pricing / Apollo (2023) — +- TechCrunch, _Social networks are getting stingy with their data_ (2024) — + +- RSS history — +- Solid → ODI stewardship (Oct 2024) — ; + Project Liberty talks — +- ATProto & Lexicon — ; + private-data gap — · + +- Ink & Switch, _Local-first software_ (2019) — +- UCAN — +- Google Zanzibar (USENIX ATC 2019) — +- Confused deputy — +- Plaid / screen scraping — +- GDPR Art. 20 portability in practice — +- "You're the product" origin (Lewis, 2010) — +- Fediverse moderation limits — · + +- Decentralized storage economics — +- Repo: [docs/specs/protocol/](../specs/protocol/) (L0–L3 + conformance), + [packages/data/src/schema/](../../packages/data/src/schema/) (node, registry, + extension, sidecar, lens-builders), + [packages/data/src/auth/](../../packages/data/src/auth/), + [packages/identity/src/](../../packages/identity/src/) (did, ucan, sharing), + [packages/crypto/src/envelope.ts](../../packages/crypto/src/envelope.ts), + [packages/core/src/lww.ts](../../packages/core/src/lww.ts), + [packages/sync/src/change.ts](../../packages/sync/src/change.ts), + [packages/hub/src/server.ts](../../packages/hub/src/server.ts), + [packages/plugins/src/connectors/define-connector.ts](../../packages/plugins/src/connectors/define-connector.ts), + [packages/cli/src/commands/mcp.ts](../../packages/cli/src/commands/mcp.ts); + explorations 0188, 0200, 0247, 0281 (essay #11), 0304, 0305, 0307 From f268aa08beb90e0b11c51873d19534f90c9efc65 Mon Sep 17 00:00:00 2001 From: xNet Test Date: Tue, 14 Jul 2026 05:29:30 +0200 Subject: [PATCH 2/5] =?UTF-8?q?feat(site):=20add=20blog=20post=20#15=20?= =?UTF-8?q?=E2=80=94=20Clutch=20Power?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LEGO for all data on the web (exploration 0319): the coupling, not the brick — one node shape, one namespace, one merge rule, one permission algebra; and clutch power as the permissions half. Bespoke BrickArt hero, HonestBrick limits box, two Mermaid diagrams, extKey/sidecarId code figure. Co-Authored-By: Claude Fable 5 Signed-off-by: xNet Test --- ..._BLOG_POST_LEGO_FOR_ALL_DATA_ON_THE_WEB.md | 16 +- site/public/llms-full.txt | 37 ++ site/src/components/blog/BrickArt.astro | 186 +++++++ site/src/components/blog/BrickHero.astro | 38 ++ site/src/components/blog/HonestBrick.astro | 64 +++ site/src/data/blog.ts | 18 + site/src/pages/blog/clutch-power.astro | 518 ++++++++++++++++++ site/src/pages/blog/index.astro | 2 + 8 files changed, 871 insertions(+), 8 deletions(-) create mode 100644 site/src/components/blog/BrickArt.astro create mode 100644 site/src/components/blog/BrickHero.astro create mode 100644 site/src/components/blog/HonestBrick.astro create mode 100644 site/src/pages/blog/clutch-power.astro diff --git a/docs/explorations/0319_[_]_BLOG_POST_LEGO_FOR_ALL_DATA_ON_THE_WEB.md b/docs/explorations/0319_[_]_BLOG_POST_LEGO_FOR_ALL_DATA_ON_THE_WEB.md index e5aceeb21..93345ce68 100644 --- a/docs/explorations/0319_[_]_BLOG_POST_LEGO_FOR_ALL_DATA_ON_THE_WEB.md +++ b/docs/explorations/0319_[_]_BLOG_POST_LEGO_FOR_ALL_DATA_ON_THE_WEB.md @@ -588,28 +588,28 @@ await mutate.create(SidecarSchema, { ## Implementation Checklist -- [ ] Re-verify at draft time: 0307 remediation status (gates how the +- [x] Re-verify at draft time: 0307 remediation status (gates how the hardening limit is phrased); JMAP still exploration-only; the ~60 built-in schema-module count. -- [ ] Write `site/src/pages/blog/clutch-power.astro` following series +- [x] Write `site/src/pages/blog/clutch-power.astro` following series conventions (Byline, SeriesNav, Mermaid, CodeFigure, `tok-*` helpers, `prose` body, en-GB, nothing third-party). -- [ ] Bespoke vendored hero under `site/src/components/blog/` — abstract +- [x] Bespoke vendored hero under `site/src/components/blog/` — abstract stud-grid motif, no LEGO trade dress. -- [ ] Add the `posts[]` entry in `site/src/data/blog.ts` (slug +- [x] Add the `posts[]` entry in `site/src/data/blog.ts` (slug `clutch-power`, tags `['essay','protocol','decentralization','philosophy']`, authors `['crs48','claude']`, honest `readingMinutes`). -- [ ] Body structure per Recommendation: cold open (1958 patent) → the bin +- [x] Body structure per Recommendation: cold open (1958 patent) → the bin we never got → the coupling & who gets to play → six limits → the weld and the grip. -- [ ] Every mechanism claim carries its repo receipt (paths as listed in +- [x] Every mechanism claim carries its repo receipt (paths as listed in Current State); external dates/quotes only from the verified set in External Research; any new quote re-verified against the live source (0247 discipline). -- [ ] `CodeFigure` uses the real `extKey`/`sidecarId` APIs (no invented +- [x] `CodeFigure` uses the real `extKey`/`sidecarId` APIs (no invented fields); Mermaid diagrams adapted from this exploration. -- [ ] Cross-link essays #7, #8, #10, #11 once each; link the protocol spec +- [x] Cross-link essays #7, #8, #10, #11 once each; link the protocol spec (`docs/specs/protocol/`) as the "System of Play" receipt. - [ ] Changelog fragment via `scripts/changelog/new.mjs`; no changeset (site is not a publishable package). diff --git a/site/public/llms-full.txt b/site/public/llms-full.txt index 891fa4fe0..c8cc3e7b2 100644 --- a/site/public/llms-full.txt +++ b/site/public/llms-full.txt @@ -315,6 +315,29 @@ Without writing a single line of backend code, you got: - src/ - schema.ts defineSchema() definitions - App.tsx XNetProvider - TaskList.tsx useQuery + useMutate +## Go multiplayer in two commands + +Everything above is one keystroke away from being a shared app. Point the +provider at a sync hub and give everyone the same room string — whoever +shares the room sees the same data: + +```tsx + +``` + +To run your own hub locally (dev only — auth off accepts anyone): + +```bash +docker run --rm -p 4444:4444 -e HUB_AUTH=false ghcr.io/crs48/xnet-hub:latest +``` + +Open the app in two browser windows — changes appear in both. The room string +is the entire join flow: put it in a URL (`?room=standup`) and the URL becomes +an invitation. The smallest complete example of this is +[`examples/minimal-app`](https://github.com/crs48/xNet/tree/main/examples/minimal-app) +in the repo (~60 lines, copy-paste ready), and you can watch it run live on +the [demos page](/demos/). + ## Next steps @@ -7660,6 +7683,20 @@ reports upstream — the sender's DID is hashed (never sent raw) and document content is never included. Leave them unset (the default) and nothing is forwarded; `GET /diagnostics/health` simply reports `sharing: false`. +The upstream sink is xNet Cloud's first-party `POST /diagnostics` ingest +(exploration 0315): reports land in a quarantine and are drained into +`debug-report` nodes in the operator's own xNet workspace, where the workbench +_is_ the triage console — filterable tables, a `new → acked → fixed → released` +status field, and comments. **xNet does not use a third-party error service such +as Sentry.** The client keeps a dormant, vendor-neutral Sentry seam (no +`@sentry/*` SDK is installed and no DSN is minted), so if you self-host a +Sentry-compatible backend you can point that seam at it — [Bugsink][bugsink] +(single container, SQLite) or [GlitchTip][glitchtip] (MIT, Sentry-SDK +compatible) are the proven small-footprint options — but nothing ships enabled. + +[bugsink]: https://www.bugsink.com/ +[glitchtip]: https://glitchtip.com/ + ### CLI Flags | Flag | Description | diff --git a/site/src/components/blog/BrickArt.astro b/site/src/components/blog/BrickArt.astro new file mode 100644 index 000000000..3c0898f9a --- /dev/null +++ b/site/src/components/blog/BrickArt.astro @@ -0,0 +1,186 @@ +--- +// Decorative art for blog post #15 (exploration 0319), extracted so the same +// inline SVG backs both the post hero and the blog-index preview card (no +// external assets — Self-Audit parity). The scene draws the essay's argument: +// on the left, the silo era — two sealed boxes whose connectors don't match +// (a triangle socket, a round socket), each with a few dim points locked +// inside. On the right, one baseplate: a ground plane of studs on which +// bricks of different shapes all snap, because the coupling is shared. One +// brick hovers just above the plate, mid-lift — the grip lets go; that's the +// point. Another sits dashed with a keyhole: present, but it won't snap for +// you without the key. The cosmic-X hangs overhead as the reading lamp, as in +// the rest of the series. All geometry original; no LEGO trade dress. +interface Props { + /** Override the wrapper classes; defaults to full-bleed for hero use. */ + class?: string +} +const { class: className = 'pointer-events-none absolute inset-0 h-full w-full' } = + Astro.props + +// The baseplate stud row (x positions along the plate's top edge). +const studCols = Array.from({ length: 15 }, (_, i) => 448 + i * 34) + +// Studs on top of a brick: n studs across a brick starting at x with width w. +const brickStuds = (x: number, w: number, n: number) => + Array.from({ length: n }, (_, i) => x + (w / (n * 2)) * (2 * i + 1)) + +// The dotted footpath from the silos out to the baseplate. +const path = [ + [300, 300], + [348, 294], + [396, 296], + [436, 306] +] + .map(([x, y]) => `${x},${y}`) + .join(' ') +--- + + diff --git a/site/src/components/blog/BrickHero.astro b/site/src/components/blog/BrickHero.astro new file mode 100644 index 000000000..a4afd4903 --- /dev/null +++ b/site/src/components/blog/BrickHero.astro @@ -0,0 +1,38 @@ +--- +// Hero band for blog post #15 (exploration 0319). The decorative art lives in +// BrickArt.astro so the same inline SVG backs both this hero and the +// blog-index preview card; this component layers the post's title/deck over it. +import BrickArt from './BrickArt.astro' + +interface Props { + title: string + deck: string + date: string + readingMinutes: number + tags: string[] +} +const { title, deck, date, readingMinutes, tags } = Astro.props +--- + +
+ + +
+
+ + + {readingMinutes} min read + { + tags.map((tag) => ( + + {tag} + + )) + } +
+

+ {title} +

+

{deck}

+
+
diff --git a/site/src/components/blog/HonestBrick.astro b/site/src/components/blog/HonestBrick.astro new file mode 100644 index 000000000..f72da0564 --- /dev/null +++ b/site/src/components/blog/HonestBrick.astro @@ -0,0 +1,64 @@ +--- +// The honesty beat for post #15 (exploration 0319), modeled on HonestVault / +// HonestWorkshop. An essay that says "one coupling for all your data, and you +// decide who plays" owes the reader the six places where the metaphor stops +// working — starting with the one no architecture can fix: a grip is not a +// weld, and reading is copying. The rows concede the strongest standing +// objections rather than dodging them. +const rows = [ + { + isnt: 'We won’t pretend revocation can reach into the past.', + is: 'Once someone has read a piece of data, they have it — decryption is copying, and no protocol can un-show something. Revoking a grant stops every future change from reaching them; it cannot repossess what they already saw. Anything that promised more would be DRM wearing a nicer coat, and the grip is deliberately not a weld.' + }, + { + isnt: 'We won’t pretend a shared namespace makes people agree.', + is: 'Two apps sharing a Contact still have to agree on what a contact is, and that agreement is social, not technical — the Semantic Web spent a decade proving it. Lenses, overlays, and sidecars make disagreement cheap enough to live with; they don’t make coordination free. Anyone can mint a schema, which also means anyone can mint a duplicate.' + }, + { + isnt: 'We won’t pretend a frozen interface maintains itself.', + is: 'LEGO froze one moulding geometry and iterates everything else; a protocol pays for that promise continuously. When we hardened one detail of our merge rule, the change rippled through every conformance kernel and golden vector we keep. Backwards compatibility is a standing engineering bill, not a patent you file once.' + }, + { + isnt: 'We won’t pretend a general-purpose substrate is fast for free.', + is: 'A silo optimises for exactly one access pattern; a store that must answer any question about any shape pays a tax the silo never sees. Making the open substrate feel app-fast has taken months of unglamorous query and hydration work, and that ledger is still open.' + }, + { + isnt: 'We won’t pretend nobody has to run anything.', + is: 'Moxie Marlinspike is right that people do not want to run their own servers. Your replica is primary and local, and peers can sync directly — but an always-reachable relay is what makes sharing feel instant, and someone hosts and pays for it. Ours is optional and replaceable; it is not imaginary.' + }, + { + isnt: 'We won’t pretend permissions solve moderation or discovery.', + is: 'Access control decides who may read and write; it says nothing about what deserves an audience. Spaces give every community its own table and its own rules, which works at the scale of a table — network-scale discovery, spam, and abuse in a world with no central operator remain honestly unsolved, here and everywhere.' + } +] +--- + +
+
+

+ Where the metaphor stops +

+

+ Six things a universal coupling cannot do, conceded in plain sight — + because the essays that skip this section are the ones you were right + not to trust. +

+ +
    + { + rows.map((row) => ( +
  • +
    + +

    {row.isnt}

    +
    +
    + +

    {row.is}

    +
    +
  • + )) + } +
+
+
diff --git a/site/src/data/blog.ts b/site/src/data/blog.ts index 94a7151a1..2f67628a4 100644 --- a/site/src/data/blog.ts +++ b/site/src/data/blog.ts @@ -87,6 +87,24 @@ export interface BlogPost { } const posts: BlogPost[] = [ + { + slug: 'clutch-power', + title: 'Clutch Power', + description: + 'On 28 January 1958 the LEGO Group patented not a brick but a ' + + 'coupling — stud and tube, and with them clutch power: a grip firm ' + + 'enough to build with that still comes apart by hand. The web never ' + + 'got a coupling for data, so every app moulds pieces that fit only ' + + 'its own set, and the APIs that promised otherwise were drawbridges. ' + + 'On the four frozen interfaces xNet ships instead — one node shape, ' + + 'one namespace anyone can mint into, one merge rule, one permission ' + + 'algebra — and why the grip matters as much as the snap: nobody ' + + 'plays with your bricks unless you say so.', + pubDate: '2026-07-14T17:00:00Z', + authors: ['crs48', 'claude'], + tags: ['essay', 'protocol', 'decentralization', 'philosophy'], + readingMinutes: 14 + }, { slug: 'weights-you-can-hold', title: 'Weights You Can Hold', diff --git a/site/src/pages/blog/clutch-power.astro b/site/src/pages/blog/clutch-power.astro new file mode 100644 index 000000000..c6b90f56e --- /dev/null +++ b/site/src/pages/blog/clutch-power.astro @@ -0,0 +1,518 @@ +--- +import Base from '../../layouts/Base.astro' +import Nav from '../../components/sections/Nav.astro' +import Footer from '../../components/sections/Footer.astro' +import SeriesNav from '../../components/blog/SeriesNav.astro' +import BrickHero from '../../components/blog/BrickHero.astro' +import Byline from '../../components/blog/Byline.astro' +import Mermaid from '../../components/blog/Mermaid.astro' +import CodeFigure from '../../components/blog/CodeFigure.astro' +import HonestBrick from '../../components/blog/HonestBrick.astro' +import { postBySlug, formatPostDate } from '../../data/blog' + +const post = postBySlug('clutch-power')! + +// --- syntax highlighting helpers (same tok-* idiom as the landing page's +// CodeBlock; coloured by the CSS variables in Base.astro). +const kw = (s: string) => `${s}` +const st = (s: string) => `${s}` +const cm = (s: string) => `${s}` + +// The essay's central exhibit: composing across an ownership boundary without +// forking and without asking. `extKey` and `sidecarId` are the real helpers +// from packages/data/src/schema/{extension,sidecar}.ts; `update`/`create` are +// the real mutate surface from the previous developer essay. +const composeCode = [ + `${cm('// Their brick: a Contact someone else created and governs.')}`, + `${cm('// Your stud: a field in your own namespace, riding on the')}`, + `${cm('// node itself — syncing and merging like any other property.')}`, + `${kw('await')} update(ContactSchema, contact.id, {`, + ` [extKey(${st("'acme.example'")}, ${st("'leadScore'")})]: 42`, + `})`, + ``, + `${cm('// Your private brick on their public one: a sidecar — a')}`, + `${cm('// separate node with its own permissions (they never see it),')}`, + `${cm('// addressed deterministically so every device finds the same one.')}`, + `${kw('await')} create(ContactNotes, {`, + ` target: contact.id, ${cm('// relation → any node, any schema')}`, + ` body: ${st("'Prefers the 1958 catalogue. Buys in bulk.'")}`, + `}, sidecarId(me.did, contact.id))` +].join('\n') + +// --- mermaid diagram sources (rendered client-side by ) --- +const coupling = `flowchart TB + subgraph couplingBlock["The coupling — frozen, specified, versioned"] + N["one node shape
id · schemaId · createdAt · createdBy"] + IRI["one namespace
xnet://authority/Name@version
(the authority can be you)"] + LWW["one merge rule
signed change log,
deterministic fold"] + AUTHZ["one permission algebra
roles · actions · grants,
enforced where data moves"] + end + subgraph bricks["The bricks — open-ended"] + T["a task"] + C["a contact"] + M["a message"] + X["your field on
someone else's node"] + S["your private notes
on their data"] + F["an imported silo
(CSV, Slack, feeds)"] + end + subgraph players["The players"] + APP["apps — views
(the previous essay)"] + AGT["agents — same table,
same rules"] + PPL["people — names you mint,
links you hand over"] + end + bricks -->|snap onto| couplingBlock + players -->|"play, where permitted"| couplingBlock` + +const gripNotWeld = `sequenceDiagram + participant O as Owner + participant R as Relay + participant G as Guest + O->>O: creates a node — encrypted,
its key wrapped per recipient + O->>R: publishes the signed change + Note over R: Guest holds no grant →
nothing is relayed.
No key → the brick doesn't snap. + O->>G: hands over a share link
(the secret rides in the URL fragment,
which no server ever receives) + G->>R: claims it — a delegation,
attenuated to read-only + R-->>G: changes for that one resource + G->>G: unwraps the key. The brick snaps. + O->>O: revokes the grant + Note over G: future changes stop arriving.
What was already read is already copied —
a grip, not a weld.` +--- + + +