Skip to content

Instantly share code, notes, and snippets.

@seandavi
Created June 2, 2026 19:33
Show Gist options
  • Select an option

  • Save seandavi/21f88b953d4c0d76c43d3713a8970cef to your computer and use it in GitHub Desktop.

Select an option

Save seandavi/21f88b953d4c0d76c43d3713a8970cef to your computer and use it in GitHub Desktop.
Publishing and Versioning Architecture for CFDE Working-Group RFCs

Proposal: Publishing and Versioning Architecture for CFDE Working-Group RFCs

Purpose

This document proposes an architecture for hosting, citing, versioning, and amplifying the discoverability of Requests for Comment (RFCs) produced by Common Fund Data Ecosystem (CFDE) working groups. The goals, in priority order:

  1. Knowledge sharing — make the content of RFCs easy to find, read, and reuse.
  2. Finding new users — reach people in neighboring domains who would not otherwise encounter the work.
  3. Citability and permanence — every RFC is a citable, archived, versioned object.
  4. Low maintenance burden — the process must be sustainable at a volume of roughly 5–10 RFCs per year, with minimal per-RFC scaffolding.

Comment collection is a secondary goal; the primary aim is dissemination.


Recommended architecture (summary)

A single monorepo for the working/discussion layer, with one independently versioned Zenodo record per RFC for the citable/archival layer, plus a rendered GitHub Pages "RFC Book" as the human-facing front door — and, for the subset of RFCs that define a standard, data resource, or policy, a linked FAIRsharing / re3data registration.

The key design principle is the separation of layers:

Layer System Purpose
Working / discussion GitHub monorepo + Issues/Discussions Drafting, review, comment, version control
Presentation GitHub Pages (rendered "RFC Book") Readable, browsable, indexed front door
Citable / archival Zenodo, one record per RFC DOIs, archival guarantee, scholarly graph
Amplification FAIRsharing / re3data (selective) Cross-domain discovery of registrable artifacts

The reason for splitting these is that the artifact you want to share (knowledge) and the activity you want to enable (comment) have different ideal homes, and the unit you want to cite (one RFC) differs from the unit GitHub naturally releases (a whole repo). Forcing one platform to do everything is where most such efforts bog down.


Part 1: Repository topology — monorepo, not one-repo-per-RFC

The decision criterion

For FAIR purposes the deciding factor is the granularity of the citable, versioned object. Zenodo's native GitHub integration mints a DOI per release of a repository. So the real question is: should each RFC version independently, or should the series be the versioned object?

We want each RFC to version independently (so RFC-007 can reach v1.0 while RFC-003 is being superseded), but we do not want the operational overhead of a new repository per RFC.

Options considered

Option A — One repo per RFC. Each RFC gets its own release cadence, its own concept-DOI, and a cleanly scoped discussion thread. Cost: proliferation (5–10 new repos/year, each needing identical scaffolding — CITATION.cff, .zenodo.json, license, CI), plus a discovery problem: nothing ties the repos together except a naming convention, and cross-RFC linking becomes manual.

Option B — One monorepo, many RFCs (the IETF / Rust / Kubernetes-KEP model). A single home, a natural index page, trivial cross-referencing, one set of scaffolding, one Discussions space. Naive cost: a Zenodo release of the monorepo would snapshot all RFCs together, so you could not cleanly cite or version one RFC independently — the DOI would point to "the collection as of release N."

Option C — One repo per working group. A middle ground: RFCs grouped by WG, each WG with its own Zenodo sub-community. Scales better than per-RFC repos, keeps related RFCs together, still allows per-RFC DOIs. A reasonable fallback if the single monorepo grows unwieldy.

Recommended resolution

Adopt the monorepo (Option B) for the working and presentation layers, but do NOT use the repo-granular GitHub→Zenodo release hook for archival. Instead, deposit each finalized RFC to Zenodo as its own record, driven by a per-RFC git tag and a CI job. This gives:

  • monorepo convenience (one home, shared scaffolding, cross-linking, one index);
  • per-RFC DOIs and independent version chains (the FAIR requirement);
  • a Zenodo Community that gathers all RFC records under one umbrella.

