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.
- paper_preflight-0.1.0/.claude-plugin/marketplace.json +17 -0
- paper_preflight-0.1.0/.gitattributes +11 -0
- paper_preflight-0.1.0/.gitignore +30 -0
- paper_preflight-0.1.0/.pre-commit-config.yaml +19 -0
- paper_preflight-0.1.0/.pre-commit-hooks.yaml +18 -0
- paper_preflight-0.1.0/.python-version +1 -0
- paper_preflight-0.1.0/CHANGELOG.md +91 -0
- paper_preflight-0.1.0/CODE_OF_CONDUCT.md +14 -0
- paper_preflight-0.1.0/CONTRIBUTING.md +42 -0
- paper_preflight-0.1.0/LICENSE +21 -0
- paper_preflight-0.1.0/PKG-INFO +341 -0
- paper_preflight-0.1.0/README.md +303 -0
- paper_preflight-0.1.0/README.zh-CN.md +283 -0
- paper_preflight-0.1.0/SECURITY.md +18 -0
- paper_preflight-0.1.0/THIRD_PARTY_NOTICES.md +39 -0
- paper_preflight-0.1.0/action.yml +80 -0
- paper_preflight-0.1.0/docs/PROGRESS.md +148 -0
- paper_preflight-0.1.0/docs/adr/0000-template.md +16 -0
- paper_preflight-0.1.0/docs/adr/0001-source-first-input.md +28 -0
- paper_preflight-0.1.0/docs/adr/0002-verdicts-and-abstention.md +45 -0
- paper_preflight-0.1.0/docs/adr/0003-identifier-first-routing.md +101 -0
- paper_preflight-0.1.0/docs/adr/0004-no-llm-in-verdicts.md +25 -0
- paper_preflight-0.1.0/docs/adr/0005-http-adapters-and-cache.md +30 -0
- paper_preflight-0.1.0/docs/adr/0006-license-policy.md +28 -0
- paper_preflight-0.1.0/docs/adr/0007-sarif-canonical-output.md +23 -0
- paper_preflight-0.1.0/docs/adr/0008-python-and-tooling.md +23 -0
- paper_preflight-0.1.0/docs/adr/0009-distribution-matrix.md +29 -0
- paper_preflight-0.1.0/docs/adr/0010-parsing-stack.md +43 -0
- paper_preflight-0.1.0/docs/adr/README.md +19 -0
- paper_preflight-0.1.0/docs/github-action.md +55 -0
- paper_preflight-0.1.0/docs/mcp.md +92 -0
- paper_preflight-0.1.0/docs/pre-commit.md +31 -0
- paper_preflight-0.1.0/docs/releasing.md +58 -0
- paper_preflight-0.1.0/docs/spikes/S1-dblp-sparql.md +218 -0
- paper_preflight-0.1.0/docs/spikes/S2-crossref.md +165 -0
- paper_preflight-0.1.0/docs/spikes/S3-openalex.md +156 -0
- paper_preflight-0.1.0/docs/spikes/S4-arxiv-datacite-doiorg.md +164 -0
- paper_preflight-0.1.0/docs/spikes/S5-semantic-scholar.md +119 -0
- paper_preflight-0.1.0/docs/spikes/S8-datasets.md +312 -0
- paper_preflight-0.1.0/evals/README.md +66 -0
- paper_preflight-0.1.0/evals/datasets.lock +151 -0
- paper_preflight-0.1.0/evals/hallmark_disputed.toml +60 -0
- paper_preflight-0.1.0/evals/results/hallmark-dev_public.md +67 -0
- paper_preflight-0.1.0/evals/results/hallmark-test_public.md +58 -0
- paper_preflight-0.1.0/evals/run_hallmark.py +161 -0
- paper_preflight-0.1.0/examples/demo-paper/EXPECTED.md +29 -0
- paper_preflight-0.1.0/examples/demo-paper/main.tex +36 -0
- paper_preflight-0.1.0/examples/demo-paper/refs.bib +131 -0
- paper_preflight-0.1.0/glama.json +4 -0
- paper_preflight-0.1.0/plugins/paper-preflight/.claude-plugin/plugin.json +12 -0
- paper_preflight-0.1.0/plugins/paper-preflight/.mcp.json +15 -0
- paper_preflight-0.1.0/plugins/paper-preflight/skills/paper-preflight/SKILL.md +51 -0
- paper_preflight-0.1.0/pyproject.toml +119 -0
- paper_preflight-0.1.0/server.json +36 -0
- paper_preflight-0.1.0/src/paper_preflight/__init__.py +3 -0
- paper_preflight-0.1.0/src/paper_preflight/__main__.py +3 -0
- paper_preflight-0.1.0/src/paper_preflight/bib/__init__.py +1 -0
- paper_preflight-0.1.0/src/paper_preflight/bib/ids.py +163 -0
- paper_preflight-0.1.0/src/paper_preflight/bib/names.py +124 -0
- paper_preflight-0.1.0/src/paper_preflight/bib/normalize.py +38 -0
- paper_preflight-0.1.0/src/paper_preflight/bib/parse.py +278 -0
- paper_preflight-0.1.0/src/paper_preflight/bibtex.py +158 -0
- paper_preflight-0.1.0/src/paper_preflight/cache.py +200 -0
- paper_preflight-0.1.0/src/paper_preflight/check.py +236 -0
- paper_preflight-0.1.0/src/paper_preflight/cli.py +487 -0
- paper_preflight-0.1.0/src/paper_preflight/connectivity.py +106 -0
- paper_preflight-0.1.0/src/paper_preflight/data/__init__.py +1 -0
- paper_preflight-0.1.0/src/paper_preflight/data/suspicious_sources.toml +7 -0
- paper_preflight-0.1.0/src/paper_preflight/evaluation/__init__.py +1 -0
- paper_preflight-0.1.0/src/paper_preflight/evaluation/hallmark.py +264 -0
- paper_preflight-0.1.0/src/paper_preflight/fetch.py +154 -0
- paper_preflight-0.1.0/src/paper_preflight/findings.py +116 -0
- paper_preflight-0.1.0/src/paper_preflight/fixes.py +195 -0
- paper_preflight-0.1.0/src/paper_preflight/hygiene.py +245 -0
- paper_preflight-0.1.0/src/paper_preflight/identifier_lint.py +94 -0
- paper_preflight-0.1.0/src/paper_preflight/match.py +593 -0
- paper_preflight-0.1.0/src/paper_preflight/mcp_server.py +233 -0
- paper_preflight-0.1.0/src/paper_preflight/py.typed +0 -0
- paper_preflight-0.1.0/src/paper_preflight/report/__init__.py +1 -0
- paper_preflight-0.1.0/src/paper_preflight/report/jsonout.py +107 -0
- paper_preflight-0.1.0/src/paper_preflight/report/sarif.py +117 -0
- paper_preflight-0.1.0/src/paper_preflight/report/text.py +99 -0
- paper_preflight-0.1.0/src/paper_preflight/resolve.py +497 -0
- paper_preflight-0.1.0/src/paper_preflight/rules.py +296 -0
- paper_preflight-0.1.0/src/paper_preflight/sources/__init__.py +1 -0
- paper_preflight-0.1.0/src/paper_preflight/sources/arxiv.py +161 -0
- paper_preflight-0.1.0/src/paper_preflight/sources/base.py +400 -0
- paper_preflight-0.1.0/src/paper_preflight/sources/crossref.py +174 -0
- paper_preflight-0.1.0/src/paper_preflight/sources/datacite.py +93 -0
- paper_preflight-0.1.0/src/paper_preflight/sources/dblp.py +229 -0
- paper_preflight-0.1.0/src/paper_preflight/sources/doiorg.py +161 -0
- paper_preflight-0.1.0/src/paper_preflight/sources/openalex.py +117 -0
- paper_preflight-0.1.0/src/paper_preflight/sources/pubmed.py +157 -0
- paper_preflight-0.1.0/src/paper_preflight/sources/record.py +99 -0
- paper_preflight-0.1.0/src/paper_preflight/sources/semanticscholar.py +88 -0
- paper_preflight-0.1.0/src/paper_preflight/tex/__init__.py +1 -0
- paper_preflight-0.1.0/src/paper_preflight/tex/auxdata.py +103 -0
- paper_preflight-0.1.0/src/paper_preflight/tex/cites.py +229 -0
- paper_preflight-0.1.0/src/paper_preflight/tex/mask.py +114 -0
- paper_preflight-0.1.0/src/paper_preflight/tex/project.py +236 -0
- paper_preflight-0.1.0/src/paper_preflight/textio.py +86 -0
- paper_preflight-0.1.0/src/paper_preflight/verdict.py +786 -0
- paper_preflight-0.1.0/tests/__init__.py +1 -0
- paper_preflight-0.1.0/tests/conftest.py +47 -0
- paper_preflight-0.1.0/tests/fake_web.py +167 -0
- paper_preflight-0.1.0/tests/fixtures/schemas/sarif-schema-2.1.0.json +3389 -0
- paper_preflight-0.1.0/tests/fixtures/sources/README.md +11 -0
- paper_preflight-0.1.0/tests/fixtures/sources/arxiv/idlist_gelu_versions.xml +98 -0
- paper_preflight-0.1.0/tests/fixtures/sources/arxiv/idlist_multi.xml +223 -0
- paper_preflight-0.1.0/tests/fixtures/sources/arxiv/idlist_nonexistent.xml +10 -0
- paper_preflight-0.1.0/tests/fixtures/sources/arxiv/idlist_withdrawn_versions_and_jref.xml +63 -0
- paper_preflight-0.1.0/tests/fixtures/sources/arxiv/search_ti_phrase_t1.xml +147 -0
- paper_preflight-0.1.0/tests/fixtures/sources/arxiv/search_ti_t8.xml +10 -0
- paper_preflight-0.1.0/tests/fixtures/sources/crossref/batch_filter_doi.json +673 -0
- paper_preflight-0.1.0/tests/fixtures/sources/crossref/biblio_t1_withauthors.json +1234 -0
- paper_preflight-0.1.0/tests/fixtures/sources/crossref/biblio_t2.json +546 -0
- paper_preflight-0.1.0/tests/fixtures/sources/crossref/biblio_t8.json +409 -0
- paper_preflight-0.1.0/tests/fixtures/sources/crossref/work_65215_ysbyhc05.json +229 -0
- paper_preflight-0.1.0/tests/fixtures/sources/crossref/work_bert.json +162 -0
- paper_preflight-0.1.0/tests/fixtures/sources/crossref/work_cvpr.json +166 -0
- paper_preflight-0.1.0/tests/fixtures/sources/crossref/work_tacl.json +400 -0
- paper_preflight-0.1.0/tests/fixtures/sources/crossref/work_wakefield.json +336 -0
- paper_preflight-0.1.0/tests/fixtures/sources/datacite/dc_arxiv_attn.json +581 -0
- paper_preflight-0.1.0/tests/fixtures/sources/datacite/dc_arxiv_demo_batch.json +200 -0
- paper_preflight-0.1.0/tests/fixtures/sources/datacite/dc_arxiv_gelu.json +255 -0
- paper_preflight-0.1.0/tests/fixtures/sources/datacite/dc_multi_ids.json +38 -0
- paper_preflight-0.1.0/tests/fixtures/sources/datacite/dc_nonexistent.json +8 -0
- paper_preflight-0.1.0/tests/fixtures/sources/dblp/batch_doi_upper.json +134 -0
- paper_preflight-0.1.0/tests/fixtures/sources/dblp/full_records.json +1972 -0
- paper_preflight-0.1.0/tests/fixtures/sources/dblp/full_records_adam.json +103 -0
- paper_preflight-0.1.0/tests/fixtures/sources/dblp/gelu_by_doi.json +31 -0
- paper_preflight-0.1.0/tests/fixtures/sources/dblp/link_corr_to_conf.json +111 -0
- paper_preflight-0.1.0/tests/fixtures/sources/dblp/prefix_adam.json +26 -0
- paper_preflight-0.1.0/tests/fixtures/sources/dblp/prefix_t1.json +246 -0
- paper_preflight-0.1.0/tests/fixtures/sources/dblp/prefix_t8.json +15 -0
- paper_preflight-0.1.0/tests/fixtures/sources/dblp/sparql_dataset_meta.json +101 -0
- paper_preflight-0.1.0/tests/fixtures/sources/doiorg/cn_datacite_arxiv.json +57 -0
- paper_preflight-0.1.0/tests/fixtures/sources/doiorg/doira_multi.json +26 -0
- paper_preflight-0.1.0/tests/fixtures/sources/doiorg/hdl_cvpr.json +16 -0
- paper_preflight-0.1.0/tests/fixtures/sources/openalex/batch_or_doi.json +2070 -0
- paper_preflight-0.1.0/tests/fixtures/sources/openalex/title_search_t8.json +26 -0
- paper_preflight-0.1.0/tests/fixtures/sources/openalex/work_W2626778328_attention.json +1470 -0
- paper_preflight-0.1.0/tests/fixtures/sources/openalex/work_doi_cvpr.json +1196 -0
- paper_preflight-0.1.0/tests/fixtures/sources/openalex/work_doi_wakefield.json +1523 -0
- paper_preflight-0.1.0/tests/fixtures/sources/pubmed/esummary_pmc.json +39 -0
- paper_preflight-0.1.0/tests/fixtures/sources/pubmed/esummary_pubmed.json +342 -0
- paper_preflight-0.1.0/tests/test_bib_fetch.py +130 -0
- paper_preflight-0.1.0/tests/test_bib_fix.py +110 -0
- paper_preflight-0.1.0/tests/test_bib_ids.py +76 -0
- paper_preflight-0.1.0/tests/test_bib_parse.py +111 -0
- paper_preflight-0.1.0/tests/test_bibtex.py +130 -0
- paper_preflight-0.1.0/tests/test_cache.py +58 -0
- paper_preflight-0.1.0/tests/test_check_offline.py +188 -0
- paper_preflight-0.1.0/tests/test_check_online.py +196 -0
- paper_preflight-0.1.0/tests/test_cli.py +88 -0
- paper_preflight-0.1.0/tests/test_evaluation.py +122 -0
- paper_preflight-0.1.0/tests/test_identifier_lint.py +51 -0
- paper_preflight-0.1.0/tests/test_match.py +416 -0
- paper_preflight-0.1.0/tests/test_mcp_server.py +187 -0
- paper_preflight-0.1.0/tests/test_plugin_manifests.py +100 -0
- paper_preflight-0.1.0/tests/test_pre_commit_hooks.py +19 -0
- paper_preflight-0.1.0/tests/test_pubmed.py +102 -0
- paper_preflight-0.1.0/tests/test_resolve.py +171 -0
- paper_preflight-0.1.0/tests/test_sarif.py +67 -0
- paper_preflight-0.1.0/tests/test_semanticscholar.py +142 -0
- paper_preflight-0.1.0/tests/test_source_fetch.py +155 -0
- paper_preflight-0.1.0/tests/test_source_parsers.py +212 -0
- paper_preflight-0.1.0/tests/test_sources_base.py +302 -0
- paper_preflight-0.1.0/tests/test_tex_cites.py +92 -0
- paper_preflight-0.1.0/tests/test_tex_project.py +155 -0
- paper_preflight-0.1.0/tests/test_verdict.py +658 -0
- 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
|
+
[](https://github.com/amos689/paper-preflight/actions/workflows/ci.yml)
|
|
46
|
+
[](https://github.com/amos689/paper-preflight/blob/main/LICENSE)
|
|
47
|
+

|
|
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.
|