diff --git a/spec/FederationArchitecture.md b/spec/FederationArchitecture.md new file mode 100644 index 0000000..2cc8780 --- /dev/null +++ b/spec/FederationArchitecture.md @@ -0,0 +1,220 @@ +# FederationArchitecture + +Status: **draft for review** · Date: 2026-06-15 · Deliverable of **SHARD-WP-0002** (T1–T10, T17) + +The federation **design decisions** for shard-wiki: *what the union does*. It records, per +topic, a decision with rationale, tradeoffs, and a **Decided / Deferred / Open** footer. It +**references** `spec/CoreArchitectureBlueprint.md` (the whole-system architecture) and +`spec/FederationRequirements.md` (yawex-derived ADRs) rather than restating them; the adapter +contract (*what a backend must expose*) is the companion deliverable in +`spec/TechnicalSpecificationDocument.md` §A (T11–T16, T18). UC references → `UseCaseCatalog.md`. + +Cross-cutting invariants assumed throughout (blueprint §2): orchestrator-not-engine (I-1), +three-state canonical/derived (I-2), capability-as-data (I-3), union-without-erasure (I-4), +overlay-before-mutation (I-5), git-addressable coordination (I-6), mechanism-over-policy (I-7), +graceful degradation (I-8), identity≠placement (I-9), history-as-floor (I-10), authz-in-core +(I-11), tenant-partitioned derived state (I-13). + +--- + +## T1 — Orchestrator positioning & boundaries + +**Decision.** shard-wiki is an **adapter-layer orchestrator** in a **star** shape (many +sovereign shards ↔ one information space), **not** a homogeneous federation network. It +**compares, does not equate** (Federated Wiki homogeneous JSON sites, ikiwiki homogeneous git +wikis, ActivityPub activity streams are *models it can speak*, §T17 — not shapes it imposes). +Core owns: the union, the coordination journal, projection, overlay, resolution, authorization. +Adapters own backend specifics; UI and editorial policy live outside core. (Blueprint §1, §5; +UC-02, UC-26.) + +*Decided:* star orchestrator; compare-not-equate; core/adapter/UI/policy boundaries. +*Deferred:* the reference UI (L6) is out of scope here. *Open:* none. + +## T2 — Remix primitives: reference / projection / overlay / import-fork + +**Decision.** Four primitives, escalating in commitment; **overlay-before-mutation is the +default write path** (I-5), fork is *one federation model* (§T17) not the default for editing: + +| Primitive | Trigger | Writes remote? | Coordination-canonical? | +|-----------|---------|----------------|--------------------------| +| **Reference** | link only | no | no (a link in content) | +| **Projection** | read remote page | no (cache) | no (derived) | +| **Overlay** | edit a sub-write-through shard | not until explicit apply | **yes** (decision log) | +| **Import / fork** | copy into a writable shard / fork-with-provenance | source unchanged | **yes** (fork event) | + +(Blueprint §8.2; FederationRequirements ADR-05; UC-04, UC-26, UC-29.) + +*Decided:* the four primitives + overlay-default. *Deferred:* fork-attribution portability +format. *Open:* whether "import" and "fork" are one primitive with a flag or two (impl spike). + +## T3 — Equivalent-page identity & multi-version presentation + +**Decision.** Separate **identity** (stable handle), **placement** (N paths/shards), and +**equivalence** (content-fingerprint / span-set overlap *across* identities), per +FederationRequirements ADR-01/ADR-02 (I-9). Equivalence signals: normalized title/path, alias +table (coordination-canonical), link-graph overlap, fingerprint, **curator binding**. Default +presentation = **chorus-of-voices** (all equivalent versions, attributed); **designated- +canonical** is a policy preset (§T9). Divergence is data in the provenance envelope (I-4), +detected as core mechanism (blueprint §8.6). (UC-07, UC-27; UC-46.) + +*Decided:* identity/placement/equivalence split; chorus default. *Deferred:* fingerprint +algorithm + blocking params (blueprint O-1). *Open:* curator-binding UX (L6). + +## T4 — History, attribution & the coordination journal + +**Decision.** Each information space has a **git-addressable, event-sourced coordination +journal** (blueprint §8.1, I-6/I-10): coordination-canonical decisions (overlay/binding/alias/ +merge/fork) are append-only events; current state is a derived fold. **One append authority per +space** gives a total order (read-your-writes across instances). Per-shard native history is +**adopted** (git-native), **supplemented** (DB/CRDT internal → journal begins-now/mirrors), or +**imported** (open file history backfilled) per the history-portability axis (TSD §A T13). +Attribution is portable on the event (UC-29). (UC-29, UC-33.) + +*Decided:* event-sourced journal + per-space append authority + adopt/supplement/import. +*Deferred:* per-space log sharding for extreme write rates (blueprint O-12). *Open:* none. + +## T5 — Union composition layer + +**Decision.** The **server-side orchestrator union is primary** — the derived tier (union +graph, indexes, projections) is composed in core for agents/CLI/non-browser consumers +(blueprint §8.4), **incrementally maintained** (not recomputed, §8.7), **tenant-partitioned** +(I-13). **Client-side composition** (Federated-Wiki-style browser pull) is a supported +*consumer pattern over the same union*, not the only path. Freshness/caching per §8.8. (UC-05, +UC-27, UC-03, UC-31.) + +*Decided:* server-primary, client-optional; incremental, partitioned. *Deferred:* client +SDK shape. *Open:* persisted-union digest granularity (blueprint O-4, B-4 checker). + +## T6 — Change notification & subscription transports + +**Decision.** Change-notification is an **optional adapter capability** (`notify`), and it is +the **primary driver of incremental maintenance** (blueprint §8.7/§8.8). Transports, per +profile: git hook / ikiwiki-style ping, ActivityPub Create/Update, webhook, WebDAV/HTTP ETag +or `Last-Modified` poll, plain polling fallback. A notification → invalidate affected entries ++ enqueue delta refresh + a RecentChanges union entry (FederationRequirements ADR-03; UC-31, +UC-17). Rate-limited shards favour event-driven + long TTL (operational-envelope axis). + +*Decided:* notify = optional capability, drives incremental + RecentChanges; transport per +profile. *Deferred:* ActivityPub as content-bearing (vs notify-only) — start notify-only. +*Open:* fediverse-dependency posture for v1. + +## T7 — Information-space lifecycle + +**Decision.** Root entities have lifecycle states: **active → read-only-archived → retired +(detached)**, and **merged-into-successor**. **Carry-forward** is selective import from an +archived shard (UC-28, UC-30). **Space-fork / branch** (UC-33) = branch the coordination +journal + shard-config (a fork event, §T2/§T17 fork+journal model). Retirement **preserves +read-only union entries** by default (history-as-floor, I-10), never hard-deletes projections. +(UC-28, UC-30, UC-33.) + +*Decided:* the lifecycle states + carry-forward + space-branch; retire-preserves. *Deferred:* +ephemeral "happenings" as a first-class mode. *Open:* GC policy for retired-space derived tier. + +## T8 — Transclusion & projection depth + +**Decision.** Transclusion is **one reference-not-copy primitive** over the addressable union +(blueprint §8.4), at three depths: + +| Level | UC | Behaviour | +|-------|-----|-----------| +| Whole-page projection | UC-03 | lazy full page from a remote shard (replication-projection) | +| Block/span transclusion | UC-32 | inline embed by span address, with origin + freshness | +| Link reference | UC-08 | pointer only (ADR-06) | + +Every transcluded artifact carries provenance + **staleness** (I-4, §8.8); live-transclusion +fragility (link rot / remote down) degrades to last-known + an `unavailable`/`stale` marker +(blueprint O-11). Span-level authz under transclusion = the stricter of source/host (O-10). +Reference-not-copy unifies Xanadu transclusion, ZigZag clone, embeds, synced blocks, Trilium +note-clone, literate named-chunk. (UC-03, UC-32.) + +*Decided:* one primitive, three depths, provenance+staleness mandatory. *Deferred:* snapshot- +on-import vs live default (a policy). *Open:* span-authz composition (O-10), addressing (O-6). + +## T9 — Consensus & reconciliation policy catalog + +**Decision.** **Detection is core, resolution is policy** (I-7, blueprint §8.6). Core always +detects divergence and represents it as a coexisting (chorus) set; the **resolution preset** is +configurable per space / per equivalence set: + +- **chorus-spread** (versions coexist; default) · **designated-canonical** (explicit write + target) · **git-merge** (where merge capability allows) · **vote-to-merge / editorial gate** + (optional, L6-assisted) · **overlay-only** (no destructive merge on read-only sources). + +(FederationRequirements ADR-03/ADR-05; UC-07, UC-27.) + +*Decided:* the preset catalog; detection-core/resolution-policy. *Deferred:* vote/editorial +gate mechanics (L6). *Open:* default preset per persona bundle (blueprint O-8). + +## T10 — Federation-operations capability matrix + +**Decision.** Each federation operation requires a minimum **verified capability profile** +(TSD §A T11/§6.6); below it, the op **degrades** along the named interaction axes (blueprint +§6.5) rather than failing. The matrix (consuming the T11 vocabulary): + +| Federation op | Min capabilities | Degradation when absent | +|---------------|------------------|--------------------------| +| **read / project** | `read` | (floor — every shard) | +| **transclude span** | `read` + addressing≥span | whole-page projection only | +| **overlay** | `read` | always available (overlay is local) | +| **write-through** | `write` (+ `merge` for concurrent) | → overlay/patch target | +| **diff / 3-way merge** | `diff`,`merge` | → keep-both / chorus | +| **notify-driven freshness** | `notify` | → validator-poll → TTL (§8.8) | +| **native search delegate** | native-query≥index | → derived index over projection | +| **publish / mirror** | `publish` | → read-only / static projection | +| **fork+journal federation** | `read` + history (any) | → projection-only participant | + +Every backend, down to the Oddmuse flat-file floor, is usable as **read-only / cache / +projection / backup / patch target** (I-8). This matrix and the T11 spectra are kept in sync +(it consumes that vocabulary). (UC-02–UC-07.) + +*Decided:* the op→capability matrix + degradation paths. *Deferred:* exhaustive per-op test +vectors → the conformance suite (§6.6). *Open:* axis-interaction completeness (blueprint O-5). + +--- + +## T17 — Federation-model taxonomy (selectable / composable) + +**Decision.** Federation is **plural and composable**, not one mechanism (blueprint §8.3). A +space selects a model (composing per shard); the default is **fork+journal over Git** (the home +case): + +| Model | Anchor | Coordination shape | Capability floor | UCs | +|-------|--------|--------------------|------------------|-----| +| **Fork + journal** *(default)* | Federated Wiki | copy-with-provenance + per-page action journal (story = replay) | `read` + journal | UC-26, UC-71, UC-72 | +| **VCS-replication + ping** | ikiwiki | git clone/pull/push + change-ping | git-IS-store | UC-31, UC-33, UC-79 | +| **Query-time graph-join** | Wikibase `SERVICE` | join remote graphs at query, no copy | native-query≥graph | UC-74 | +| **Feed aggregation** | RSS/Atom | inbound feed → pages | `read` | UC-03 | +| **Activity streams** | ActivityPub | Create/Update events (notify or content) | `notify` | UC-31 | +| **Engine-mirror** | Wiki.js DB↔Git | engine mirrors its store to git | `publish`/mirror | UC-68, UC-69 | + +The coordination journal (T4) is the fork+journal model's home; **git IS the journal** in +VCS-replication and engine-mirror (forge wikis make git the store *and* journal, resolving the +engine-mirror write-race). Models compose: e.g. fork+journal locally, query-join for a +typed-graph shard, feed-aggregation for an external source. (Mechanism over policy, I-7.) + +*Decided:* the six models, selectable per space + composable per shard, default fork+journal. +*Deferred:* activity-streams content-bearing mode. *Open:* multi-model interaction edge cases +(when two models touch one shard). + +--- + +## Consolidated decisions / deferred / open + +- **Decided (architecture-settling):** star orchestrator (T1); overlay-default remix (T2); + identity/placement/equivalence + chorus (T3); event-sourced journal + append authority (T4); + server-primary incremental union (T5); notify-driven freshness (T6); space lifecycle (T7); + reference-not-copy transclusion (T8); detection-core/resolution-policy preset catalog (T9); + op→capability matrix (T10); selectable/composable federation models (T17). +- **Deferred (to impl / L6 / persona bundles):** reference UI; fork-attribution format; client + SDK; vote/editorial mechanics; ephemeral spaces; ActivityPub content-bearing; default-preset + bundles (O-8). +- **Open (tracked in blueprint §12):** O-1 equivalence blocking, O-4 union digest, O-5 axis + interactions, O-6 addressing, O-8 presets, O-10 span-authz, O-11 unavailability, O-12 log + throughput. + +## Acceptance (SHARD-WP-0002 federation half) + +T1–T10 + T17 each have a decision record with a Decided/Deferred/Open footer; all honour INTENT; +UC-26–UC-33, UC-56, UC-71–UC-72, UC-74, UC-79 trace here; the adapter-contract companion is +`spec/TechnicalSpecificationDocument.md` §A (T11–T16, T18). Conflicts with SHARD-WP-0001 are +none (FederationRequirements ADRs are consumed, not duplicated).