The only discipline this requires: "publish RFC-N" is an explicit, tagged action — not an automatic side effect of any repository release. A tag like rfc-0007-v1.0 triggers a CI job that deposits only that RFC's directory to its own Zenodo record (creating a new version if the concept already exists).

Repository layout

cfde-rfcs/
├── README.md                  # series overview + index + how-to-cite
├── CONTRIBUTING.md            # the RFC process itself (lifecycle, statuses)
├── VERSIONING.md              # version + DOI policy (see Part 3)
├── LICENSE                    # e.g. CC-BY-4.0 for text
├── 0000-template/
│   ├── rfc.md                 # the RFC body, with YAML front-matter
│   ├── CITATION.cff           # per-RFC citation metadata
│   └── .zenodo.json           # per-RFC Zenodo deposition metadata
├── 0001-some-topic/
│   ├── rfc.md
│   ├── CITATION.cff
│   └── .zenodo.json
├── 0002-another-topic/
│   └── ...
├── book.toml                  # mdBook config (renders the "RFC Book")
├── generate-index.py          # builds the index page from front-matter
└── .github/workflows/
    ├── deploy-book.yml        # build + publish GitHub Pages on merge to main
    └── publish-rfc.yml        # on rfc-NNNN-vX.Y tag → deposit to Zenodo

This mirrors the Rust approach, where every feature began as a Markdown file in a GitHub PR and the repository serves as both the proposal system and the permanent record of design decisions; a generate-book.py + book.toml toolchain renders a browsable RFC Book deployed via a GitHub Actions workflow. We add the per-RFC Zenodo deposition step that Rust does not need (Rust does not assign DOIs to RFCs).


Part 2: The three metadata surfaces

The maximalist FAIR play is not to stuff each surface independently but to make them consistent and cross-linked. There are three surfaces:

Surface 1 — CITATION.cff (per RFC, in the repo)

Human- and machine-readable. GitHub renders a "Cite this repository" button from it and uses it to pass metadata toward Zenodo.

cff-version: 1.2.0
title: "CFDE RFC-0007: <Title>"
message: "If you use or build on this RFC, please cite it as below."
type: dataset        # closest CFF type; see notes in VERSIONING.md
authors:
  - given-names: Jane
    family-names: Doe
    orcid: "https://orcid.org/0000-0000-0000-0000"
    affiliation: "University of Example"
    # ROR via affiliation-meta where tooling supports it
abstract: >
  One-paragraph summary of the RFC's contribution, written for a reader
  outside the immediate working group.
version: "1.0.0"
date-released: "2026-01-15"
doi: "10.5281/zenodo.XXXXXXX"     # the CONCEPT DOI (all versions)
license: CC-BY-4.0
keywords:
  - common fund data ecosystem
  - data standards
  - <domain terms>
repository-code: "https://github.com/<org>/cfde-rfcs/tree/main/0007-some-topic"
url: "https://<org>.github.io/cfde-rfcs/0007-some-topic.html"
references:
  - type: report
    title: "CFDE RFC-0003: <prior related RFC>"
    doi: "10.5281/zenodo.YYYYYYY"

Surface 2 — .zenodo.json (per RFC; or the equivalent REST-API payload)

This is where the rich, FAIR-critical fields live that CFF does not carry.

