Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions library/other/retraction-checker/.golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
linters:
enable:
- errorlint
- govet
- ineffassign
- staticcheck
- unused
- bodyclose
- noctx
- rowserrcheck
- sqlclosecheck

formatters:
enable:
- gofmt
- goimports
51 changes: 51 additions & 0 deletions library/other/retraction-checker/.goreleaser.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
version: 2
project_name: retraction-checker-pp-cli
changelog:
disable: true
builds:
- id: retraction-checker-pp-cli
main: ./cmd/retraction-checker-pp-cli
binary: retraction-checker-pp-cli
env:
- CGO_ENABLED=0
ldflags:
- -s -w -X github.com/mvanhorn/printing-press-library/library/other/retraction-checker/internal/cli.version={{ .Version }}
targets:
- darwin_amd64
- darwin_arm64
- linux_amd64
- linux_arm64
- windows_amd64
- windows_arm64
- id: retraction-checker-pp-mcp
main: ./cmd/retraction-checker-pp-mcp
binary: retraction-checker-pp-mcp
env:
- CGO_ENABLED=0
ldflags:
- -s -w -X main.version={{ .Version }}
targets:
- darwin_amd64
- darwin_arm64
- linux_amd64
- linux_arm64
- windows_amd64
- windows_arm64
archives:
- formats: [tar.gz]
name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
format_overrides:
- goos: windows
formats: [zip]
checksum:
name_template: checksums.txt
brews:
- name: retraction-checker-pp-cli
repository:
owner: laci141
name: homebrew-tap
homepage: "https://github.com/mvanhorn/printing-press-library"
description: "Check whether a paper is retracted, why, and what the current research says now — keyless, over Crossref and OpenAlex."
install: |
bin.install "retraction-checker-pp-cli"
bin.install "retraction-checker-pp-mcp"
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Retraction Checker — Shipcheck Proof

## Shipcheck umbrella: PASS (7/7 legs)
| Leg | Result |
|-----|--------|
| verify | PASS |
| validate-narrative | PASS |
| dogfood | PASS (4/4 novel features built) |
| workflow-verify | PASS |
| apify-audit | PASS |
| verify-skill | PASS |
| scorecard | PASS — 87/100, Grade A |

## Live behavioral verification (keyless, real APIs)
| Command | Test | Result |
|---------|------|--------|
| check | DOI 10.1016/j.micpro.2020.103768 (retracted) | RETRACTED, type=retraction, date=2021-03-01, source=publisher, notice URL — correct |
| check | DOI 10.1038/nature12373 (clean) | not retracted — correct |
| check | PMID:9500320 (Wakefield, retracted) | resolved PMID→DOI via NCBI esummary, RETRACTED via title-prefix — correct |
| scan | .txt with #comment + blank lines + 3 DOIs | 3 parsed, 1 retracted flagged, 0 errors — correct |
| watch | "crispr" first run then second run | baseline established (10 notices), second run 0 new — correct diff behavior |
| superseded | 10.1016/j.micpro.2020.103768 | Crossref lookup OK; OpenAlex leg blocked (see baseline) |

## Exit codes
- check no-arg → 2 (usage); scan missing-file → 1; happy paths → 0. Correct.

## Known external baseline (NOT a CLI bug)
OpenAlex is currently returning HTTP 503 for all anonymous search
("Anonymous search is temporarily rate-limited due to heavy load"). A raw curl
to the identical, well-formed URL the CLI builds also returns 503, confirming
the outage is upstream and global, not a request-construction bug. The
`superseded` command:
- builds a verified-correct OpenAlex request (search + sort=cited_by_count:desc + from_publication_date filter),
- retries 503/429 up to 3x with linear backoff,
- surfaces a clear, actionable error rather than phantom-empty results.
Re-run `superseded` when OpenAlex recovers to confirm the happy path.

## Notable fix during dogfood
- PMID→DOI resolution initially used the NCBI PMC ID Converter, which only
covers the PMC open-access subset (Wakefield PMID returned no DOI). Switched
to NCBI E-utilities `esummary` (covers all of PubMed). Verified end-to-end.

