Skip to content

feat(learn): citation infrastructure + bibliography page#32

Merged
Bissbert merged 2 commits into
mainfrom
feat/learn-citations-infra
May 12, 2026
Merged

feat(learn): citation infrastructure + bibliography page#32
Bissbert merged 2 commits into
mainfrom
feat/learn-citations-infra

Conversation

@Bissbert
Copy link
Copy Markdown
Contributor

Summary

  • Adds a YAML references: block + {cite:id} inline marker system for /learn/ articles, rendering numbered superscript citations and a DPUB-ARIA doc-bibliography references list at the bottom of each article.
  • Emits citation[] on the LearningResource JSON-LD as ScholarlyArticle / Book / WebPage with DOIs serialised as PropertyValue { propertyID: "doi" } and ISBNs on Book — surface for AI search and Google citation eligibility.
  • Switches author from Organization to Person (E-E-A-T fix per audit P2-GEO-02): name: Fabian Moor, alternateName: Bissbert, @id: https://gemmology.dev/about#author. Per-article author override supported in YAML frontmatter.
  • New /about/sources/ aggregate bibliography page, grouped by kind (Journal articles / Books / Web sources / Standards), sorted by author family + year, with which-articles-cite-this back-links. Renders a placeholder until content PRs land.
  • Adds validate:citations script + CI step that fails the build on dangling {cite:id} markers and warns on unused references.

Architecture

  • Citation index built once in [...slug].astro frontmatter via buildCitationIndex, then threaded through SectionRenderer → PropertyList / DataTable / References as a prop. First-appearance order assigns the [n] number used across the page.
  • resolveCiteMarkers runs after marked.parse (so Markdown does not escape the <sup> output) and before addMineralLinks. Dangling ids render as empty string — never break the page.
  • Discriminated reference union (book / journal / web / standard) in src/content/config.ts. references is optional on every learn entry, so this PR is fully backwards-compatible and can ship before any article gets its citations.
  • DOI → PropertyValue per schema.org best practice. ISBN → Book.isbn. Both also surface as DOI/WorldCat hyperlinks in the visible references list.

Files

  • src/lib/citations/index.ts — index builder, marker resolver, label helpers
  • src/lib/citations/format.ts — shared reference formatter (used by References.astro and /about/sources/)
  • src/components/learn/References.astro — bibliography section component
  • src/components/seo/LearnSchema.astro — Person author + citation array
  • src/components/seo/StructuredData.astro — optional alternateName on Person
  • src/components/learn/SectionRenderer.astro + PropertyList.astro + DataTable.astro — thread citationIndex through render tree
  • src/content/config.ts — Zod discriminated union for references; optional publishedAt and author fields
  • src/pages/about/index.astro (moved from src/pages/about.astro) — Fabian Moor (Bissbert) byline, link to /about/sources/
  • src/pages/about/sources/index.astro — aggregate bibliography page
  • src/pages/learn/[...slug].astro — wires buildCitationIndex and renders <References> after sections
  • scripts/validate-citations.mjs — dangling marker / unused reference detector
  • .github/workflows/ci.yml — adds validate:citations step before build

Phase 2: citation audits (separate followup PRs)

Nine background audit agents have produced gap matrices for every /learn/ article. Output lives under .tmp/citation-audit-*.md (not committed — used as input to bulk YAML edits in gemmology-knowledge):

Category Articles Claims File
fundamentals 9 60 citation-audit-fundamentals.md
equipment 13 52 citation-audit-equipment.md
species 20 147 citation-audit-species.md
identification 15 60 citation-audit-identification.md
phenomena 16 46 citation-audit-phenomena.md
origin (top-level) 15 75 citation-audit-origin-top.md
origin (subdirs) 45 135 citation-audit-origin-countries.md
market 4 38 citation-audit-market.md
care 1 10 citation-audit-care.md
total 138 623

