ADR 23: Subject Sources
Date: 2026-06-22
Status: Accepted (2026-07-06). The Source contract section was amended 2026-08-07, resolving the "Source interface contract" open question.
Feedback remains welcome on the Open questions section below.
Context
Prior to this ADR, NeoWiki assumed every Subject is local, editable, versioned, stored in a MediaWiki revision slot (ADR 4), and projected into the graph (ADR 19).
Several needed capabilities do not fit that assumption: cross-wiki metadata in a wiki farm, page and approval metadata, free-form (Confluence-style) tables, and structured data drawn from other systems (another NeoWiki, an on-wiki SMW or Wikibase store, external services).
The detailed exploration is in planning/SubjectSources.md.
Decision
Subjects come from pluggable Sources
A Subject is produced by a Source. The local revision slot is the default Source; others, like an on-wiki SMW/Wikibase store, another NeoWiki, or an external system, can also supply Subjects. A Source registry maps a source key to its Source, which is the authority for its Subjects' capabilities, identity, and schema resolution. A wiki farm is simply more registered Sources.
The Source contract
A Source answers for five things and no more:
- Fetch by id, one Subject or a whole list. A list is one call, so a Source that can answer it in one round trip does.
- Schema resolution by name, because a Subject's Schema is resolved through the Schema's own Source.
- Editability, the one capability the model varies.
- localId validation, so the global id-format check can be source-delegated: the nanoid grammar is the local Source's rule, not a rule about ids. Unconsulted so far — see Identity below.
- A base URI, the IRI prefix its Subjects are named under, which is also its RDF prefix entry.
On top of those five it carries one obligation rather than a capability: a Source vouches for what it returns. Everything it hands back is readable by every reader of this wiki, because a sourced Subject has no page here to authorize against and NeoWiki performs no per-user authorization on it. A Source over data with restrictions of its own must serve only the unrestricted part — a question it answers without knowing who is asking. The accepted limitation: sourced data has no per-user granularity — ADR 27 records this as its source-attested read class; lifting it would be an additive context on this contract, not a redesign.
Two absences are deliberate. There is no write method: write-back is end-of-roadmap (below), and a stub for it would be a contract nobody can implement against, so it arrives with the feature. And Sources take no part at query time — materialisation is the only gate on queryability, so a query never consults a Source.
Editability is likewise stated ahead of its use: nothing reads it until sourced Subjects render. It belongs in the frozen contract because a Source author must answer it from the start.
Availability is not part of the contract either: a Source that cannot reach its store answers as though the Subject or Schema is absent. Together with an unregistered source key resolving to nothing, a Subject from a Source this wiki lacks degrades wherever it is read rather than breaking the page.
A source decides editability
The distinction:
- Local Subjects are editable through the normal editor (subject to access rights) and versioned.
- Sourced Subjects are read-only. Writing back to a source is deferred (see Open questions).
Every Subject, whatever its source, renders through the existing Views (sourced ones read-only) and is queryable once materialised in the graph.
Editability is the only capability the model varies today, and it bundles editable + versioned (local) against read-only (sourced). This is not a permanent two-state space: the deferred write-back capability will make some sourced Subjects writeable, reintroducing per-source variation — so "sourced ⇒ read-only" is the current scope, not a closed decision.
Page Properties are not exposed via Subjects
Approval state and system page metadata (name, creationTime, lastEditor, categories) are Page Properties — facts stored on the page node, the built-in ones plus any an extension contributes through the PagePropertyProvider plugin. They are surfaced via query (Cypher), not through the View or editor. The Source model could expose them as read-only Subjects; for this use case it deliberately does not — they stay Page Properties.
Identity
A Subject's id is a pair (source, localId). The existing SubjectId (ADR 14) is widened to carry a source, defaulting to local — a bare nanoid still means a local Subject. localId is opaque outside its Source (a nanoid locally; a page id or a remote id / URI elsewhere), and each Source owns its grammar and minting. Validation is meant to follow: Source::isValidLocalId() is the seam for it, but nothing consults it yet — a foreign localId is checked only against the shared serialization grammar, so a Source with a narrower rule of its own is not yet held to it. The pair is the canonical reference form (relation targets, view ids, fetch); IRI and CURIE forms are projections of it, with the source-to-base-URI map doubling as the RDF prefix map. ADR 14's fixed-length and time-sortable guarantees hold only for local nanoids, not for arbitrary localIds.
This ratifies the two forward-compatibility assumptions of ADR 22, which decided the first increment (per-wiki node identity in a shared graph): the local source key is the MediaWiki Wiki ID, and a local Subject stays stored as a bare nanoid (with wiki_id as a property), the (source, localId) pair being derived from it rather than a re-keying of stored data.
Schemas come from Sources
A schema is resolved through a Source and may be read-only (a code-defined built-in, or a remote-owned schema) or writeable (an ordinary local schema). A schema reference is (source, name) (ADR 17), and a schema's source is independent of the subject's source. Rendering a sourced Subject therefore resolves the schema through its Source, which may differ from the subject's. When a schema cannot be resolved — a foreign, offline, or removed schema — rendering degrades gracefully rather than breaking the page.
Unlike a Subject id, a schema reference is not written as one string. A local schema name is a page title and may itself contain a colon (ISO:9001), so a qualified string would be ambiguous with names that were legal before Sources existed, and would read them back wrongly. A stored reference is therefore either a plain name, always local, or an object carrying source and name (Schema format). A qualified source:name string survives only as a one-way rendering for people.
Consequences
- One model spans local data, on-wiki SMW/Wikibase adoption, cross-wiki farm metadata, and external/federated data, rather than separate mechanisms.
- The View, query, and editing surfaces stay Subject-shaped; they gain only a read-only state for sourced Subjects.
- Approval and page metadata stay Page Properties, queryable without being exposed as Subjects, so recording them does not create a page revision.
- Materialisation is required for a Subject to be queryable; sourced data that is not materialised is fetchable by id but not queryable.
Open questions
Deferred and/or still being designed; consortium feedback is expected here.
- Federation resolution — fetch-at-read vs cache/materialise; for triple-store backends, federated queries.
- RDF / IRI export and ontology mapping — see planning/NativeRdfProjection.md and planning/OntologyMapping.md.
- Editing sourced Subjects (write-back) — end-of-roadmap. How useful? Things like editing Wikibase Items via NeoWiki UI, or editing data from a remote NeoWiki
Alternatives Considered
- Global properties / a single shared schema set. Rejected (planning/GlobalProperties.md); name consistency is handled per-schema.
- Schemaless Subjects. Disallowed (ADR 8); free-form tables use an ordinary schema edited through a table UI.
- Model Page Properties (approval, metadata) as Subjects. Rejected for this use case: they are facts about a page, simpler kept on the page node; modelling them as slot-backed Subjects would make recording them a new, unapproved page revision.
- Materialization only. We'd avoid adding subject sources and continue without support for displaying anything that is not a "normal local Subject" via the View system. You'd only be able to display it via userland scripting on top of queries.
Related
- planning/SubjectSources.md — detailed exploration behind this ADR.
- ADR 22: Multi-wiki Graph Node Identity, ADR 19: Graph Database Architecture, ADR 14: Improved Id Format, ADR 8: One Schema per Subject, ADR 18: Views.
- planning/NativeRdfProjection.md, planning/OntologyMapping.md, planning/GlobalProperties.md.