paper-preflight 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. paper_preflight-0.1.0/.claude-plugin/marketplace.json +17 -0
  2. paper_preflight-0.1.0/.gitattributes +11 -0
  3. paper_preflight-0.1.0/.gitignore +30 -0
  4. paper_preflight-0.1.0/.pre-commit-config.yaml +19 -0
  5. paper_preflight-0.1.0/.pre-commit-hooks.yaml +18 -0
  6. paper_preflight-0.1.0/.python-version +1 -0
  7. paper_preflight-0.1.0/CHANGELOG.md +91 -0
  8. paper_preflight-0.1.0/CODE_OF_CONDUCT.md +14 -0
  9. paper_preflight-0.1.0/CONTRIBUTING.md +42 -0
  10. paper_preflight-0.1.0/LICENSE +21 -0
  11. paper_preflight-0.1.0/PKG-INFO +341 -0
  12. paper_preflight-0.1.0/README.md +303 -0
  13. paper_preflight-0.1.0/README.zh-CN.md +283 -0
  14. paper_preflight-0.1.0/SECURITY.md +18 -0
  15. paper_preflight-0.1.0/THIRD_PARTY_NOTICES.md +39 -0
  16. paper_preflight-0.1.0/action.yml +80 -0
  17. paper_preflight-0.1.0/docs/PROGRESS.md +148 -0
  18. paper_preflight-0.1.0/docs/adr/0000-template.md +16 -0
  19. paper_preflight-0.1.0/docs/adr/0001-source-first-input.md +28 -0
  20. paper_preflight-0.1.0/docs/adr/0002-verdicts-and-abstention.md +45 -0
  21. paper_preflight-0.1.0/docs/adr/0003-identifier-first-routing.md +101 -0
  22. paper_preflight-0.1.0/docs/adr/0004-no-llm-in-verdicts.md +25 -0
  23. paper_preflight-0.1.0/docs/adr/0005-http-adapters-and-cache.md +30 -0
  24. paper_preflight-0.1.0/docs/adr/0006-license-policy.md +28 -0
  25. paper_preflight-0.1.0/docs/adr/0007-sarif-canonical-output.md +23 -0
  26. paper_preflight-0.1.0/docs/adr/0008-python-and-tooling.md +23 -0
  27. paper_preflight-0.1.0/docs/adr/0009-distribution-matrix.md +29 -0
  28. paper_preflight-0.1.0/docs/adr/0010-parsing-stack.md +43 -0
  29. paper_preflight-0.1.0/docs/adr/README.md +19 -0
  30. paper_preflight-0.1.0/docs/github-action.md +55 -0
  31. paper_preflight-0.1.0/docs/mcp.md +92 -0
  32. paper_preflight-0.1.0/docs/pre-commit.md +31 -0
  33. paper_preflight-0.1.0/docs/releasing.md +58 -0
  34. paper_preflight-0.1.0/docs/spikes/S1-dblp-sparql.md +218 -0
  35. paper_preflight-0.1.0/docs/spikes/S2-crossref.md +165 -0
  36. paper_preflight-0.1.0/docs/spikes/S3-openalex.md +156 -0
  37. paper_preflight-0.1.0/docs/spikes/S4-arxiv-datacite-doiorg.md +164 -0
  38. paper_preflight-0.1.0/docs/spikes/S5-semantic-scholar.md +119 -0
  39. paper_preflight-0.1.0/docs/spikes/S8-datasets.md +312 -0
  40. paper_preflight-0.1.0/evals/README.md +66 -0
  41. paper_preflight-0.1.0/evals/datasets.lock +151 -0
  42. paper_preflight-0.1.0/evals/hallmark_disputed.toml +60 -0
  43. paper_preflight-0.1.0/evals/results/hallmark-dev_public.md +67 -0
  44. paper_preflight-0.1.0/evals/results/hallmark-test_public.md +58 -0
  45. paper_preflight-0.1.0/evals/run_hallmark.py +161 -0
  46. paper_preflight-0.1.0/examples/demo-paper/EXPECTED.md +29 -0
  47. paper_preflight-0.1.0/examples/demo-paper/main.tex +36 -0
  48. paper_preflight-0.1.0/examples/demo-paper/refs.bib +131 -0
  49. paper_preflight-0.1.0/glama.json +4 -0
  50. paper_preflight-0.1.0/plugins/paper-preflight/.claude-plugin/plugin.json +12 -0
  51. paper_preflight-0.1.0/plugins/paper-preflight/.mcp.json +15 -0
  52. paper_preflight-0.1.0/plugins/paper-preflight/skills/paper-preflight/SKILL.md +51 -0
  53. paper_preflight-0.1.0/pyproject.toml +119 -0
  54. paper_preflight-0.1.0/server.json +36 -0
  55. paper_preflight-0.1.0/src/paper_preflight/__init__.py +3 -0
  56. paper_preflight-0.1.0/src/paper_preflight/__main__.py +3 -0
  57. paper_preflight-0.1.0/src/paper_preflight/bib/__init__.py +1 -0
  58. paper_preflight-0.1.0/src/paper_preflight/bib/ids.py +163 -0
  59. paper_preflight-0.1.0/src/paper_preflight/bib/names.py +124 -0
  60. paper_preflight-0.1.0/src/paper_preflight/bib/normalize.py +38 -0
  61. paper_preflight-0.1.0/src/paper_preflight/bib/parse.py +278 -0
  62. paper_preflight-0.1.0/src/paper_preflight/bibtex.py +158 -0
  63. paper_preflight-0.1.0/src/paper_preflight/cache.py +200 -0
  64. paper_preflight-0.1.0/src/paper_preflight/check.py +236 -0
  65. paper_preflight-0.1.0/src/paper_preflight/cli.py +487 -0
  66. paper_preflight-0.1.0/src/paper_preflight/connectivity.py +106 -0
  67. paper_preflight-0.1.0/src/paper_preflight/data/__init__.py +1 -0
  68. paper_preflight-0.1.0/src/paper_preflight/data/suspicious_sources.toml +7 -0
  69. paper_preflight-0.1.0/src/paper_preflight/evaluation/__init__.py +1 -0
  70. paper_preflight-0.1.0/src/paper_preflight/evaluation/hallmark.py +264 -0
  71. paper_preflight-0.1.0/src/paper_preflight/fetch.py +154 -0
  72. paper_preflight-0.1.0/src/paper_preflight/findings.py +116 -0
  73. paper_preflight-0.1.0/src/paper_preflight/fixes.py +195 -0
  74. paper_preflight-0.1.0/src/paper_preflight/hygiene.py +245 -0
  75. paper_preflight-0.1.0/src/paper_preflight/identifier_lint.py +94 -0
  76. paper_preflight-0.1.0/src/paper_preflight/match.py +593 -0
  77. paper_preflight-0.1.0/src/paper_preflight/mcp_server.py +233 -0
  78. paper_preflight-0.1.0/src/paper_preflight/py.typed +0 -0
  79. paper_preflight-0.1.0/src/paper_preflight/report/__init__.py +1 -0
  80. paper_preflight-0.1.0/src/paper_preflight/report/jsonout.py +107 -0
  81. paper_preflight-0.1.0/src/paper_preflight/report/sarif.py +117 -0
  82. paper_preflight-0.1.0/src/paper_preflight/report/text.py +99 -0
  83. paper_preflight-0.1.0/src/paper_preflight/resolve.py +497 -0
  84. paper_preflight-0.1.0/src/paper_preflight/rules.py +296 -0
  85. paper_preflight-0.1.0/src/paper_preflight/sources/__init__.py +1 -0
  86. paper_preflight-0.1.0/src/paper_preflight/sources/arxiv.py +161 -0
  87. paper_preflight-0.1.0/src/paper_preflight/sources/base.py +400 -0
  88. paper_preflight-0.1.0/src/paper_preflight/sources/crossref.py +174 -0
  89. paper_preflight-0.1.0/src/paper_preflight/sources/datacite.py +93 -0
  90. paper_preflight-0.1.0/src/paper_preflight/sources/dblp.py +229 -0
  91. paper_preflight-0.1.0/src/paper_preflight/sources/doiorg.py +161 -0
  92. paper_preflight-0.1.0/src/paper_preflight/sources/openalex.py +117 -0
  93. paper_preflight-0.1.0/src/paper_preflight/sources/pubmed.py +157 -0
  94. paper_preflight-0.1.0/src/paper_preflight/sources/record.py +99 -0
  95. paper_preflight-0.1.0/src/paper_preflight/sources/semanticscholar.py +88 -0
  96. paper_preflight-0.1.0/src/paper_preflight/tex/__init__.py +1 -0
  97. paper_preflight-0.1.0/src/paper_preflight/tex/auxdata.py +103 -0
  98. paper_preflight-0.1.0/src/paper_preflight/tex/cites.py +229 -0
  99. paper_preflight-0.1.0/src/paper_preflight/tex/mask.py +114 -0
  100. paper_preflight-0.1.0/src/paper_preflight/tex/project.py +236 -0
  101. paper_preflight-0.1.0/src/paper_preflight/textio.py +86 -0
  102. paper_preflight-0.1.0/src/paper_preflight/verdict.py +786 -0
  103. paper_preflight-0.1.0/tests/__init__.py +1 -0
  104. paper_preflight-0.1.0/tests/conftest.py +47 -0
  105. paper_preflight-0.1.0/tests/fake_web.py +167 -0
  106. paper_preflight-0.1.0/tests/fixtures/schemas/sarif-schema-2.1.0.json +3389 -0
  107. paper_preflight-0.1.0/tests/fixtures/sources/README.md +11 -0
  108. paper_preflight-0.1.0/tests/fixtures/sources/arxiv/idlist_gelu_versions.xml +98 -0
  109. paper_preflight-0.1.0/tests/fixtures/sources/arxiv/idlist_multi.xml +223 -0
  110. paper_preflight-0.1.0/tests/fixtures/sources/arxiv/idlist_nonexistent.xml +10 -0
  111. paper_preflight-0.1.0/tests/fixtures/sources/arxiv/idlist_withdrawn_versions_and_jref.xml +63 -0
  112. paper_preflight-0.1.0/tests/fixtures/sources/arxiv/search_ti_phrase_t1.xml +147 -0
  113. paper_preflight-0.1.0/tests/fixtures/sources/arxiv/search_ti_t8.xml +10 -0
  114. paper_preflight-0.1.0/tests/fixtures/sources/crossref/batch_filter_doi.json +673 -0
  115. paper_preflight-0.1.0/tests/fixtures/sources/crossref/biblio_t1_withauthors.json +1234 -0
  116. paper_preflight-0.1.0/tests/fixtures/sources/crossref/biblio_t2.json +546 -0
  117. paper_preflight-0.1.0/tests/fixtures/sources/crossref/biblio_t8.json +409 -0
  118. paper_preflight-0.1.0/tests/fixtures/sources/crossref/work_65215_ysbyhc05.json +229 -0
  119. paper_preflight-0.1.0/tests/fixtures/sources/crossref/work_bert.json +162 -0
  120. paper_preflight-0.1.0/tests/fixtures/sources/crossref/work_cvpr.json +166 -0
  121. paper_preflight-0.1.0/tests/fixtures/sources/crossref/work_tacl.json +400 -0
  122. paper_preflight-0.1.0/tests/fixtures/sources/crossref/work_wakefield.json +336 -0
  123. paper_preflight-0.1.0/tests/fixtures/sources/datacite/dc_arxiv_attn.json +581 -0
  124. paper_preflight-0.1.0/tests/fixtures/sources/datacite/dc_arxiv_demo_batch.json +200 -0
  125. paper_preflight-0.1.0/tests/fixtures/sources/datacite/dc_arxiv_gelu.json +255 -0
  126. paper_preflight-0.1.0/tests/fixtures/sources/datacite/dc_multi_ids.json +38 -0
  127. paper_preflight-0.1.0/tests/fixtures/sources/datacite/dc_nonexistent.json +8 -0
  128. paper_preflight-0.1.0/tests/fixtures/sources/dblp/batch_doi_upper.json +134 -0
  129. paper_preflight-0.1.0/tests/fixtures/sources/dblp/full_records.json +1972 -0
  130. paper_preflight-0.1.0/tests/fixtures/sources/dblp/full_records_adam.json +103 -0
  131. paper_preflight-0.1.0/tests/fixtures/sources/dblp/gelu_by_doi.json +31 -0
  132. paper_preflight-0.1.0/tests/fixtures/sources/dblp/link_corr_to_conf.json +111 -0
  133. paper_preflight-0.1.0/tests/fixtures/sources/dblp/prefix_adam.json +26 -0
  134. paper_preflight-0.1.0/tests/fixtures/sources/dblp/prefix_t1.json +246 -0
  135. paper_preflight-0.1.0/tests/fixtures/sources/dblp/prefix_t8.json +15 -0
  136. paper_preflight-0.1.0/tests/fixtures/sources/dblp/sparql_dataset_meta.json +101 -0
  137. paper_preflight-0.1.0/tests/fixtures/sources/doiorg/cn_datacite_arxiv.json +57 -0
  138. paper_preflight-0.1.0/tests/fixtures/sources/doiorg/doira_multi.json +26 -0
  139. paper_preflight-0.1.0/tests/fixtures/sources/doiorg/hdl_cvpr.json +16 -0
  140. paper_preflight-0.1.0/tests/fixtures/sources/openalex/batch_or_doi.json +2070 -0
  141. paper_preflight-0.1.0/tests/fixtures/sources/openalex/title_search_t8.json +26 -0
  142. paper_preflight-0.1.0/tests/fixtures/sources/openalex/work_W2626778328_attention.json +1470 -0
  143. paper_preflight-0.1.0/tests/fixtures/sources/openalex/work_doi_cvpr.json +1196 -0
  144. paper_preflight-0.1.0/tests/fixtures/sources/openalex/work_doi_wakefield.json +1523 -0
  145. paper_preflight-0.1.0/tests/fixtures/sources/pubmed/esummary_pmc.json +39 -0
  146. paper_preflight-0.1.0/tests/fixtures/sources/pubmed/esummary_pubmed.json +342 -0
  147. paper_preflight-0.1.0/tests/test_bib_fetch.py +130 -0
  148. paper_preflight-0.1.0/tests/test_bib_fix.py +110 -0
  149. paper_preflight-0.1.0/tests/test_bib_ids.py +76 -0
  150. paper_preflight-0.1.0/tests/test_bib_parse.py +111 -0
  151. paper_preflight-0.1.0/tests/test_bibtex.py +130 -0
  152. paper_preflight-0.1.0/tests/test_cache.py +58 -0
  153. paper_preflight-0.1.0/tests/test_check_offline.py +188 -0
  154. paper_preflight-0.1.0/tests/test_check_online.py +196 -0
  155. paper_preflight-0.1.0/tests/test_cli.py +88 -0
  156. paper_preflight-0.1.0/tests/test_evaluation.py +122 -0
  157. paper_preflight-0.1.0/tests/test_identifier_lint.py +51 -0
  158. paper_preflight-0.1.0/tests/test_match.py +416 -0
  159. paper_preflight-0.1.0/tests/test_mcp_server.py +187 -0
  160. paper_preflight-0.1.0/tests/test_plugin_manifests.py +100 -0
  161. paper_preflight-0.1.0/tests/test_pre_commit_hooks.py +19 -0
  162. paper_preflight-0.1.0/tests/test_pubmed.py +102 -0
  163. paper_preflight-0.1.0/tests/test_resolve.py +171 -0
  164. paper_preflight-0.1.0/tests/test_sarif.py +67 -0
  165. paper_preflight-0.1.0/tests/test_semanticscholar.py +142 -0
  166. paper_preflight-0.1.0/tests/test_source_fetch.py +155 -0
  167. paper_preflight-0.1.0/tests/test_source_parsers.py +212 -0
  168. paper_preflight-0.1.0/tests/test_sources_base.py +302 -0
  169. paper_preflight-0.1.0/tests/test_tex_cites.py +92 -0
  170. paper_preflight-0.1.0/tests/test_tex_project.py +155 -0
  171. paper_preflight-0.1.0/tests/test_verdict.py +658 -0
  172. paper_preflight-0.1.0/uv.lock +2497 -0
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "paper-preflight",
3
+ "owner": {
4
+ "name": "amos689",
5
+ "url": "https://github.com/amos689"
6
+ },
7
+ "description": "paper-preflight: pre-submission reference checks for LaTeX papers.",
8
+ "plugins": [
9
+ {
10
+ "name": "paper-preflight",
11
+ "source": "./plugins/paper-preflight",
12
+ "description": "Verify every reference of a LaTeX paper against real scholarly records before submission: an MCP server plus a skill that runs the check and fixes what it proves wrong.",
13
+ "category": "productivity",
14
+ "tags": ["latex", "bibtex", "citations", "research"]
15
+ }
16
+ ]
17
+ }
@@ -0,0 +1,11 @@
1
+ # Normalize text files to LF in the repository.
2
+ * text=auto eol=lf
3
+
4
+ # Test fixtures must keep their exact bytes (CRLF, BOM, GB18030, etc.).
5
+ tests/fixtures/** -text
6
+ evals/cassettes/** -text
7
+
8
+ *.png binary
9
+ *.jpg binary
10
+ *.pdf binary
11
+ *.gif binary
@@ -0,0 +1,30 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .venv/
6
+ build/
7
+ dist/
8
+ .coverage
9
+ coverage.xml
10
+ htmlcov/
11
+ .pytest_cache/
12
+ .mypy_cache/
13
+ .ruff_cache/
14
+ .hypothesis/
15
+
16
+ # paper-preflight outputs
17
+ .preflight/
18
+
19
+ # Spike scratch space and downloaded benchmark data (never committed)
20
+ .spikes/
21
+ evals/.data/
22
+ evals/.cache/
23
+ evals/results/*.jsonl
24
+
25
+ # Editors / OS
26
+ .vscode/
27
+ .idea/
28
+ .DS_Store
29
+ Thumbs.db
30
+ .pytest_tmp/
@@ -0,0 +1,19 @@
1
+ repos:
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
+ rev: v6.0.0
4
+ hooks:
5
+ - id: trailing-whitespace
6
+ exclude: ^tests/fixtures/
7
+ - id: end-of-file-fixer
8
+ exclude: ^tests/fixtures/
9
+ - id: check-yaml
10
+ - id: check-toml
11
+ - id: check-merge-conflict
12
+ - id: check-added-large-files
13
+ args: ["--maxkb=500"]
14
+ - repo: https://github.com/astral-sh/ruff-pre-commit
15
+ rev: v0.16.10
16
+ hooks:
17
+ - id: ruff-check
18
+ args: [--fix]
19
+ - id: ruff-format
@@ -0,0 +1,18 @@
1
+ # pre-commit hooks for LaTeX projects (https://pre-commit.com). Both check the whole project in
2
+ # the repository root, so they run once per commit when a .tex or .bib file changed.
3
+ - id: paper-preflight
4
+ name: paper-preflight (verify references)
5
+ description: Verify every cited reference against Crossref, dblp, arXiv, DataCite and OpenAlex.
6
+ entry: paper-preflight check
7
+ language: python
8
+ types_or: [tex, bib]
9
+ pass_filenames: false
10
+ require_serial: true
11
+ - id: paper-preflight-offline
12
+ name: paper-preflight (offline, cached answers only)
13
+ description: Citation-key checks plus cached reference verdicts; never touches the network.
14
+ entry: paper-preflight check --offline
15
+ language: python
16
+ types_or: [tex, bib]
17
+ pass_filenames: false
18
+ require_serial: true
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,91 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses
5
+ [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.1.0] - 2026-10-03
10
+
11
+ The first release.
12
+
13
+ ### Added
14
+
15
+ - Project scaffold: packaging, CLI entry point (`--version`, `doctor`), CI, contribution docs.
16
+ - Verdict engine: one verdict per reference (verified, metadata mismatch, identifier conflict,
17
+ not found, cannot determine) with rules REF001-REF005, REF010-REF015, REF018, REF090 and RUN001.
18
+ Search results with another title and no author in common are other works: they no longer
19
+ keep an entry nobody found from being reported as not found (REF003).
20
+ - `check` verifies the cited references online by default; `--offline` answers from the local
21
+ cache only. Text output adds a verdict summary line; JSON adds `verification` and `references`.
22
+ Exit code 2 when a source was unavailable and nothing blocking was found.
23
+ - `--refresh` (`check`, `bib fetch`, `bib fix`) asks every source again instead of using cached
24
+ answers; within the run each answer is still asked for once. It contradicts `--offline`.
25
+ - The JSON report records what each source did (`verification.sources`: requests, cache hits,
26
+ stale hits, negatives and unavailability by reason), so a run can be audited and compared.
27
+ - Releases are published to PyPI from GitHub Releases through trusted publishing, with PEP 740
28
+ attestations (`release.yml`, `docs/releasing.md`); the PyPI page links back to GitHub.
29
+ - When the arXiv API refuses requests or times out, arXiv IDs are verified through DataCite
30
+ (`10.48550/arXiv.<id>`); the run still reports arXiv as unavailable.
31
+ - Semantic Scholar as an optional rescue source, used only when `S2_API_KEY` is set: it is asked
32
+ about references no other source found, stays below the keyed limit of 1 request/s, backs off
33
+ exponentially on HTTP 429, and its outages never block a verdict. Its answers are cached
34
+ locally but never exported (licence).
35
+ - PubMed (NCBI E-utilities) verifies PMIDs: its record anchors the entry, a PMID it does not
36
+ know is REF002, and articles it marks as retracted get REF004. `doctor` checks it too.
37
+ - PMCIDs are verified too: PubMed Central gives their PMID, whose PubMed record anchors the
38
+ entry; a PMCID it does not know is REF002.
39
+ - Evaluation harness for the HALLMARK benchmark (`evals/run_hallmark.py`): flag / clean / abstain
40
+ outcomes, fabrication-only and any-issue modes, precision, conservative recall, false-positive
41
+ rate and coverage, broken down by hallucination type.
42
+ - `doctor` checks each source with one uncached request and reports `ok`, `unavailable` (with the
43
+ reason: rate limit, bot wall, timeout ...) or `skipped`; `--offline` skips the check.
44
+ - MCP server (`paper-preflight mcp`, needs the `mcp` extra): read-only `preflight_check` with
45
+ paged findings and `preflight_explain`; paths are confined to the workspace root
46
+ (`docs/mcp.md`).
47
+ - Claude Code plugin and marketplace (`plugins/paper-preflight`): the MCP server plus a
48
+ `paper-preflight` skill that runs the check before a paper is called finished.
49
+ - pre-commit hooks (`docs/pre-commit.md`): `paper-preflight-offline` (seconds, cached verdicts
50
+ only) and `paper-preflight` (full online verification).
51
+ - `paper-preflight explain [RULE]`: what a rule detects, its severity, its message and whether a
52
+ fix is safe; without an argument it lists every rule.
53
+ - CFG001: a `% preflight: ignore[...]` comment that silenced nothing is reported (info), among
54
+ the rules that ran on its entry; unknown rule names always are. Documented in the README.
55
+ - First full HALLMARK dev_public results (`evals/results/hallmark-dev_public.md`), with a second
56
+ summary that leaves out labels checked by hand and found wrong (`evals/hallmark_disputed.toml`).
57
+ - `bib fetch <DOI|arXiv ID>` or `bib fetch --title ...`: a BibTeX entry built from the registry
58
+ record (published versions of preprints keep their eprint; retracted works warn; ambiguous
59
+ titles list candidates; `--format json` for agents).
60
+ - MCP tool `preflight_bib_lookup`: `bib fetch` for agents.
61
+ - `bib fix`: edits the .bib files from the verified records, as a diff or with `--apply`;
62
+ `--level safe` (identifier formatting, missing DOIs) or `unsafe` (also authors, title, year,
63
+ venue, wrong identifiers). Only the affected fields change. REF016 offers a missing DOI.
64
+ - GitHub Action (`action.yml`): runs the check, writes the job summary and a SARIF report,
65
+ caches answers per bibliography (`docs/github-action.md`).
66
+ - Identifier lookups (doi.org, Crossref, DataCite, OpenAlex, arXiv, and dblp's published-version
67
+ links) are cached per identifier, so adding an entry no longer makes its batch companions
68
+ unverifiable in `--offline` runs, nor hides their published versions (REF015).
69
+ - REF014 also reports an invented venue on a paper whose venue is known: an unrecognised name
70
+ that shares no word or abbreviation with the recorded venue (abbreviations stay unknown).
71
+ - REF012 also reports a title that is close to the record's but has other words ("towards" for
72
+ "for", "Hidden" for "Latent") and names them; spelling, hyphenation, "&", math and
73
+ "RETRACTED:" notices do not count, nor do preprints whose earlier titles are unknown.
74
+ - REF011 also reports an author whose surname is right but whose given name belongs to someone
75
+ else ("Aviral Sharma" for Archit Sharma). Initials, short forms, middle names, hyphenation,
76
+ transcriptions and common nicknames (Bill, Misha) agree.
77
+ - More venues are recognised for REF014: AISTATS, UAI, COLT, CoRL, TMLR, IJCV, WWW, WSDM, CIKM,
78
+ ICASSP, Interspeech, MICCAI, ICRA, IROS, WACV and BMVC. URLs in a venue field are ignored.
79
+ - An unrecognised venue is also reported when it names something the recorded venue does not
80
+ ("International Conference on Quantum Machine Learning" for ICML). Abbreviations, ordinals,
81
+ series and publishers (PMLR, LNCS, OpenReview) never count, only booktitle and journal are
82
+ judged, and a workshop must share no word at all with the recorded venue.
83
+ - The same recognised venue now counts as evidence when binding a search result: a four- or
84
+ five-word title at the same venue in the same year names one work (wrong authors become
85
+ REF010 instead of "cannot determine"), and a year more than three years off is no reprint
86
+ when the venue is the same (REF013).
87
+ - A search result by the same people at the same venue in the same year binds when its title
88
+ is one or two words off, even below the usual similarity threshold; REF012 names the words.
89
+
90
+ [Unreleased]: https://github.com/amos689/paper-preflight/compare/v0.1.0...HEAD
91
+ [0.1.0]: https://github.com/amos689/paper-preflight/releases/tag/v0.1.0
@@ -0,0 +1,14 @@
1
+ # Code of conduct
2
+
3
+ This project follows the
4
+ [Contributor Covenant, version 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/).
5
+
6
+ In short: be respectful and constructive, assume good faith, and focus on the work. Harassment,
7
+ personal attacks and discriminatory language are not tolerated.
8
+
9
+ Because this tool deals with research integrity, one extra rule applies: **do not use issues,
10
+ discussions or pull requests to accuse named authors of misconduct.** Report tool behaviour,
11
+ not people.
12
+
13
+ Report unacceptable behaviour privately to the maintainers via GitHub's private reporting
14
+ features. Maintainers will review reports promptly and confidentially.
@@ -0,0 +1,42 @@
1
+ # Contributing to paper-preflight
2
+
3
+ Thanks for your interest! The project is pre-alpha; the architecture is still settling, so
4
+ please open an issue before starting larger changes.
5
+
6
+ ## Development setup
7
+
8
+ ```bash
9
+ # requires uv (https://docs.astral.sh/uv/)
10
+ uv sync
11
+ uv run pytest
12
+ uv run ruff check && uv run ruff format --check
13
+ uv run mypy
14
+ uv run pre-commit install
15
+ ```
16
+
17
+ ## Ground rules
18
+
19
+ 1. **No LLM in the verdict path.** Verdicts must be reproducible from recorded source
20
+ responses. No bibliographic field may be generated by a language model.
21
+ 2. **Abstain rather than guess.** If a source is unavailable (rate limit, bot challenge,
22
+ timeout, HTML instead of JSON), the affected references become "cannot determine",
23
+ never "not found".
24
+ 3. **Every network call goes through a source adapter** with rate limiting and caching.
25
+ Never scrape sites that forbid automated access (Google Scholar, CNKI/Wanfang/VIP search
26
+ pages, paywalled publisher pages) and never try to bypass bot challenges.
27
+ 4. **Licenses.** Runtime dependencies must be MIT/BSD/Apache-2.0/ISC/MPL-2.0/PSF licensed.
28
+ Adapted code must be permissively licensed and recorded in `THIRD_PARTY_NOTICES.md`.
29
+ 5. **Test fixtures.** Recorded API responses may only come from sources whose data can be
30
+ redistributed (Crossref without abstracts, OpenAlex, DataCite, arXiv metadata, dblp).
31
+ Never commit Semantic Scholar responses or full texts.
32
+ 6. **Bilingual messages.** User-visible strings need English and Simplified Chinese versions.
33
+ 7. **Fabricated test data uses fictional author names**, never real people.
34
+
35
+ ## Reporting false positives
36
+
37
+ False positives are the bugs we care about most. Please use the "False positive" issue
38
+ template and include the BibTeX entry and the output of `paper-preflight explain <finding-id>`.
39
+
40
+ ## Commit messages
41
+
42
+ Use [Conventional Commits](https://www.conventionalcommits.org/) (`feat:`, `fix:`, `docs:`, …).
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 paper-preflight contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,341 @@
1
+ Metadata-Version: 2.5
2
+ Name: paper-preflight
3
+ Version: 0.1.0
4
+ Summary: Pre-submission integrity gate for LaTeX papers: every reference verified against real scholarly records. No LLM guessing, no false accusations.
5
+ Project-URL: Homepage, https://github.com/amos689/paper-preflight
6
+ Project-URL: Issues, https://github.com/amos689/paper-preflight/issues
7
+ Project-URL: Changelog, https://github.com/amos689/paper-preflight/blob/main/CHANGELOG.md
8
+ Author: paper-preflight contributors
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ License-File: THIRD_PARTY_NOTICES.md
12
+ Keywords: academic-writing,agent-skills,bibtex,citations,hallucinated-citations,latex,mcp,references,research-integrity
13
+ Classifier: Development Status :: 2 - Pre-Alpha
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
23
+ Classifier: Topic :: Scientific/Engineering
24
+ Classifier: Topic :: Text Processing :: Markup :: LaTeX
25
+ Classifier: Typing :: Typed
26
+ Requires-Python: >=3.11
27
+ Requires-Dist: bibtexparser<3,>=2.0
28
+ Requires-Dist: httpx<1,>=0.28
29
+ Requires-Dist: platformdirs>=4
30
+ Requires-Dist: pydantic<3,>=2.7
31
+ Requires-Dist: pylatexenc<3,>=2.10
32
+ Requires-Dist: rapidfuzz<4,>=3.9
33
+ Requires-Dist: rich>=13
34
+ Requires-Dist: typer>=0.12
35
+ Provides-Extra: mcp
36
+ Requires-Dist: fastmcp<4.1,>=4.0; extra == 'mcp'
37
+ Description-Content-Type: text/markdown
38
+
39
+ # paper-preflight
40
+
41
+ <!-- mcp-name: io.github.amos689/paper-preflight -->
42
+
43
+ **English** · [简体中文](https://github.com/amos689/paper-preflight/blob/main/README.zh-CN.md)
44
+
45
+ [![CI](https://github.com/amos689/paper-preflight/actions/workflows/ci.yml/badge.svg)](https://github.com/amos689/paper-preflight/actions/workflows/ci.yml)
46
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/amos689/paper-preflight/blob/main/LICENSE)
47
+ ![Python 3.11–3.14](https://img.shields.io/badge/python-3.11%E2%80%933.14-blue.svg)
48
+
49
+ **Check every reference of a LaTeX paper against real scholarly records before you submit.
50
+ No LLM guessing, no false accusations.**
51
+
52
+ Language models invent references, and copy-pasted BibTeX carries wrong years, wrong authors
53
+ and dead DOIs. paper-preflight reads your `.tex` and `.bib` files and asks Crossref, dblp,
54
+ arXiv, DataCite, PubMed and OpenAlex (and Semantic Scholar, if you have a key) about every cited
55
+ work:
56
+
57
+ - Does it exist?
58
+ - Does it match what you wrote?
59
+ - Has it been retracted?
60
+ - Has the preprint you cite been published since?
61
+
62
+ When it cannot tell, it says so instead of guessing.
63
+
64
+ > **Status: v0.1, an early release.** False positives are the bugs we most want to hear
65
+ > about: please [open an issue](https://github.com/amos689/paper-preflight/issues).
66
+
67
+ The repository's [demo paper](https://github.com/amos689/paper-preflight/blob/main/examples/demo-paper) cites eleven works, several of them wrong on
68
+ purpose. A real run, against the live sources:
69
+
70
+ ```text
71
+ $ paper-preflight check examples/demo-paper
72
+ paper-preflight 0.0.1.dev0 · main.tex · 12 entries, 12 cited keys
73
+
74
+ error CIT001 main.tex:31
75
+ Citation key 'nonexistent2023' is not defined in any bibliography file (1 use(s)).
76
+ error REF001 refs.bib:43
77
+ The doi of 'devlin2019bert' (10.1109/cvpr.2016.90) resolves to a different work in Crossref: "Deep Residual Learning for Image Recognition" (He et al., 2016).
78
+ error REF003 refs.bib:66
79
+ 'lindqvist2024quantum' was not found in Crossref, dblp and Semantic Scholar, and every source responded. Check that the work exists and that its title is correct.
80
+ error REF004 refs.bib:73
81
+ 'wakefield1998ileal' has been retracted (reported by Crossref, OpenAlex). Cite it only if the text discusses the retraction.
82
+ error CIT002 refs.bib:127
83
+ Entry key 'kingma2015adam' is already defined at line 47; BibTeX ignores this one.
84
+ warning REF015 refs.bib:31
85
+ 'he2015residual' cites a preprint that has been published in CVPR (2016), DOI 10.1109/cvpr.2016.90. Cite the published version and keep the eprint field.
86
+ warning CIT004 refs.bib:37
87
+ Entries 'devlin2019bert' and 'he2016deep' look like the same work (same DOI).
88
+ warning REF013 refs.bib:51
89
+ 'kingma2015adam' gives the year 2016, but dblp records 2015.
90
+ warning REF017 refs.bib:111
91
+ The doi of 'tacl2019example' contains LaTeX escapes: '10.1162/tacl\_a\_00276'. Write it as: 10.1162/tacl_a_00276
92
+ info REF005 refs.bib:73
93
+ 'wakefield1998ileal' has a published correction (reported by Crossref).
94
+ info REF090 refs.bib:86
95
+ 'goodfellow2016deep' could not be verified: grey literature without an identifier (book, report, software, web page).
96
+ info REF090 refs.bib:94
97
+ 'zhou2016ml' could not be verified: non-Latin titles are not supported yet; grey literature without an identifier (book, report, software, web page).
98
+ info CIT003 refs.bib:115
99
+ Entry 'lecun1998gradient' is never cited.
100
+
101
+ References: 6 verified · 1 metadata mismatch · 1 identifier conflict · 1 not found · 2 cannot determine
102
+ 5 error(s) · 4 warning(s) · 4 info
103
+ ```
104
+
105
+ Each finding is backed by a record (or by every source answering "no"). The correct NeurIPS
106
+ paper is verified through dblp even though Crossref only holds fake copies of it, and the two
107
+ books without identifiers are reported as "cannot determine" instead of "not found".
108
+
109
+ ## What it catches
110
+
111
+ | Rule | Finding |
112
+ |---|---|
113
+ | REF001 | The DOI or arXiv ID points to a different paper |
114
+ | REF002 | The DOI or arXiv ID does not exist |
115
+ | REF003 | The work was not found in any source, and every source answered |
116
+ | REF004 · REF005 | The work was retracted, or has an expression of concern or a correction |
117
+ | REF010–REF014 | Authors, title, year or venue differ from the real record |
118
+ | REF015 | A cited preprint has been formally published |
119
+ | REF016 | The registry has a DOI the entry lacks (offered as a safe fix) |
120
+ | REF017 | An identifier is written so that links break (`10.1162/tacl\_a\_00276`, `…v1`) |
121
+ | CIT001–CIT008 | Undefined, duplicate, unused or near-duplicate citation keys; broken `.bib` syntax |
122
+ | REF090 | Cannot determine, always with the reason (source unavailable, grey literature, …) |
123
+
124
+ `paper-preflight explain REF003` describes any rule.
125
+
126
+ ## How accurate is it?
127
+
128
+ paper-preflight is measured on [HALLMARK](https://github.com/rpatrik96/hallmark), a public
129
+ benchmark of real and hallucinated BibTeX entries, against the live sources.
130
+
131
+ | Split | Mode | Precision | Recall | False-positive rate | Coverage |
132
+ |---|---|---|---|---|---|
133
+ | `test_public`: 831 entries, never used during development | Any issue | 97.9% | 88.4% | 2.6% | 96.7% |
134
+ | | Fabrication | 99.0% | 48.6% | 0.6% | 96.7% |
135
+ | `dev_public`: 1,119 entries, used during development | Any issue | 97.6% | 90.5% | 2.1% | 98.3% |
136
+ | | Fabrication | 98.1% | 52.5% | 1.0% | 98.3% |
137
+
138
+ HALLMARK v1.2.3, every entry of both public splits, run on 2026-10-03. *Fabrication* counts a
139
+ wrong identifier, a work not found and no author in common; *any issue* also counts wrong
140
+ authors, title, year or venue.
141
+
142
+ - **The held-out split confirms the development numbers:** the same precision and two points
143
+ less recall on entries no rule was ever tuned on.
144
+ - **Every flag on a `dev_public` entry labelled VALID was checked by hand.** The 11 that remain are not
145
+ correct citations: DOIs that belong to other papers, author lists naming people who did not
146
+ write the paper, a shifted year and a truncated title.
147
+ - **Without them, both modes reach 100% precision and 0% false positives.** The list, each item
148
+ with a reason one lookup confirms, is in
149
+ [`evals/hallmark_disputed.toml`](https://github.com/amos689/paper-preflight/blob/main/evals/hallmark_disputed.toml).
150
+ - **What is still missed:** invented venues on papers known only as preprints (an arXiv record
151
+ cannot contradict a venue) and author lists that merely leave people out. See
152
+ [`evals/results/`](https://github.com/amos689/paper-preflight/blob/main/evals/results/) for every hallucination type.
153
+
154
+ Precision comes first: a reference is called fabricated only on positive evidence, and an
155
+ unanswered or ambiguous lookup is reported as "cannot determine", never as "not found". The
156
+ evaluation harness and every run's summary are in [`evals/`](https://github.com/amos689/paper-preflight/blob/main/evals/README.md).
157
+
158
+ ## Quick start
159
+
160
+ With [uv](https://docs.astral.sh/uv/) nothing needs installing (or `pip install paper-preflight`):
161
+
162
+ ```bash
163
+ uvx paper-preflight check path/to/paper
164
+ ```
165
+
166
+ `path/to/paper` is the project directory, its main `.tex` file, or a single `.bib` file.
167
+
168
+ | Option | Effect |
169
+ |---|---|
170
+ | `--format json` / `--format sarif` | Machine-readable output (SARIF works with GitHub code scanning) |
171
+ | `--offline` | Never touch the network; use only answers already in the local cache |
172
+ | `--refresh` | Ask every source again instead of using cached answers (after a correction, say) |
173
+ | `--fail-on warning` | Make warnings fail the run too (the default is errors) |
174
+ | `--lang zh` | Chinese messages (also chosen automatically from your locale) |
175
+
176
+ Exit codes:
177
+
178
+ | Code | Meaning |
179
+ |---|---|
180
+ | 0 | Nothing at or above `--fail-on` was found |
181
+ | 1 | Blocking findings |
182
+ | 2 | No blocking findings, but a source was unavailable, so the paper cannot be called clean yet |
183
+ | 3 | Usage error |
184
+
185
+ ## Fetch verified BibTeX
186
+
187
+ Instead of writing an entry from memory, ask for it by DOI, arXiv ID or title. Every field
188
+ comes from the registry record, which a comment above the entry names:
189
+
190
+ ```bash
191
+ paper-preflight bib fetch 1810.04805
192
+ ```
193
+
194
+ ```bibtex
195
+ % Verified with paper-preflight against dblp (conf/naacl/DevlinCLT19), 2026-10-03
196
+ @inproceedings{devlin2019bert,
197
+ title = {{BERT:} Pre-training of Deep Bidirectional Transformers for Language Understanding},
198
+ author = {Devlin, Jacob and Chang, Ming-Wei and Lee, Kenton and Toutanova, Kristina},
199
+ booktitle = {NAACL-HLT (1)},
200
+ year = {2019},
201
+ doi = {10.18653/v1/n19-1423},
202
+ eprint = {1810.04805},
203
+ archivePrefix = {arXiv},
204
+ }
205
+ ```
206
+
207
+ - **Preprints:** an arXiv preprint that has been published comes back as the published version,
208
+ with its `eprint` kept (`--prefer preprint` for the preprint itself).
209
+ - **Titles:** `--title` (with `--author`/`--year` if needed) lists the candidates instead of
210
+ choosing when several works match.
211
+ - **Retractions:** a retracted work comes with a warning.
212
+ - **Agents:** `--format json` is for scripts and agents.
213
+
214
+ ## Fix the bibliography
215
+
216
+ `bib fix` turns findings into edits of your `.bib` files, taken from the verified records. It
217
+ prints a diff and changes nothing until you add `--apply`:
218
+
219
+ ```bash
220
+ paper-preflight bib fix path/to/paper --level unsafe
221
+ ```
222
+
223
+ ```diff
224
+ --- a/refs.bib
225
+ +++ b/refs.bib
226
+ @@ -48,7 +47,7 @@
227
+ title = {Adam: A Method for Stochastic Optimization},
228
+ author = {Kingma, Diederik P. and Ba, Jimmy},
229
+ booktitle = {International Conference on Learning Representations (ICLR)},
230
+ - year = {2016},
231
+ + year = {2015},
232
+ }
233
+ ```
234
+
235
+ - `--level safe` (the default) only fixes what cannot change which work is cited: identifiers
236
+ written so that links break, and DOIs the registry has but the entry lacks.
237
+ - `--level unsafe` also rewrites authors, title, year and venue from the record, and removes
238
+ identifiers that point to another work. Review the diff first.
239
+ - Only the affected fields change; comments, formatting, line endings and encoding are kept.
240
+ A reference nobody could find is never "fixed": only you can say what was meant.
241
+
242
+ ## Silence a finding you have checked
243
+
244
+ A comment directly above an entry silences rules for that entry, with an optional reason:
245
+
246
+ ```bibtex
247
+ % preflight: ignore[REF003] reason="internal technical report, not indexed anywhere"
248
+ @techreport{lab2024internal,
249
+ ...
250
+ }
251
+ ```
252
+
253
+ The verdict stays in the JSON report; only the finding is dropped. A suppression that silenced
254
+ nothing is reported as CFG001 (info), so stale comments do not pile up. Reference rules are only
255
+ judged after a complete online run, since offline answers and outages may leave them unrun.
256
+
257
+ ## Use it from your coding agent
258
+
259
+ **Claude Code** — install the plugin. It bundles an MCP server and a skill that makes Claude
260
+ check the references before calling a paper finished, fix only what is proven wrong, and never
261
+ invent a reference.
262
+
263
+ ```bash
264
+ claude plugin marketplace add amos689/paper-preflight
265
+ ```
266
+
267
+ ```bash
268
+ claude plugin install paper-preflight@paper-preflight
269
+ ```
270
+
271
+ **Codex, Cursor, VS Code and other MCP clients** — run `paper-preflight mcp`. The tools are
272
+ read-only and confined to your workspace; see [docs/mcp.md](https://github.com/amos689/paper-preflight/blob/main/docs/mcp.md).
273
+
274
+ **pre-commit** — check citation keys and cached verdicts on every commit in seconds; see
275
+ [docs/pre-commit.md](https://github.com/amos689/paper-preflight/blob/main/docs/pre-commit.md).
276
+
277
+ **GitHub Actions** — `uses: amos689/paper-preflight@main` checks the paper on every push, with
278
+ the report in the job summary and optional code-scanning alerts; see
279
+ [docs/github-action.md](https://github.com/amos689/paper-preflight/blob/main/docs/github-action.md).
280
+
281
+ ## Better results with free credentials
282
+
283
+ paper-preflight works without any account. These optional environment variables make it faster
284
+ and more complete; their values are never printed or logged.
285
+
286
+ | Variable | Effect |
287
+ |---|---|
288
+ | `PAPER_PREFLIGHT_EMAIL` | Crossref's polite pool: faster, more reliable lookups |
289
+ | `OPENALEX_API_KEY` | A larger OpenAlex budget for retraction checks |
290
+ | `S2_API_KEY` | Semantic Scholar as a rescue source for references nobody else found |
291
+
292
+ `paper-preflight doctor` shows which are set and whether each source answers right now.
293
+
294
+ ## How it works
295
+
296
+ 1. **Source-first.** It reads the LaTeX project as LaTeX sees it: comments, `\iffalse` blocks and
297
+ `\includeonly` are respected, `.aux` files are used when they are fresh, and the first
298
+ definition of a duplicated key wins, as in BibTeX.
299
+ 2. **Identifier-first routing.** DOIs go to their registration agency (doi.org tells which:
300
+ Crossref, DataCite, …). arXiv IDs go to arXiv, with DataCite as a fallback, and PMIDs and
301
+ PMCIDs to PubMed (which also marks retracted articles). Entries without identifiers are searched by
302
+ title in dblp and Crossref.
303
+ 3. **Field-by-field matching with guards.** It compares titles (including earlier arXiv version
304
+ titles), authors (tolerating transcriptions such as Reiß/Reis), year and venue. A search
305
+ result is used only when enough of these agree and no other work fits as well; known fake
306
+ DOI copies are skipped.
307
+ 4. **One verdict per reference:** verified, metadata mismatch, identifier conflict, not found,
308
+ or cannot determine with a reason. "Not found" needs every required source to answer "no".
309
+ 5. **No LLM anywhere in the verdict.** Answers are cached locally (SQLite), so re-runs are fast
310
+ and `--offline` works.
311
+
312
+ ## Design principles
313
+
314
+ - **Positive confirmation or abstain.** Rate limits, outages and unindexed works lead to "cannot
315
+ determine", never to "not found".
316
+ - **Neutral wording.** Findings state observations ("not found in Crossref, dblp and Semantic
317
+ Scholar, and every source responded"), never accusations.
318
+ - **Local-first, no telemetry.** Only the metadata of the cited works (DOIs, titles, authors) is
319
+ sent to the public scholarly APIs above. Your manuscript never leaves your machine.
320
+
321
+ ## What it will never do
322
+
323
+ Help evade plagiarism or AI-text detection, scrape paywalled or bot-protected sites, recommend
324
+ or "complete" references from memory, or name and shame authors.
325
+
326
+ ## Roadmap
327
+
328
+ - The first PyPI release (v0.1)
329
+ - Chinese-language references (v0.2)
330
+
331
+ Progress is tracked in [docs/PROGRESS.md](https://github.com/amos689/paper-preflight/blob/main/docs/PROGRESS.md) (in Chinese) and the
332
+ [changelog](https://github.com/amos689/paper-preflight/blob/main/CHANGELOG.md).
333
+
334
+ ## Contributing
335
+
336
+ Bug reports with a reproducible `.bib` entry are the most valuable contribution, especially
337
+ false positives. See [CONTRIBUTING.md](https://github.com/amos689/paper-preflight/blob/main/CONTRIBUTING.md).
338
+
339
+ ## License
340
+
341
+ [MIT](https://github.com/amos689/paper-preflight/blob/main/LICENSE). See [THIRD_PARTY_NOTICES.md](https://github.com/amos689/paper-preflight/blob/main/THIRD_PARTY_NOTICES.md) for adapted code.