Top corpus-wide sources: Read 2014 Gemmology (DOI 10.4324/9780080507224) · Hughes 2017 Ruby & Sapphire (ISBN 978-0-9645097-6-4) · Palke et al. 2019 G&G geographic-origin trilogy · Nassau 2001 Physics and Chemistry of Color · Schumann 2009 Gemstones of the World · Gübelin & Koivula Photoatlas.

Each audit file ships ready-to-paste YAML references: blocks and inline {cite:id} placement notes — Phase 3 is the bulk edit pass in gemmology-knowledge.

Test plan

  • npm run build — 913 pages, no errors
  • npm run validate:citations — exits 0 on current content (no citations yet)
  • /about/sources/ renders placeholder when no citations exist
  • /about/ renders updated Fabian Moor (Bissbert) byline + link to sources
  • After Phase 3 lands, validate JSON-LD citation array via Google Rich Results Test on /learn/identification/treatments/ (the highest-citation-density article)
  • After Phase 3, manually open one citation back-link to confirm focus moves correctly

Bissbert added 2 commits May 12, 2026 10:22
Wire up a {cite:id} marker system and YAML references block so learn
articles can carry first-class citations with proper SEO and a11y
treatment. References render as a DPUB ARIA doc-bibliography landmark
with role=doc-backlink, and surface in JSON-LD as ScholarlyArticle /
Book / WebPage citation[] entries with DOI as PropertyValue.

Schema (src/content/config.ts)
  - Discriminated reference union (book / journal / web / standard)
  - id slug regex, year required for book/journal/standard
  - top-level references[] optional on learnCollection (backwards-compat)
  - publishedAt frontmatter field added
  - per-article author override

Renderer
  - buildCitationIndex (src/lib/citations/index.ts) scans sections for
    {cite:id} markers and section/item citations[], assigns sequential
    numbers in first-appearance order, silently skips dangling ids
  - resolveCiteMarkers runs after marked.parse, before mineral-linker
  - SectionRenderer threads citationIndex into PropertyList and DataTable
  - References.astro component renders the bibliography list with
    back-links and external rel=noopener noreferrer
  - [...slug].astro wraps index build in try/catch — malformed YAML
    cannot 404 a page; passes ordered refs to LearnSchema for JSON-LD

SEO
  - LearnSchema author switched from Organization to Person with
    @id=https://gemmology.dev/about#author, name="Fabian Moor",
    alternateName="Bissbert" (E-E-A-T fix per audit P2-GEO-02)
  - Per-article articleAuthor prop allows YAML override
  - citation[] array emitted on LearningResource only when references
    are provided (never empty array)
  - DOIs serialised as { @type: PropertyValue, propertyID: "doi" }
  - ISBNs serialised on Book

About page
  - Moved /about.astro → /about/index.astro to free /about/sources/
  - Updated to show Fabian Moor (Bissbert) authorship with link to
    /about/sources/ aggregate bibliography

StructuredData component
  - Added alternateName to optional Person prop
…ions CI

- Extract formatAuthors/doiLink/isbnLink/urlLink/formatReference into
  src/lib/citations/format.ts; update References.astro to import from there.
- Add src/pages/about/sources/index.astro: aggregate bibliography grouped by
  kind (Journal articles / Books / Web sources / Standards), sorted by author
  family name then year, with per-entry cited-in links; placeholder shown when
  no citations are declared yet.
- Add scripts/validate-citations.mjs: validates {cite:id} markers, citations
  arrays, unique ids, valid kinds and years >= 1800; dangling markers exit 1,
  unused references warn only.
- Add validate:citations script to package.json.
- Add .github/workflows/ci.yml: lint/typecheck/build pipeline with sync step
  before validate:citations, matching deploy.yml style.
@github-actions
Copy link
Copy Markdown

🚀 Preview deployed to: https://1ed9a86d.gemmology-dev.pages.dev

@Bissbert Bissbert merged commit 9731d19 into main May 12, 2026
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant