id: https://sniff.world/schema/citation
name: sniff_citation
title: "Sniff Citation: every rendered attribution names exactly the authors the record names"
version: 0.1.0
license: https://creativecommons.org/licenses/by/4.0/

description: >-
  LinkML root for the citation membrane. A page that renders "Surname et al. 2026"
  makes a claim about real people: that Surname wrote it first and that others
  wrote it with them. Sniff rendered that claim about a single-author preprint on
  thousands of pages, attached a cohort paper to two people who did not write it,
  and named a senior author as if he were second. None of it was caught, because
  the figures registry governed the numbers beside each citation and nothing
  governed the words.


  This schema makes the cited works a governed catalog. A CitedWork carries its
  DOI and the author list, years and title as the DOI record states them, with the
  date the record was read. The catalog is refreshed from Crossref or DataCite by
  a script and never typed by hand; the build reads it (web/scripts/validate-
  citations.cjs) and refuses any author-year form on a page that the catalog does
  not produce: a wrong first author, a co-author suffix on a sole author, a wrong
  initial, a wrong year, or a DOI that does not resolve.

prefixes:
  linkml: https://w3id.org/linkml/
  sniff: https://sniff.world/schema/
  dcterms: http://purl.org/dc/terms/
default_prefix: sniff
default_range: string

imports:
  - linkml:types

see_also:
  - https://sniff.world/schema/taxon-scope

keywords:
  - citation
  - attribution
  - provenance
  - membrane

classes:

  CitationCatalog:
    description: >-
      Every work a page cites by author and year or by DOI. An empty catalog is a
      defect, not a pass.
    tree_root: true
    slots:
      - works
      - authored_planes

  CitedWork:
    description: >-
      One cited work as its DOI record states it. Only id, doi and note are
      authored; every other slot is written by the refresh script from the
      record and carries the date it was read.
    slots:
      - id
      - doi
      - note
      - record_source
      - record_verified_on
      - title
      - container
      - authors
      - n_authors
      - year_online
      - year_print
    slot_usage:
      doi:
        required: true

  Author:
    description: One author as the record lists them, in list order.
    slots:
      - family
      - given

slots:

  works:
    description: The cited works.
    range: CitedWork
    multivalued: true
    inlined_as_list: true
    required: true

  authored_planes:
    description: >-
      Data planes under src/data whose prose Sniff wrote and which therefore carry
      Sniff's own attributions, listed by path. Pages, components and library code
      are always read. Planes not listed hold references received from a source
      (OMIA's reference lists, an upstream dataset's DOI) and are the source's
      claim, not ours; they belong to a currency check, not this one.
    multivalued: true

  id:
    description: A stable slug for the work, conventionally first-author-year.
    identifier: true

  doi:
    description: The DOI, without a resolver prefix and without a version suffix.
    pattern: "^10\\.[0-9]{4,9}/\\S+$"

  note:
    description: Why this work is in the catalog, or what a page cites it for.

  record_source:
    description: Which registry answered for this DOI.
    range: RecordSourceEnum

  record_verified_on:
    description: The date the record was read from the registry.
    range: date

  title:
    description: The title as the record states it.

  container:
    description: The journal, server or repository as the record states it.

  authors:
    description: The author list in record order.
    range: Author
    multivalued: true
    inlined_as_list: true

  n_authors:
    description: The length of the author list; a co-author suffix requires it to exceed the names given.
    range: integer

  year_online:
    description: The year the record says the work was issued.
    range: integer

  year_print:
    description: The print year where the record gives one, which citations conventionally use.
    range: integer

  family:
    description: Family name as the record lists it.
    required: true

  given:
    description: Given names or initials as the record lists them.

enums:

  RecordSourceEnum:
    description: The registries a DOI record may come from.
    permissible_values:
      crossref:
        description: Crossref, for journal articles and most preprints.
      datacite:
        description: DataCite, for datasets and repository deposits.