{
  "title": "CFDE RFC-0007: <Title>",
  "upload_type": "publication",
  "publication_type": "technicalnote",
  "description": "<HTML or text abstract>",
  "version": "1.0.0",
  "publication_date": "2026-01-15",
  "language": "eng",
  "license": "CC-BY-4.0",
  "access_right": "open",

  "creators": [
    {
      "name": "Doe, Jane",
      "orcid": "0000-0000-0000-0000",
      "affiliation": "University of Example"
    }
  ],
  "contributors": [
    {
      "name": "Roe, Richard",
      "type": "Editor",
      "orcid": "0000-0000-0000-0001"
    },
    {
      "name": "<WG name>",
      "type": "WorkPackageLeader"
    }
  ],

  "communities": [{ "identifier": "cfde-rfcs" }],

  "grants": [
    { "id": "<U24 award number>" },
    { "id": "<U54 award number>" }
  ],

  "keywords": ["common fund data ecosystem", "data standards"],
  "subjects": [
    {
      "term": "Data sharing",
      "identifier": "http://edamontology.org/topic_XXXX",
      "scheme": "EDAM"
    }
  ],

  "related_identifiers": [
    { "relation": "isDocumentedBy",
      "identifier": "https://github.com/<org>/cfde-rfcs/tree/main/0007-some-topic",
      "resource_type": "software" },
    { "relation": "isVersionOf",
      "identifier": "10.5281/zenodo.CONCEPT" },
    { "relation": "isPartOf",
      "identifier": "10.5281/zenodo.SERIES_RECORD" },
    { "relation": "references",
      "identifier": "10.5281/zenodo.YYYYYYY" },
    { "relation": "isNewVersionOf",
      "identifier": "10.5281/zenodo.PRIOR_RFC" },
    { "relation": "isDescribedBy",
      "identifier": "https://fairsharing.org/bsg-sXXXXXX" }
  ],

  "notes": "Status: Accepted. Supersedes RFC-0003. See VERSIONING.md for policy."
}

related_identifiers is the single most important FAIR field here. Every entry is a discovery edge in the scholarly graph. Use it aggressively for: provenance (isDocumentedBy → GitHub source), the version chain (isVersionOf / isNewVersionOf / isPreviousVersionOf), series membership (isPartOf → the series record), inter-RFC citation (references / isReferencedBy), and links to any FAIRsharing record (isDescribedBy).

Surface 3 — Front-matter + embedded JSON-LD (in the rendered page)

The RFC body carries YAML front-matter that drives both the index generator and an embedded schema.org block in the rendered HTML <head>. This is what makes Google Dataset Search and Scholar see structured metadata — the cheapest reach-new-users lever once the other two surfaces exist.

---
rfc: 0007
title: "<Title>"
status: Accepted        # Draft | In Review | Accepted | Superseded | Withdrawn
working-group: "<WG name>"
authors: ["Jane Doe", "Richard Roe"]
created: 2025-11-01
version: "1.0.0"
doi: "10.5281/zenodo.XXXXXXX"
supersedes: []
superseded-by: []
---

Rendered into the page head as schema.org/TechArticle:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "TechArticle",
  "identifier": "https://doi.org/10.5281/zenodo.XXXXXXX",
  "headline": "CFDE RFC-0007: <Title>",
  "author": [{ "@type": "Person", "name": "Jane Doe",
               "identifier": "https://orcid.org/0000-0000-0000-0000" }],
  "datePublished": "2026-01-15",
  "version": "1.0.0",
  "license": "https://creativecommons.org/licenses/by/4.0/",
  "isPartOf": { "@type": "CreativeWorkSeries", "name": "CFDE RFCs" },
  "funding": "<U24 / U54 award numbers>",
  "sameAs": [
    "https://github.com/<org>/cfde-rfcs/tree/main/0007-some-topic",
    "https://doi.org/10.5281/zenodo.XXXXXXX",
    "https://fairsharing.org/bsg-sXXXXXX"
  ]
}
</script>

Part 3: Versioning policy

State this explicitly in VERSIONING.md so it is itself machine- and human-discoverable.

DOI model

Zenodo provides two DOIs per record:

  • a concept DOI that always resolves to the latest version — use this for "cite the RFC" (in the README, the index, general references);
  • a version DOI that resolves to one exact, frozen text — use this for "cite exactly this text" (in reproducibility-sensitive citations).

Both belong in the metadata: the concept DOI in CITATION.cff doi:, the version DOI minted fresh on each tagged deposition.

Semantic versioning for RFCs

  • MAJOR — substantive change to the proposal's meaning or recommendations.
  • MINOR — added clarification or non-substantive expansion.
  • PATCH — typo / formatting / link fixes.

Each MAJOR/MINOR bump is a new Zenodo version (new version DOI, same concept DOI). PATCH fixes may be batched.

Status vocabulary (controlled)

Draft → In Review → Accepted → Superseded | Withdrawn

Surface status in both the page front-matter and the Zenodo notes/version, so it is machine-discoverable rather than only visible on a web page.

Reciprocal supersession links