## Verdict: ship (pending OpenAlex recovery re-test of superseded happy path)
Not yet promoted to library or published — awaiting user confirmation.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"schema_version": 1,
"api_name": "retraction-checker",
"run_id": "20260702-090842-5bac53b7",
"status": "pass",
"level": "full",
"matrix_size": 46,
"tests_passed": 46,
"tests_skipped": 35,
"auth_context": {
"type": "none"
}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
{
"api_name": "retraction-checker",
"novelty_score": 8,
"alternatives": [
{
"name": "scientific-consensus-pp-cli",
"url": "https://github.com/mvanhorn/printing-press-library/tree/main/library/other/scientific-consensus",
"language": "Go",
"install_method": "",
"stars": 0,
"last_updated": "",
"command_count": 20,
"has_json_output": false,
"has_auth_support": false
}
],
"gaps": [],
"patterns": [],
"recommendation": "proceed",
"researched_at": "2026-07-02T09:10:00Z",
"novel_features": [
{
"name": "Retraction check",
"command": "check",
"description": "Tell whether a paper (by DOI or PMID) has been retracted, when, why, and where the notice is.",
"rationale": "Crossref embeds Retraction Watch update records; we parse update-to/update-by plus the RETRACTED title signal into one structured verdict no raw API call returns.",
"example": "retraction-checker-pp-cli check 10.1016/j.micpro.2020.103768 --json",
"why_it_matters": "Agents citing a paper should verify it is not retracted before relying on it.",
"group": "Retraction intelligence"
},
{
"name": "Bibliography scan",
"command": "scan",
"description": "Batch-check a reading list or .bib file and flag every retracted entry.",
"rationale": "Reuses the batch-file line pattern (skip blank/# lines) and fans out DOI/PMID lookups against Crossref with a single command.",
"example": "retraction-checker-pp-cli scan refs.bib --json",
"why_it_matters": "Catches retracted citations across a whole manuscript or literature review at once.",
"group": "Retraction intelligence"
},
{
"name": "Superseding research",
"command": "superseded",
"description": "For a retracted or older paper, find related more-recent research on the same topic, ranked by citation count.",
"rationale": "Joins Crossref retraction/date context with OpenAlex citation-ranked related works published after the original — a cross-source view no single API provides.",
"example": "retraction-checker-pp-cli superseded 10.1016/j.micpro.2020.103768 --json",
"why_it_matters": "When a paper is retracted, the agent still needs the current best evidence on the topic.",
"group": "Retraction intelligence"
},
{
"name": "Retraction watch",
"command": "watch",
"description": "Monitor a topic or reading list for newly-announced retractions since the last run.",
"rationale": "Persists a baseline of seen retraction notices and diffs on each run, using the snapshot/first-run-baseline pattern.",
"example": "retraction-checker-pp-cli watch \"machine learning\" --json",
"why_it_matters": "Surfaces new retractions in a field or personal library without re-reading everything.",
"group": "Local state that compounds"
}
],
"novel_features_built": [
{
"name": "Retraction check",
"command": "check",
"description": "Tell whether a paper (by DOI or PMID) has been retracted, when, why, and where the notice is.",
"rationale": "Crossref embeds Retraction Watch update records; we parse update-to/update-by plus the RETRACTED title signal into one structured verdict no raw API call returns.",
"example": "retraction-checker-pp-cli check 10.1016/j.micpro.2020.103768 --json",
"why_it_matters": "Agents citing a paper should verify it is not retracted before relying on it.",
"group": "Retraction intelligence"
},
{
"name": "Bibliography scan",
"command": "scan",
"description": "Batch-check a reading list or .bib file and flag every retracted entry.",
"rationale": "Reuses the batch-file line pattern (skip blank/# lines) and fans out DOI/PMID lookups against Crossref with a single command.",
"example": "retraction-checker-pp-cli scan refs.bib --json",
"why_it_matters": "Catches retracted citations across a whole manuscript or literature review at once.",
"group": "Retraction intelligence"
},
{
"name": "Superseding research",
"command": "superseded",
"description": "For a retracted or older paper, find related more-recent research on the same topic, ranked by citation count.",
"rationale": "Joins Crossref retraction/date context with OpenAlex citation-ranked related works published after the original — a cross-source view no single API provides.",
"example": "retraction-checker-pp-cli superseded 10.1016/j.micpro.2020.103768 --json",
"why_it_matters": "When a paper is retracted, the agent still needs the current best evidence on the topic.",
"group": "Retraction intelligence"
},
{
"name": "Retraction watch",
"command": "watch",
"description": "Monitor a topic or reading list for newly-announced retractions since the last run.",
"rationale": "Persists a baseline of seen retraction notices and diffs on each run, using the snapshot/first-run-baseline pattern.",
"example": "retraction-checker-pp-cli watch \"machine learning\" --json",
"why_it_matters": "Surfaces new retractions in a field or personal library without re-reading everything.",
"group": "Local state that compounds"
}
],
"auth": {},
"narrative": {
"display_name": "Retraction Checker",
"headline": "Check whether a paper is retracted, why, and what the current research says now — keyless, over Crossref and OpenAlex.",
"value_prop": "Retraction Checker turns Crossref's embedded Retraction Watch data into a one-shot verdict: is this DOI or PMID retracted, when, why, and where is the notice. It batch-scans reading lists and .bib files, finds citation-ranked superseding research via OpenAlex, and watches a topic or library for newly-announced retractions. Fully keyless.",
"quickstart": [
{
"command": "retraction-checker-pp-cli doctor --dry-run",
"comment": "Confirm the CLI and Crossref reachability before checking papers"
},
{
"command": "retraction-checker-pp-cli check 10.1016/j.micpro.2020.103768 --json",
"comment": "Check a single DOI for retraction status"
},
{
"command": "retraction-checker-pp-cli scan refs.bib --json",
"comment": "Flag retracted entries across a bibliography"
}
],
"troubleshoots": [
{
"symptom": "Rate-limited by Crossref",
"fix": "Pass --mailto you@example.com to join the polite pool for better limits"
},
{
"symptom": "PMID not found",
"fix": "PMIDs are resolved to DOIs first; some records have no DOI and cannot be checked via Crossref"
}
],
"when_to_use": "Use this CLI when an agent or researcher needs to verify that a cited paper has not been retracted, audit a bibliography for retracted references, or find current research that supersedes a retracted study. It is the right choice for citation-integrity checks in literature reviews and RAG pipelines.",
"anti_triggers": [
"Do not use this CLI to fetch full-text papers or PDFs",
"Do not use it for general scholarly search unrelated to retraction — use scientific-consensus for consensus and evidence analytics"
],
"recipes": [
{
"title": "Check a DOI",
"command": "retraction-checker-pp-cli check 10.1016/j.micpro.2020.103768 --json",
"explanation": "Returns retraction status, date, reason source, and notice reference for one paper."
},
{
"title": "Audit a bibliography",
"command": "retraction-checker-pp-cli scan reading-list.txt --agent --select doi,retracted,reason",
"explanation": "Scans one DOI/PMID per line and returns only the key retraction fields for each entry."
},
{
"title": "Find superseding work",
"command": "retraction-checker-pp-cli superseded 10.1016/j.micpro.2020.103768 --json",
"explanation": "Lists more-recent related papers ranked by citations, published after the retracted paper."
},
{
"title": "Watch a field",
"command": "retraction-checker-pp-cli watch \"crispr\" --json",
"explanation": "Baselines retraction notices for a topic and reports new ones on later runs."
}
],
"trigger_phrases": [
"is this paper retracted",
"check retraction",
"check this DOI",
"scan my bibliography for retractions",
"what replaced this retracted paper",
"use retraction-checker",
"run retraction-checker"
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Retraction Checker — Absorb Manifest

Scope is deliberately capped by the user: exactly four commands in the first PR.
No competing keyless retraction CLI exists; the closest prior art is our own
scientific-consensus (OpenAlex analytics), which does not do retraction checking.

## Absorbed (foundation, generator-emitted)
| # | Feature | Best Source | Our Implementation | Added Value |
|---|---------|-------------|--------------------|-------------|
| 1 | Search/filter works | Crossref /works | (generated endpoint) works searchWorks | --json/--select/--csv, offline cache |
| 2 | Get work by DOI | Crossref /works/{doi} | (generated endpoint) works getWork | typed output, cache |
| 3 | Health check | framework | (behavior in retraction-checker-pp-cli doctor) | keyless reachability probe |
| 4 | Local sync/SQL/search | framework | (behavior in retraction-checker-pp-cli sync) | SQLite cache of checked works |

## Transcendence (the four shipping-scope commands)
| # | Feature | Command | Buildability | Why Only We Can Do This | Long Description |
|---|---------|---------|--------------|-------------------------|------------------|
| 1 | Retraction check | check | hand-code | Parses Crossref update-to/update-by + RETRACTED title into one verdict; resolves PMID→DOI first | Use to verify a single paper is not retracted before citing it. |
| 2 | Bibliography scan | scan | hand-code | Batch line/.bib parsing + fan-out retraction lookups with partial-failure accounting | Use to audit a whole reading list or manuscript for retracted citations. |
| 3 | Superseding research | superseded | hand-code | Cross-source join: Crossref date context + OpenAlex citation-ranked related works published after the original | Use to find current best evidence when a paper is retracted or outdated. AI summary deferred (keyless first PR). |
| 4 | Retraction watch | watch | hand-code | Snapshot baseline of seen retraction notices per topic/list, diff on later runs | Use to monitor a field or personal library for newly-announced retractions. |

Stubs: none. AI synthesis on `superseded` is deferred entirely (not shipped as a stub).
Hand-code count: 4 transcendence commands. Auto-emitted: 2 endpoint commands + framework.
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Retraction Checker CLI Brief

## API Identity
- Domain: scholarly metadata / research integrity
- Primary source: Crossref REST API (https://api.crossref.org) — free, keyless, polite pool via `mailto`
- Secondary source: OpenAlex (https://api.openalex.org) — free, keyless; citation-ranked related works
- Users: researchers, librarians, meta-scientists, and AI agents doing citation-integrity checks
- Data profile: 73,126+ retraction notices in Crossref (embedded Retraction Watch data); each work carries `update-to`/`update-by` records with `type: retraction`, date, and source

## Reachability Risk
- None. Live probe: `GET /works?filter=update-type:retraction&rows=1` → HTTP 200, 73,126 results.
- Single work: `GET /works/10.1016/j.micpro.2020.103768` → HTTP 200 with `update-to[].type=retraction` and title `RETRACTED:` prefix.

## Retraction detection signals (Crossref)
- `message.update-to[]` with `type` in {retraction, correction, withdrawal, expression_of_concern, removal} → this record is/points to a retraction notice.
- `message.update-by[]` → this work has been retracted by the listed notice(s).
- Title prefix `RETRACTED:` / `WITHDRAWN:` → corroborating signal.
- `filter=update-type:retraction` lists retraction notices; each item's `update-to[].DOI` is the retracted paper.

## Top Workflows
1. Check one DOI/PMID for retraction status, date, reason source, notice.
2. Batch-scan a reading list / .bib for retracted entries.
3. Find current superseding research for a retracted/older paper (OpenAlex, citation-ranked).
4. Watch a topic or reading list for newly-announced retractions.

## Data Layer
- Local SQLite cache of checked works (DOI → retraction verdict + fetched-at) via modernc.org/sqlite.
- Watch state files (baseline of seen retraction notices per topic/list) via os.UserConfigDir, snapshot/first-run/diff pattern.

## Source Priority
- Primary: crossref — internal OpenAPI spec authored from docs + live probe — auth: free
- Secondary: openalex — aggregator-pattern hand-built source client — auth: free
- Economics: both keyless; no paid tier. No inversion risk (Crossref leads all headline commands).

## User Vision
- Fully keyless by default; every command works with zero configuration.
- Exactly four commands in the first PR: check, scan, superseded, watch. Do NOT build more.
- Optional AI synthesis on `superseded` is DEFERRED (keyless-only first PR).
- Go-only, no subprocess. Follow scientific-consensus conventions (cobra rootFlags, printJSONFiltered, isTerminal, boundCtx, classifyAPIError, modernc.org/sqlite, internal/{cli,source,client,store,cliutil,mcp}).

## Product Thesis
- Name: Retraction Checker (retraction-checker-pp-cli)
- Why it should exist: no keyless CLI turns Crossref's embedded Retraction Watch data into a one-shot retraction verdict, batch bibliography audit, superseding-research finder, and retraction watch.

## Build Priorities
1. Crossref source client + DOI/PMID resolution + retraction verdict parser.
2. check + scan (Crossref-only, keyless).
3. superseded (Crossref date context + OpenAlex citation-ranked related works).
4. watch (snapshot/baseline/diff).
Loading
Loading