//
··
1% rrxiv.cls -- rrxiv paper class v0.8
2%
3% Provides a LaTeX class for rrxiv submissions. Extends `article` with
4% semantic environments that the rrxiv parser extracts into the Canonical
5% Intermediate Representation (CIR) without requiring post-hoc OCR.
6%
7% v0.8.2 (2026-07-14): \rrxivauthor now DEFERS author rendering — it
8% accumulates (name, affiliation) and emits the authblk block once at
9% \AtBeginDocument. When every author shares one affiliation (the common
10% rrxiv case, e.g. all "The rrxiv project") it renders a single shared
11% \affil with no per-author superscripts; distinct/partial affiliations
12% fall back to per-author \author/\affil. Supersedes the v0.8.1 approach,
13% which triple-printed a shared affiliation (authblk does not merge
14% identical per-author \affil calls).
15%
16% v0.8.1 (2026-07-14): \rrxivauthor paired each \author with an \affil
17% (empty when none given) — authblk silently keeps only the LAST of
18% repeated bare \author{} calls, so multi-author papers using
19% \rrxivauthor rendered a single name in the PDF title block. (Correct for
20% distinct affiliations, but see v0.8.2 for the shared-affiliation case.)
21%
22% v0.8 (2026-07-14, RRP-0030): the `claim` environment's optional
23% argument becomes a key=value list exposing claim.schema fields at the
24% authoring site: `type=` (claim_type), `evidence=` (evidence_type),
25% `confidence=`/`confidence-low=`/`confidence-high=`/`rationale=`,
26% `labels={...}`, and scope keys `models=`/`datasets=`/`regimes=`/
27% `assumptions=`. Backwards compatible: an optional argument containing
28% no `=` is a plain display title exactly as before (titles that contain
29% a literal `=` must be written via `title={...}`). The semantic keys
30% are render-inert here — the rrxiv parser reads them from the source;
31% only `title` affects the rendered theorem note.
32%
33% v0.7 (2026-05-26, RRP-0026): \rrxivauthor gains four new keys for the
34% gold-standard agent attribution shape — `model-name`, `model-vendor`,
35% `model-series`, `model-version`, `model-release-pin`. The previous
36% `model-slug` key (v0.6, RRP-0025) is kept as a deprecated alias for
37% `model-release-pin` so existing papers don't break. Agent authors
38% SHOULD set Name to the full marketing identifier ("Claude Opus 4.7"),
39% with model-name matching it for the single-model case.
40%
41% v0.6 (2026-05-26, RRP-0021 + RRP-0025): new \rrxivauthor macro for
42% structured author records with role/ORCID/agent-handle/provenance keys.
43% Authors call \rrxivauthor[k=v,...]{Name} for each author; the macro
44% emits a pipe-separated RRXIV:author:<n>|... line to the sidecar in
45% declaration order, and falls through to authblk's \author{} so the
46% rendered title block stays visual. Plain \author{...} continues to
47% work as a fallback.
48%
49% v0.5 (2026-05-25): \RequirePackage{tikz} + \usetikzlibrary{calc} at
50% class level so geometric figures don't need preamble boilerplate.
51%
52% v0.4 (2026-05-25): \RequirePackage{float} for [H] figure placement.
53%
54% v0.3 (2026-05-25): visible page-stamp footer. Every page now carries
55% the canonical paper id, version, license, build date, and page number
56% in a small footer rule. Lets a reader holding a printed PDF know which
57% rrxiv revision they're looking at — important when multiple versions
58% of the same paper are in circulation. Override the build date with
59% \rrxivbuilddate{YYYY-MM-DD} for deterministic builds.
60%
61% v0.2 (RRP-0002): edge marker delimiter changed from `:` to `|` to
62% disambiguate edges whose source/target IDs themselves contain colons
63% (which the canonical <paper_id>:claim:<label> convention guarantees).
64% Parsers that recognise the v0.1 format continue to work; the rrxiv
65% reference parser emits a DeprecationWarning when it sees one.
66%
67% License: MIT.
68
69\NeedsTeXFormat{LaTeX2e}
70\ProvidesClass{rrxiv}[2026/07/14 v0.8.2 rrxiv paper class]
71
72% Pass options to article
73\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}}
74\ProcessOptions\relax
75\LoadClass[11pt]{article}
76
77% ---- Required packages ----
78\RequirePackage[a4paper, margin=1in]{geometry}
79\RequirePackage[utf8]{inputenc}
80\RequirePackage[T1]{fontenc}
81\RequirePackage{amsmath, amsthm, amssymb, mathtools}
82\RequirePackage{graphicx}
83% `float` provides the [H] placement specifier used by figure/table
84% environments that must appear inline (e.g. mid-proof TikZ diagrams).
85\RequirePackage{float}
86\RequirePackage{xcolor}
87% TikZ + the `calc` library covers geometric figures (coordinate
88% arithmetic like $(A)!0.5!(B)$ for midpoints). Loading at the class
89% level so paper authors don't have to repeat the boilerplate.
90\RequirePackage{tikz}
91\usetikzlibrary{calc}
92\RequirePackage{keyval} % for \rrxivauthor[k=v,...]{Name} (v0.6)
93\RequirePackage{enumitem}
94\RequirePackage[numbers]{natbib}
95\RequirePackage{booktabs}
96\RequirePackage{authblk}
97\RequirePackage[colorlinks=true,
98 linkcolor=blue!50!black,
99 citecolor=blue!50!black,
100 urlcolor=blue!50!black]{hyperref}
101\RequirePackage{fancyhdr}
102\RequirePackage{lastpage}
103
104% ---- rrxiv metadata commands ----
105% These are extracted by the rrxiv parser into CIR top-level fields.
106\newcommand{\rrxivid}[1]{\def\@rrxivid{#1}}
107\newcommand{\rrxivversion}[1]{\def\@rrxivversion{#1}}
108\newcommand{\rrxivprotocolversion}[1]{\def\@rrxivprotocolversion{#1}}
109\newcommand{\rrxivlicense}[1]{\def\@rrxivlicense{#1}}
110\newcommand{\rrxivtopics}[1]{\def\@rrxivtopics{#1}}
111% Build-date stamp shown in the page footer. Defaults to \today in ISO
112% format; override with \rrxivbuilddate{2026-05-25} to get a deterministic
113% timestamp (useful in CI so the PDF is reproducible across rebuilds).
114\newcommand{\rrxivbuilddate}[1]{\def\@rrxivbuilddate{#1}}
115
116% Defaults
117\rrxivid{TBD}
118\rrxivversion{v1}
119\rrxivprotocolversion{0.1.0}
120\rrxivlicense{CC-BY-4.0}
121\rrxivtopics{}
122\rrxivbuilddate{\the\year-\ifnum\month<10 0\fi\the\month-\ifnum\day<10 0\fi\the\day}
123
124% ---- Page-stamp footer (v0.3) ----
125% Every page carries the canonical paper id, version, license, build
126% date, and page-count in a small footer rule. Style picks:
127% - footnotesize so it never competes with the body text
128% - typewriter (\texttt) on the id so rrxiv:YYYY.MM.NNNNN reads as
129% an identifier, not prose
130% - thin rule above the footer so it's clearly metadata, not content
131\pagestyle{fancy}
132\fancyhf{}
133\renewcommand{\headrulewidth}{0pt}
134\renewcommand{\footrulewidth}{0.4pt}
135\fancyfoot[L]{\footnotesize\texttt{\@rrxivid} \textperiodcentered\ \@rrxivversion}
136\fancyfoot[C]{\footnotesize\thepage\ /\ \pageref{LastPage}}
137\fancyfoot[R]{\footnotesize\@rrxivlicense\ \textperiodcentered\ \@rrxivbuilddate}
138% \maketitle redefines page 1 to use the `plain` pagestyle, which would
139% strip our footer from the title page (the most-shared page). Override
140% `plain` so the stamp survives \maketitle.
141\fancypagestyle{plain}{%
142 \fancyhf{}%
143 \renewcommand{\headrulewidth}{0pt}%
144 \renewcommand{\footrulewidth}{0.4pt}%
145 \fancyfoot[L]{\footnotesize\texttt{\@rrxivid} \textperiodcentered\ \@rrxivversion}%
146 \fancyfoot[C]{\footnotesize\thepage\ /\ \pageref{LastPage}}%
147 \fancyfoot[R]{\footnotesize\@rrxivlicense\ \textperiodcentered\ \@rrxivbuilddate}%
148}
149
150% ---- Sidecar log channel ----
151% The rrxiv parser reads structured metadata from a `.rrxiv.aux` channel
152% emitted via \write. This lets us extract claim content without re-parsing
153% TeX after the fact. The sidecar uses a simple line-based format:
154% RRXIV:<kind>:<label>:<json-escaped-content>
155%
156% v0.1: emit on \begin{...} and \end{...} for tracked environments.
157% v0.2: capture content body. For now the parser falls back to source scan.
158\newwrite\rrxiv@sidecar
159% v0.6: open the sidecar at class-load time so preamble macros
160% (like \rrxivauthor) can write to it before \begin{document}. The
161% RRXIV:meta:* lines still emit at \AtBeginDocument because they need
162% the metadata commands to have run.
163\immediate\openout\rrxiv@sidecar=\jobname.rrxiv.aux\relax
164\AtBeginDocument{%
165 \immediate\write\rrxiv@sidecar{RRXIV:meta:id:\@rrxivid}%
166 \immediate\write\rrxiv@sidecar{RRXIV:meta:version:\@rrxivversion}%
167 \immediate\write\rrxiv@sidecar{RRXIV:meta:protocol:\@rrxivprotocolversion}%
168 \immediate\write\rrxiv@sidecar{RRXIV:meta:license:\@rrxivlicense}%
169 \immediate\write\rrxiv@sidecar{RRXIV:meta:topics:\@rrxivtopics}%
170 % Emit the accumulated \rrxivauthor records into authblk now, before
171 % \maketitle, with shared affiliations collapsed (v0.8.2).
172 \rrxiv@emitauthors
173}
174\AtEndDocument{\immediate\closeout\rrxiv@sidecar}
175
176\newcommand{\rrxiv@emit}[2]{%
177 \immediate\write\rrxiv@sidecar{RRXIV:#1:\@currentlabel}%
178}
179
180% ---- Theorem-like environments (visual style) ----
181\theoremstyle{definition}
182\newtheorem{rrxiv@claim}{Claim}
183\newtheorem{rrxiv@evidence}{Evidence}
184\newtheorem{rrxiv@observation}{Observation}
185\newtheorem{rrxiv@remark}{Remark}
186\newtheorem{rrxiv@scope}{Scope}
187\newtheorem{rrxiv@openquestion}{Open Question}
188
189% ---- Public semantic environments ----
190% Each takes an optional title. Each emits a sidecar marker on \begin so the
191% parser can locate it in the source. Claims, in particular, get a stable
192% local label that the CIR uses for the claim ID (paper_id:label).
193
194% v0.8 (RRP-0030): the claim environment's optional argument doubles as a
195% key=value list. If the argument contains a `=`, it is parsed with keyval:
196% `title=` sets the rendered theorem note; the semantic keys below are
197% accepted but render-inert (the rrxiv parser reads them from the SOURCE,
198% mapping them onto claim.schema fields — see proposals/0030). An argument
199% with no `=` is a plain title, exactly as in v0.7.
200\RequirePackage{keyval}
201\def\rrxiv@claim@title{}
202\define@key{rrxivclaim}{title}{\def\rrxiv@claim@title{#1}}
203% Semantic keys (parser-consumed; no-ops for rendering):
204\define@key{rrxivclaim}{type}{}
205\define@key{rrxivclaim}{evidence}{}
206\define@key{rrxivclaim}{confidence}{}
207\define@key{rrxivclaim}{confidence-low}{}
208\define@key{rrxivclaim}{confidence-high}{}
209\define@key{rrxivclaim}{rationale}{}
210\define@key{rrxivclaim}{labels}{}
211\define@key{rrxivclaim}{models}{}
212\define@key{rrxivclaim}{datasets}{}
213\define@key{rrxivclaim}{regimes}{}
214\define@key{rrxivclaim}{assumptions}{}
215
216\newenvironment{claim}[1][]{%
217 \in@{=}{#1}%
218 \ifin@
219 \def\rrxiv@claim@title{}%
220 \setkeys{rrxivclaim}{#1}%
221 \else
222 \def\rrxiv@claim@title{#1}%
223 \fi
224 \begin{rrxiv@claim}[\rrxiv@claim@title]%
225 \rrxiv@emit{claim}{begin}%
226}{%
227 \end{rrxiv@claim}%
228}
229
230\newenvironment{evidence}[1][]{%
231 \begin{rrxiv@evidence}[#1]%
232 \rrxiv@emit{evidence}{begin}%
233}{%
234 \end{rrxiv@evidence}%
235}
236
237\newenvironment{observation}[1][]{%
238 \begin{rrxiv@observation}[#1]%
239 \rrxiv@emit{observation}{begin}%
240}{%
241 \end{rrxiv@observation}%
242}
243
244\newenvironment{rrxivremark}[1][]{%
245 \begin{rrxiv@remark}[#1]%
246 \rrxiv@emit{remark}{begin}%
247}{%
248 \end{rrxiv@remark}%
249}
250
251\newenvironment{scope}[1][]{%
252 \begin{rrxiv@scope}[#1]%
253 \rrxiv@emit{scope}{begin}%
254}{%
255 \end{rrxiv@scope}%
256}
257
258\newenvironment{openquestion}[1][]{%
259 \begin{rrxiv@openquestion}[#1]%
260 \rrxiv@emit{openquestion}{begin}%
261}{%
262 \end{rrxiv@openquestion}%
263}
264
265% ---- Inline edge declarations ----
266% These declare typed edges between claims without producing visual output.
267% They emit sidecar markers only.
268
269% v0.2: edge marker uses `|` between src and dst (RRP-0002).
270\newcommand{\dependson}[2]{\immediate\write\rrxiv@sidecar{RRXIV:edge:depends_on:#1|#2}}
271\newcommand{\contradicts}[2]{\immediate\write\rrxiv@sidecar{RRXIV:edge:contradicts:#1|#2}}
272\newcommand{\extendsclaim}[2]{\immediate\write\rrxiv@sidecar{RRXIV:edge:extends:#1|#2}}
273\newcommand{\supports}[2]{\immediate\write\rrxiv@sidecar{RRXIV:edge:supports:#1|#2}}
274
275% ---- Structured author records (v0.6, RRP-0021 + RRP-0025) ----
276%
277% \rrxivauthor[k=v,...]{Display Name}
278%
279% Accepted keys (all optional except the positional Name):
280% orcid ORCID iD (0000-XXXX-XXXX-XXXX form)
281% role author | coauthor | translator | editor | encoder | agent
282% handle agent handle (e.g. `agent:claude-opus-4.7`); implies is-agent=true
283% is-agent true|false (default false)
284% affiliation free-form institution
285% email contact email
286% model-slug RRP-0025 vendor model identifier (lowercased, hyphens)
287% model-family RRP-0025 coarse family (`claude`, `gpt`, `gemini`, ...)
288% model-release-date YYYY-MM-DD
289% inference-environment free-form (`Claude Code CLI`, etc.)
290%
291% Emits one pipe-separated line per call to the sidecar:
292% RRXIV:author:<n>|name=...|orcid=...|role=...|...
293% Empty fields are still emitted as `key=`; the parser strips them.
294%
295% Falls through to authblk's \author{Name} so the visible title block
296% still renders. Authors who prefer the plain \author{X \and Y \and Z}
297% form can use that instead — the parser then falls back to merging
298% rrxiv-meta.json's authors[] array onto the parsed names by name-match.
299\newcounter{rrxiv@author@count}
300\setcounter{rrxiv@author@count}{0}
301
302% ---- Deferred author rendering (v0.8.2) ----
303% authblk drops earlier authors when consecutive \author calls lack an
304% intervening \affil, and does NOT merge identical affiliations supplied as
305% separate \affil calls (both verified). So \rrxivauthor accumulates
306% (name, affiliation) pairs and rrxiv emits the authblk declarations once, at
307% \AtBeginDocument: a SINGLE shared \affil when every author carries the same
308% non-empty affiliation (the common rrxiv case — all "The rrxiv project" —
309% renders one clean footnote, no per-author superscripts), otherwise
310% per-author \author/\affil so distinct or partial affiliations still show.
311\def\rrxiv@ai@list{}
312\newif\ifrrxiv@ai@same
313\newif\ifrrxiv@ai@affdone
314\newcommand{\rrxiv@ai@add}[2]{%
315 \protected@edef\rrxiv@ai@tmp{\noexpand\rrxiv@ai@do{\unexpanded{#1}}{#2}}%
316 \expandafter\g@addto@macro\expandafter\rrxiv@ai@list\expandafter{\rrxiv@ai@tmp}%
317}
318% Pass-1 scanner: clears \ifrrxiv@ai@same if any author has no affiliation
319% or two non-empty affiliations differ.
320\def\rrxiv@ai@scan#1#2{%
321 \edef\rrxiv@ai@a{\detokenize{#2}}%
322 \ifx\rrxiv@ai@a\@empty
323 \rrxiv@ai@samefalse
324 \else
325 \ifx\rrxiv@ai@first\@undefined
326 \let\rrxiv@ai@first\rrxiv@ai@a
327 \else
328 \ifx\rrxiv@ai@a\rrxiv@ai@first\else\rrxiv@ai@samefalse\fi
329 \fi
330 \fi
331}
332\newcommand{\rrxiv@emitauthors}{%
333 \rrxiv@ai@sametrue
334 \let\rrxiv@ai@first\@undefined
335 \let\rrxiv@ai@do\rrxiv@ai@scan
336 \rrxiv@ai@list
337 \ifx\rrxiv@ai@first\@undefined\rrxiv@ai@samefalse\fi
338 \ifrrxiv@ai@same
339 % All authors share one non-empty affiliation: bare authors + one \affil.
340 \def\rrxiv@ai@do##1##2{\author{##1}}%
341 \rrxiv@ai@list
342 \rrxiv@ai@affdonefalse
343 \def\rrxiv@ai@do##1##2{\ifrrxiv@ai@affdone\else\affil{##2}\rrxiv@ai@affdonetrue\fi}%
344 \rrxiv@ai@list
345 \else
346 % Mixed/distinct/absent affiliations: pair each author with its own
347 % \affil (empty renders nothing but still closes the author).
348 \def\rrxiv@ai@do##1##2{\author{##1}\affil{##2}}%
349 \rrxiv@ai@list
350 \fi
351}
352
353\define@key{rrxiv@author}{orcid}{\def\rrxiv@author@orcid{#1}}
354\define@key{rrxiv@author}{role}{\def\rrxiv@author@role{#1}}
355\define@key{rrxiv@author}{handle}{\def\rrxiv@author@handle{#1}}
356\define@key{rrxiv@author}{is-agent}{\def\rrxiv@author@isagent{#1}}
357\define@key{rrxiv@author}{affiliation}{\def\rrxiv@author@affiliation{#1}}
358\define@key{rrxiv@author}{email}{\def\rrxiv@author@email{#1}}
359% v0.7: model-name + vendor + series + version + release-pin are the
360% RRP-0026 fields. model-slug is kept as a deprecated alias for
361% release-pin so v0.6 papers don't break.
362\define@key{rrxiv@author}{model-name}{\def\rrxiv@author@modelname{#1}}
363\define@key{rrxiv@author}{model-vendor}{\def\rrxiv@author@modelvendor{#1}}
364\define@key{rrxiv@author}{model-family}{\def\rrxiv@author@modelfamily{#1}}
365\define@key{rrxiv@author}{model-series}{\def\rrxiv@author@modelseries{#1}}
366\define@key{rrxiv@author}{model-version}{\def\rrxiv@author@modelversion{#1}}
367\define@key{rrxiv@author}{model-release-pin}{\def\rrxiv@author@modelreleasepin{#1}}
368\define@key{rrxiv@author}{model-slug}{\def\rrxiv@author@modelreleasepin{#1}}% deprecated alias (v0.6)
369\define@key{rrxiv@author}{model-release-date}{\def\rrxiv@author@modelrelease{#1}}
370\define@key{rrxiv@author}{inference-environment}{\def\rrxiv@author@infenv{#1}}
371
372\newcommand{\rrxivauthor}[2][]{%
373 % Reset all keys to empty before each call so prior \rrxivauthor's
374 % keys don't leak into this one.
375 \def\rrxiv@author@orcid{}%
376 \def\rrxiv@author@role{}%
377 \def\rrxiv@author@handle{}%
378 \def\rrxiv@author@isagent{}%
379 \def\rrxiv@author@affiliation{}%
380 \def\rrxiv@author@email{}%
381 \def\rrxiv@author@modelname{}%
382 \def\rrxiv@author@modelvendor{}%
383 \def\rrxiv@author@modelfamily{}%
384 \def\rrxiv@author@modelseries{}%
385 \def\rrxiv@author@modelversion{}%
386 \def\rrxiv@author@modelreleasepin{}%
387 \def\rrxiv@author@modelrelease{}%
388 \def\rrxiv@author@infenv{}%
389 \setkeys{rrxiv@author}{#1}%
390 \stepcounter{rrxiv@author@count}%
391 \immediate\write\rrxiv@sidecar{%
392RRXIV:author:\arabic{rrxiv@author@count}|name=#2|orcid=\rrxiv@author@orcid|role=\rrxiv@author@role|handle=\rrxiv@author@handle|is_agent=\rrxiv@author@isagent|affiliation=\rrxiv@author@affiliation|email=\rrxiv@author@email|model_name=\rrxiv@author@modelname|model_vendor=\rrxiv@author@modelvendor|model_family=\rrxiv@author@modelfamily|model_series=\rrxiv@author@modelseries|model_version=\rrxiv@author@modelversion|model_release_pin=\rrxiv@author@modelreleasepin|model_release_date=\rrxiv@author@modelrelease|inference_environment=\rrxiv@author@infenv%
393 }%
394 % Accumulate for deferred, de-duplicated rendering at \AtBeginDocument
395 % (see \rrxiv@emitauthors above) — NOT an immediate \author/\affil, which
396 % either drops earlier authors or triple-prints a shared affiliation.
397 \rrxiv@ai@add{#2}{\rrxiv@author@affiliation}%
398}
399
400% ---- Convenience macros consistent with common math notation ----
401\newcommand{\R}{\mathbb{R}}
402\newcommand{\N}{\mathbb{N}}
403\newcommand{\Z}{\mathbb{Z}}
404\newcommand{\E}{\mathbb{E}}
405\newcommand{\Prob}{\mathbb{P}}
406\newcommand{\1}{\mathbf{1}}
407
408% ---- Done ----
409\endinput
410