# AUTHORED-BY Claude Opus 4.8 (Fable unavailable) — re-review/upgrade candidate # # Federation Catalogue / Registry Vocabulary (fedreg:) # Namespace: https://w3id.org/jeswr/fedreg# (ADR-0013, prod-solid-server) # # The "Catalogue / Registry" federation service — one of the five services a # Solid federation node provides (R9 §2.2 / research brief 09 §2 + §6 rec #6 in # jeswr/full-solid-ecosystem). It is the DISCOVERY axis, distinct from: # - fedapp: (https://w3id.org/jeswr/fed#) — an app's SELF-ASSERTED registration # in its Client Identifier Document; and # - the Vocabulary/Spec Hub — the canonical, versioned client-client specs. # # Two artifacts live here, answering two discovery questions the spec leaves the # fedapp: layer unable to answer: # # 1. fedreg:Registry + fedreg:Membership — a federation registry document that # lists member apps with a REGISTRY-ASSERTED membership status. This is the # load-bearing distinction the fedapp: vocab itself flags: "membership is the # registry's job after a signed challenge — a registry MUST NOT trust a # self-asserted membership claim." A fedreg:Membership is the registry's OWN # signed assertion (fedreg:assertedBy a WebID/key), carrying a lifecycle # status (proposed → active → suspended → revoked), so a verifier can tell a # genuine membership from an app's self-description. # # 2. fedreg:StorageDescription — a resource server's catalogue entry advertising # WHICH client-client spec-VERSIONS it accepts (fedreg:acceptsSpec) and which # data sectors it supports (fedreg:supportsSector). This realises the # "decoupling" design principle (each store independently decides which specs # it supports — brief 07) and is the substrate for ASYNCHRONOUS schema # migration (brief 09 §5 / rec #6): during a dual-read window an RS advertises # both the old and new spec-version, so pods, RS and apps upgrade on their own # clock. An app discovers acceptable versions from the catalogue, never by # assumption. # # fedreg: deliberately reuses DCAT (dcat:Catalog / dcat:CatalogRecord) and Dublin # Core Terms for the catalogue spine, and ActivityStreams-style lifecycle nouns, # rather than minting parallel terms — the LD/SW best-practice "reuse, don't # reinvent" rule. The fedreg: terms are the federation-specific glue: the # registry-asserted membership and the spec-version-acceptance advertisement. # # Authored as Turtle directly (source form); machine-built RDF in this repo and in # @jeswr/federation-registry goes through n3.Writer / @rdfjs/wrapper typed # accessors — never hand-built quads. @prefix fedreg: . @prefix fedapp: . @prefix fedcon: . @prefix rdf: . @prefix rdfs: . @prefix owl: . @prefix dcat: . @prefix dcterms: . @prefix vann: . @prefix xsd: . ################################################################# # Ontology ################################################################# a owl:Ontology ; dcterms:title "Federation Catalogue / Registry Vocabulary"@en ; dcterms:description """The Catalogue / Registry federation service: a registry document listing member apps with a registry-asserted membership status, and a resource-server catalogue entry advertising which client-client spec-versions and data sectors it accepts. The discovery axis of a Solid data federation, distinct from an app's self-asserted fedapp: registration."""@en ; dcterms:creator "Claude Opus 4.8 (@jeswr PSS agent)" ; dcterms:issued "2026-06-16"^^xsd:date ; vann:preferredNamespaceUri "https://w3id.org/jeswr/fedreg#" ; vann:preferredNamespacePrefix "fedreg" ; rdfs:seeAlso ; rdfs:comment "Experimental — AI-agent-generated; under active development, not production-hardened."@en . ################################################################# # Classes ################################################################# fedreg:Registry a rdfs:Class, owl:Class ; rdfs:subClassOf dcat:Catalog ; rdfs:label "Federation Registry"@en ; rdfs:comment """A federation registry: the catalogue of apps that a Scheme Authority has admitted to a data federation. A dcat:Catalog whose records are fedreg:Membership assertions (linked via fedreg:member). The subject is the registry's own IRI. Unlike a bag of self-asserted fedapp:App documents, a Registry's entries carry the registry's OWN membership assertion — so a consumer can trust the listing as a membership claim, not merely an app's self-description."""@en ; rdfs:isDefinedBy . fedreg:RegistryAssertion a rdfs:Class, owl:Class ; rdfs:subClassOf dcat:CatalogRecord ; rdfs:label "Registry Assertion"@en ; rdfs:comment """The common superclass of any record a registry authority SIGNS as its own claim — a dcat:CatalogRecord carrying the fedreg:assertedBy authority, the fedreg:asserted timestamp and (where a lifecycle applies) a status. It generalises the assertedBy / asserted / status spine that fedreg:Membership introduced, so OTHER registry-asserted record kinds can reuse it: a fedreg:Membership (an app's membership in a federation) and a fedcon:Admission (a concept hash admitted into a registry — https://jeswr.org/fedcon#) are both fedreg:RegistryAssertions. What makes any of them a REGISTRY claim, rather than a self-asserted one, is the fedreg:assertedBy authority a verifier checks against its trust set. (The cryptographic signature binding the assertion to that authority is layered above this vocabulary.)"""@en ; rdfs:isDefinedBy . fedreg:Membership a rdfs:Class, owl:Class ; # Re-parented under fedreg:RegistryAssertion (the G1 generalisation). The DIRECT # rdfs:subClassOf dcat:CatalogRecord is KEPT (RegistryAssertion is itself ⊑ # dcat:CatalogRecord, so it is RDFS-redundant) purely so this generalisation is # strictly ADDITIVE for a NON-reasoning consumer of the published vocab: one that # read `Membership ⊑ dcat:CatalogRecord` directly still sees it, no regression. rdfs:subClassOf fedreg:RegistryAssertion, dcat:CatalogRecord ; rdfs:label "Federation Membership"@en ; rdfs:comment """A registry's signed assertion (a fedreg:RegistryAssertion) that a particular app (its client_id, linked via fedreg:app) is a member of the federation, carrying a lifecycle fedreg:status, the fedreg:assertedBy authority (a WebID / key that vouches for it) and fedreg:asserted timestamp. This is the REGISTRY-ASSERTED counterpart to the app's self-asserted fedapp:App: a verifier treats a Membership as a membership claim only when it is asserted by a recognised authority — never the app's own fedapp: document."""@en ; rdfs:isDefinedBy . fedreg:MembershipStatus a rdfs:Class, owl:Class ; rdfs:label "Membership Status"@en ; rdfs:comment """The lifecycle state of a fedreg:Membership. The four coded values fedreg:Proposed, fedreg:Active, fedreg:Suspended, fedreg:Revoked are instances of this class. Suspended/Revoked are the federation's recovery lever (brief 07 'recovery'): a misbehaving app is suspended or revoked at the registry without touching the app's own self-asserted document."""@en ; rdfs:isDefinedBy . fedreg:StorageDescription a rdfs:Class, owl:Class ; rdfs:label "Storage Description"@en ; rdfs:comment """A resource server's (storage's) federation catalogue entry: which client-client spec-VERSIONS it currently accepts (fedreg:acceptsSpec) and which data sectors it supports (fedreg:supportsSector). Realises the federation's 'decoupling' principle — each storage independently decides which specs it supports — and is the substrate for asynchronous schema migration: during a dual-read window the storage advertises both versions, so participants upgrade on their own clock. The subject is typically the storage root IRI."""@en ; rdfs:isDefinedBy . ################################################################# # Membership-status coded values (instances of MembershipStatus) ################################################################# fedreg:Proposed a fedreg:MembershipStatus ; rdfs:label "Proposed"@en ; rdfs:comment """A membership proposed but not yet ratified by the federation's Scheme Authority — the app appears in the registry pending review."""@en ; rdfs:isDefinedBy . fedreg:Active a fedreg:MembershipStatus ; rdfs:label "Active"@en ; rdfs:comment """A current, ratified membership — the app is a recognised member of the federation and its self-asserted fedapp: footprint has been accepted."""@en ; rdfs:isDefinedBy . fedreg:Suspended a fedreg:MembershipStatus ; rdfs:label "Suspended"@en ; rdfs:comment """A membership temporarily withdrawn (e.g. pending investigation of a data-integrity issue). Reversible — distinct from fedreg:Revoked. The recovery lever for a misbehaving member."""@en ; rdfs:isDefinedBy . fedreg:Revoked a fedreg:MembershipStatus ; rdfs:label "Revoked"@en ; rdfs:comment """A membership permanently withdrawn — the app is no longer a member. A consumer MUST treat a revoked member as untrusted regardless of the app's own self-asserted fedapp: claims."""@en ; rdfs:isDefinedBy . ################################################################# # Properties — Registry / Membership ################################################################# fedreg:member a rdf:Property, owl:ObjectProperty ; rdfs:label "member"@en ; rdfs:comment """Links a fedreg:Registry to one of its fedreg:Membership records. (A specialisation of dcat:record for the federation registry; a consumer may also reach the records via dcat:record.)"""@en ; rdfs:domain fedreg:Registry ; rdfs:range fedreg:Membership ; rdfs:subPropertyOf ; rdfs:isDefinedBy . fedreg:app a rdf:Property, owl:ObjectProperty ; rdfs:label "app"@en ; rdfs:comment """Links a fedreg:Membership to the app it concerns — the app's client_id IRI (the subject of the corresponding fedapp:App self-description)."""@en ; rdfs:domain fedreg:Membership ; rdfs:range fedapp:App ; rdfs:isDefinedBy . # ----------------------------------------------------------------------------- # G1 domain-widening — a DELIBERATE, backward-compatible generalisation. # # fedreg:status / :assertedBy / :asserted were re-domained from fedreg:Membership # UP to fedreg:RegistryAssertion so the shared assertion spine can be reused by # every registry-asserted record kind (fedreg:Membership AND fedcon:Admission), # rather than duplicating a parallel fedcon: spine (the reuse-don't-reinvent rule; # the signed-off design §G.1 chose this over parallel properties). # # Semantics of the widening, stated explicitly (per a review of the RDFS effect): # - EXPLICITLY-TYPED data is UNAFFECTED. A record carrying `a fedreg:Membership` # (which is how EVERY membership in this suite is written — @jeswr/federation- # registry always asserts the type explicitly and validates by explicit # targetClass, never by domain inference) still is-a Membership, and since # Membership ⊑ RegistryAssertion it is a RegistryAssertion too. No loss. # - The ONE change is to DOMAIN INFERENCE: a bare `?x fedreg:assertedBy ?a` now # RDFS-entails `?x a fedreg:RegistryAssertion` (the more general type), no # longer `?x a fedreg:Membership`. A consumer that classified UNTYPED records # as memberships PURELY via this property's old domain would see the more # general type instead. Membership records therefore SHOULD carry an explicit # `rdf:type fedreg:Membership` (they already do); do not rely on domain # inference to distinguish a membership from a concept admission — that is # exactly the ambiguity the shared spine introduces and the explicit type # resolves. # ----------------------------------------------------------------------------- fedreg:status a rdf:Property, owl:ObjectProperty ; rdfs:label "status"@en ; rdfs:comment """The lifecycle status of a fedreg:RegistryAssertion — one of the fedreg:MembershipStatus coded values (Proposed / Active / Suspended / Revoked). Domained on fedreg:RegistryAssertion so any registry-asserted record MAY carry it; fedreg:Membership uses it for the membership lifecycle. (A fedcon:Admission carries its OWN fedcon:conceptStatus lifecycle instead of this membership-shaped status.)"""@en ; rdfs:domain fedreg:RegistryAssertion ; rdfs:range fedreg:MembershipStatus ; rdfs:isDefinedBy . fedreg:assertedBy a rdf:Property, owl:ObjectProperty ; rdfs:label "asserted by"@en ; rdfs:comment """The authority that asserts a fedreg:RegistryAssertion (a fedreg:Membership or a fedcon:Admission) — a WebID (or key IRI) of the Scheme Authority / registry operator vouching for it. This is what makes the record a REGISTRY claim rather than a self-asserted one: a verifier checks fedreg:assertedBy against the set of authorities it trusts. (The cryptographic signature binding the assertion to that authority is layered above this vocabulary.)"""@en ; rdfs:domain fedreg:RegistryAssertion ; rdfs:isDefinedBy . fedreg:asserted a rdf:Property, owl:DatatypeProperty ; rdfs:label "asserted"@en ; rdfs:comment """The timestamp (xsd:dateTime) at which the registry made this assertion — used to reason about staleness / ordering of status changes on a fedreg:RegistryAssertion (a fedreg:Membership or a fedcon:Admission)."""@en ; rdfs:domain fedreg:RegistryAssertion ; rdfs:range xsd:dateTime ; rdfs:isDefinedBy . ################################################################# # Properties — StorageDescription (spec-version acceptance + sectors) ################################################################# fedreg:acceptsSpec a rdf:Property, owl:ObjectProperty ; rdfs:label "accepts spec"@en ; rdfs:comment """A client-client spec-VERSION IRI that this fedreg:StorageDescription's storage currently accepts writes against — a persistent, immutable version IRI from the Vocabulary/Spec Hub (e.g. a canonical model version). During a dual-read migration window a storage advertises BOTH the old and new version, so independent participants migrate asynchronously. An app MUST discover acceptable versions here, not assume them. The value MAY ALTERNATIVELY be a content-addressed SNAPSHOT HASH — the content address of a fedcon:Snapshot (https://jeswr.org/fedcon#Snapshot), e.g. a urn:concept: / multibase-multihash IRI — instead of a living version IRI (federation-on-hashes design §2.3). Pinning a snapshot hash advertises acceptance of one IMMUTABLE, byte-identical release rather than a mutable spec-version pointer, so 'which spec does this store accept' is answered by content address and verified by recompute-and-compare. This is purely additive: no rdfs:range is (or was) asserted on fedreg:acceptsSpec, so both the living-version-IRI and the snapshot-hash forms are valid values, distinguished by IRI scheme; the existing spec-version usage is unchanged."""@en ; rdfs:domain fedreg:StorageDescription ; rdfs:seeAlso ; rdfs:isDefinedBy . fedreg:supportsSector a rdf:Property, owl:ObjectProperty ; rdfs:label "supports sector"@en ; rdfs:comment """A data sector IRI (a https://w3id.org/jeswr/sectors/ marker) that this fedreg:StorageDescription's storage supports. Lets an app discover which storages can hold its sector's data before attempting a write."""@en ; rdfs:domain fedreg:StorageDescription ; rdfs:isDefinedBy . fedreg:storage a rdf:Property, owl:ObjectProperty ; rdfs:label "storage"@en ; rdfs:comment """Links a fedreg:StorageDescription to the storage (resource server / pod root) it describes — typically the same IRI as the description's subject, but explicit when a registry collates many storage descriptions in one document."""@en ; rdfs:domain fedreg:StorageDescription ; rdfs:isDefinedBy .