DataCite relationships are directional, so populate both sides. When RFC-0007 supersedes RFC-0003:

  • on 0007: isNewVersionOf → 0003 (and front-matter supersedes: [0003]);
  • on 0003: isPreviousVersionOf → 0007 (and superseded-by: [0007]), re-deposited as a new version so the link is live.

This makes the graph traversable from either node.

A series-level record

Create one Zenodo record (or use the Community landing page) describing the RFC series as a whole, modeled as a schema.org/CreativeWorkSeries / Collection. Each RFC points to it with isPartOf. This gives the series its own identity and a single citable entry point for "the CFDE RFC process."


Part 4: Selective registry amplification (FAIRsharing / re3data)

Neither FAIRsharing nor re3data is a document host — they catalog standards, databases, data policies (FAIRsharing) and research data repositories (re3data). An RFC by itself is not a registrable object in either.

However, for the subset of RFCs whose content defines a registrable artifact, register that artifact and link the RFC as its documentation:

  • RFC proposes/defines a standard (schema, reporting checklist, terminology, identifier scheme) → register the standard in FAIRsharing; link the RFC DOI via isDescribedBy / documents.
  • RFC describes/governs a data resource (repository, knowledgebase, portal) → register in FAIRsharing (database) and/or re3data (repository).
  • RFC is a data policy → register in the FAIRsharing policy registry.

This is the substitute for the preprint lever (preprint servers are increasingly restrictive about non-study, "RFC-shaped" content). The registries are built for exactly the cross-domain discovery we want — they let a reader arrive from a neighboring field via the standard, the repository, or the policy, and find the RFC behind it. FAIRsharing records also carry their own persistent, citable identifiers, so a registration is complementary to (not redundant with) the Zenodo DOI.

At 5–10 RFCs/year with only a fraction producing registrable artifacts, this is a small, occasional curatorial task, not a per-RFC requirement.


Part 5: Reference implementations and prior art

  • Rust RFCshttps://github.com/rust-lang/rfcs — the canonical monorepo model: each RFC is a Markdown file added via PR; the repo is both proposal system and permanent design record. Rendered RFC Book: https://rust-lang.github.io/rfcs/. (Rust does not mint DOIs — that is the piece we add.)
  • Rust RFC process texthttps://rust-lang.github.io/rfcs/0002-rfc-process.html — the process itself, written as RFC-0002; a good template for our CONTRIBUTING.md.
  • IETF RFCshttps://www.rfc-editor.org/ — the original "RFC" model; a numbered, permanent, individually citable series with a controlled status vocabulary (Proposed Standard, Draft Standard, Obsoleted-by/Updates relations) that directly inspired our status + supersession design.
  • Kubernetes KEPshttps://github.com/kubernetes/enhancements — a monorepo of per-enhancement directories (keps/NNNN-title/), each with structured YAML metadata and a lifecycle status — the closest structural analog to the per-RFC-directory layout proposed here.
  • Zenodo GitHub integration & versioninghttps://help.zenodo.org/docs/ — concept-DOI vs. version-DOI semantics and the deposition API used by the publish-rfc.yml workflow.
  • FAIRsharinghttps://fairsharing.org/ — registry of standards, databases, and policies, for Part 4 amplification.
  • re3datahttps://www.re3data.org/ — registry of research data repositories.

Summary of recommendations

  1. One monorepo (cfde-rfcs) for drafting, review, comment (Issues/Discussions), and a rendered GitHub Pages RFC Book — following the Rust/KEP model.
  2. One independently versioned Zenodo record per RFC, deposited by an explicit per-RFC git tag + CI job — not the repo-granular release hook — gathered under a single Zenodo Community.
  3. Three consistent, cross-linked metadata surfacesCITATION.cff, .zenodo.json, and front-matter→JSON-LD — with ORCIDs, RORs, grant IDs, and an aggressively populated related_identifiers graph.
  4. An explicit versioning policy — concept vs. version DOIs, semantic versioning, a controlled status vocabulary, reciprocal supersession links, and a series-level record.
  5. Selective FAIRsharing / re3data registration for the subset of RFCs that define a standard, data resource, or policy — the cross-domain "find new users" amplifier and the substitute for preprints.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment