Skip to content

checktor

0.2.0Package record

Extra CRAN Submission Checks

0packages depend
1.2Kdownloads / year
95.3%test coverage
13/13flavors OK

Overview

About

Provides automated checks for common Comprehensive R Archive Network (CRAN) submission issues that are not caught by standard 'R CMD check'. Consolidates ad-hoc requirements that CRAN reviewers enforce but standard checks do not surface, helping R package maintainers identify and fix issues before submission to reduce rejection rates. Covers code-pattern issues, DESCRIPTION-field formatting, documentation problems, and general package structure concerns.

Changes in 0.2.0

Every check now carries a severity tier, so a clean bill of health means something

precise rather than merely quiet. Checks read your examples, vignettes and demos as

well as R/, which is where several of the most common rejections actually land.

New checks bring part of CRAN's incoming filter offline, covering the Date,

Encoding and Version fields, the structure of Authors@R, ORCID and ROR

identifiers, a detectCores() that can return NA, and a scan for a leaked

credential. Existing checks are sharper and quieter, every check is callable on its

own, findings can go straight to your build system, checktor runs from anywhere

inside a package tree, and a package can tune checktor through Config/checktor/*

fields in its own DESCRIPTION.

Breaking changes

  • checktor needs R 4.5.0 or later, where 0.1.0 asked only for R 3.5.0. R 4.5.0 added tools::check_package_urls(), which the new url_liveness check uses. An older installation stays on 0.1.0.
Show all changes in 0.2.0Hide the rest of the changes in 0.2.0
  • The individual checks are now lab_*(), so the doctor orders a panel of labs. diagnose_tf_usage() is lab_tf_usage(), and the name after lab_ is the check name tidy() reports and Config/checktor refers to, which several old names did not match. The five category functions such as diagnose_code_issues() keep their names, since they run a panel rather than one test. The names released in 0.1.0 were renamed outright rather than deprecated, so replace diagnose_ with lab_ in any call to diagnose_tf_usage(), diagnose_seed_setting(), diagnose_print_cat_usage(), diagnose_roxygen_usage(), diagnose_value_tags(), diagnose_example_structure(), diagnose_missing_examples(), diagnose_suggested_in_examples(), diagnose_package_size(), diagnose_urls(), diagnose_news_file() or diagnose_cran_comments_file(). diagnose_readme_relative_links() is now lab_readme_links(), after the readme_links check it runs. Check names themselves are unchanged, so code that picks rows of tidy() or issues() by check name keeps working.
  • Every check carries a severity tier, and checktor() gained a severity argument deciding which tiers the verdict is about. It defaults to policy and robustness.
  • A policy finding is a citable violation of CRAN Repository Policy or Writing R Extensions.
  • A robustness finding is a real defect that CRAN will still accept, such as a detectCores() that may return NA.
  • An opinion finding is a convention with no authority behind it.

Every check still runs and every finding is still reported with its tier. The tier

only decides what counts against a clean bill of health, so zero issues now means

your package is submission ready and nothing here will crash a user. checkup()

follows the same default, so a missing NEWS.md no longer fails a build. On a

checktor() result, metadata$total_issues, metadata$failed_checks,

n_issues(), n_failed_checks() and is_healthy() now count those tiers alone,

while issues() and failed_checks() still list every finding.

  • A check that does not run is reported as skipped rather than as passing, so a clean bill of health never includes a check that never happened. tidy() gained a skipped column and summary() a skipped count, the names are in metadata$skipped_checks, and the printed result and every health_report() format name the checks that sat out. Printing a check or a category shows a skipped check as skipped, summary() counts it only as skipped, and a skipped row in tidy() is never passed, so !passed & !skipped picks out the failures and the passed, failed and skipped counts of summary() add up to checks. passed() asks only whether a check failed, so it is TRUE for a skipped one (#15, thanks @TroyHernandez).
  • Every check is exported, so any check checktor() runs is one you can call yourself. The checks of the DESCRIPTION fields take (path, verbose, desc = NULL), as the code checks take (path, verbose, parsed = NULL), so either can reuse a parse you already have. desc may be what read.dcf() returns, and issues() and tidy() gained a severity column.
  • description_bare_r was removed. It asked you to quote every bare R in the Description, which is not a rule anyone enforces. Writing R Extensions asks for single quotes around other packages and external software without naming R either way, and both forms clear CRAN, so language_names leaves a bare R and a quoted 'R' alone alike and takes no position on which you prefer.
  • Three checks left the default run because no authority supports them, and each stays exported for anyone who wants it. The CRAN rule behind title_starts_with_article applies to the Description and requires the word "package" after the article, not to the Title. Writing R Extensions treats single quotes as an inclusive list for non-English usage that a quoted function name fits, which is what description_function_quotes ruled out. And ?person says authors who are natural persons hold copyright by default and need no cph role, which is what cph_role asked for (#17, thanks @eddelbuettel).

New checks

  • detect_cores_robustness catches a detectCores() result used without an NA guard. The help says it returns an integer, or NA when the answer is unknown, and NA - 1 is NA, so the next comparison dies with missing value where TRUE/FALSE needed. The fix is parallelly::availableCores().
  • A family of checks mirrors CRAN's incoming filter, so you see those findings offline against your own sources before you submit.
  • date_format catches a Date that is not ISO 8601 yyyy-mm-dd, is over a month old, or lies in the future.
  • version_format catches a Version component with a leading zero or a suspiciously large one, while leaving a calendar-year version alone.
  • encoding_utf8 catches an Encoding other than exactly UTF-8. CRAN's incoming check calls latin1 and latin2 deprecated, and a lower-case utf-8 draws the same NOTE.
  • identifier_format validates the ORCID and ROR identifiers in Authors@R, and is reported as skipped when Authors@R cannot be read.
  • description_file catches a DESCRIPTION that R cannot read: a line that is neither a field nor an indented continuation, a blank line that splits the file in two, or a file R cannot open at all, such as a directory in its place or one without read permission. R CMD build and R CMD INSTALL both stop on such a file. For a malformed line checktor used to skip the DESCRIPTION checks with nothing counted, so the file could not count against a clean bill of health, and for a blank line it judged the package on the fields above it alone. It is now a policy finding, the checks that read the fields, registered ones included, are reported as skipped, and prescribe() shows how to fix it.
  • description_fields catches a DESCRIPTION field R does not know, which CRAN's incoming check NOTEs. The usual one is Remotes, which CRAN ignores since it installs dependencies from CRAN and Bioconductor alone. A typo such as Bugreports, Import or Suggest is silently ignored by R, so the finding names the field that was meant. Config/ fields, RoxygenNote and the other forms R allows pass.
  • description_placeholders catches a Title, Description, Author or Maintainer still holding the text a usethis or package.skeleton() template wrote, such as "What the Package Does (One Line, Title Case)", with the tests CRAN's incoming check uses.
  • title_package_name catches a Title that is just the package name or opens with it and a colon, as in toypkg: Fit Simple Models, which Writing R Extensions asks you not to do and CRAN's incoming check NOTEs. A Title that opens with a name that is an ordinary word, as in "Survival Analysis", is left alone, since CRAN accepts it routinely.
  • license_file_unneeded catches + file LICENSE on a standard license such as GPL-3, LGPL-3 or Apache, which the CRAN Cookbook asks you to drop along with the file, since "these are part of R". MIT and BSD, whose templates need the file, are left alone. A LICENSE that adds attribution requirements is the exception CRAN allows, and Config/checktor/allow records it.
  • hardcoded_credentials scans string literals in R/ for a leaked secret, knowing the tokens and keys used by providers such as GitHub, AWS, Google, OpenAI, Anthropic and Stripe, along with PEM private keys and JSON Web Tokens. A token published to CRAN is public and must be revoked, and R CMD check does not look for these. Only string literals are examined, so the same text in a comment never matches. See ?lab_hardcoded_credentials for the full list.
  • spelling runs utils::aspell() over the Title and Description to mirror CRAN's incoming spelling pass, with the same ignores (single-quoted names, fn() calls, <doi:...> targets) and British and en_stats words. It reads any .aspell/ dictionary, inst/WORDLIST, or Config/checktor vocabulary you already keep, and is reported as skipped when no spell-check backend is installed or the one found fails to run. Turn it off with options(checktor.spelling = FALSE). When it reports a word, prescribe() prints a ready-to-paste .aspell/ snippet, since inst/WORDLIST alone does not clear CRAN's aspell NOTE but a .aspell/ dictionary does.
  • url_liveness fetches every URL in the DESCRIPTION, .Rd files and vignettes and reports the ones that return an error, a 404, or a redirect, which is what R CMD check --as-cran does through tools::check_package_urls(). It runs when you are at the console and stays off in scripts, in continuous integration and under R CMD check, where a slow or unreachable network would make the result depend on the machine rather than the package. Set options(checktor.url_check = TRUE) or FALSE to decide for yourself. With no network reachable it comes back marked as a check that did not run, rather than calling every link broken or quietly reading as though every link resolved, while a single unreachable host among reachable ones still counts. urls remains the offline half, catching http:// links and shorteners without leaving the room.
  • A family of checks reads the code outside R/, where several of the most common rejections land. Every code check used to read R/ alone, so an install in an example, a write to the working directory in a vignette, or an options() call in inst/demo that was never put back all went unseen. Each rule below is one a maintainer has received verbatim from CRAN.
  • example_interactive asks for if (interactive()) where an interactive function is hidden in \dontrun{}, so a reader sees it is not for a script. It reports one in \donttest{} too, since R CMD check --as-cran runs that code, where a prompt errors and an app waits for input. It reads the parsed example, so a function named in a comment or a string is not a call, an app shinyApp() builds without printing is not a launch, and only a guard that encloses the call excuses it, @examplesIf interactive() included (#19, thanks @TanguyBarthelemy). A guard still counts when it is combined with &&, or with || against another guard, wrapped in suppressWarnings(), split by a comment or kept in a variable assigned before it on every path, and interactive() && f() guards f() as an if would. An assignment on the right of && or ||, which may never run, is not such a path.
  • example_installs catches installing a package from an example, a vignette or a demo.
  • example_writes catches a write to anywhere but tempdir(), judged with the same destination logic the R/ check uses. The write checks now share one list of what counts as a write, so they agree with each other, and it covers the readr, data.table, arrow, spreadsheet and JSON writers alongside the base ones. write_csv(), write_rds(), fwrite(), write_xlsx(), write_parquet() and ggsave() are all seen now, in R/ and in examples alike.
  • example_state catches options(), par() or the working directory changed and never put back. A change is put back when its old value is captured and later handed to the setter of the same kind in the same file, as in old <- setwd(tempdir()) then setwd(old). par(no.readonly = TRUE) is a read, not a change, and an on.exit() outside a function or a call that runs code in a frame of its own (local(), with(), within(), eval(), evalq()) is no restore: R CMD check never runs it, and knitr runs it straight away.
  • example_internal_ns catches ::: in an example or vignette.
  • example_tf_usage catches T or F for TRUE or FALSE in an example, a vignette or a demo, judged by the same rule tf_usage applies to R/. Tests are read only with tests = TRUE, since CRAN rarely reads them.
  • example_unparseable catches an \examples{} section that is not valid R, \dontrun{} included, and names the line the parser stopped on. R CMD check writes \dontrun{} code out as comments and never parses it, while reviewers run it and send back "Unexecutable code in man/...". It is a robustness finding rather than policy, since Writing R Extensions lets \dontrun{} hold text that is not R.

internal_ns covers the same rule in R/, where a ::: call reaches an object

another author is free to change in routine maintenance. unexported_example_ns

used to suggest adding ::: to an example, which is the change CRAN asks you to

undo, so it now says to export the object or keep the topic internal instead.

Every check in this family reads an example as R runs it. An Rd % comment is

dropped, code that shares a line with a \dontrun{} or \donttest{} block is

still read, a line of a hidden block that is not R, such as a <your key>

placeholder, is passed over without hiding the rest of the example, and code under

#ifdef is read for every platform. Sweave (.Rnw) vignettes are read alongside

R Markdown and Quarto, and the line a finding gives is its line in the .Rd file

or vignette.

  • rd_bibliography reads the \bibcitet{}, \bibcitep{} and \bibshow{} macros R 4.6.0 added to .Rd files and reports what R CMD check would: a key no bibliography holds, which R drops from the page, a key cited but never listed, and a REFERENCES file left at the top level. Keys are looked up as R does, in the package's REFERENCES.rds, .R or .bib, in R's own bibliography, and for pkg::key in an installed dependency, without running REFERENCES.R. rd_bibliography_files, at robustness tier, reports a REFERENCES.bib without bibtex in Suggests and a bibliography that is not installed because it is outside inst/ or excluded by .Rbuildignore.
  • language_names catches a bare programming-language or statistical-computing name in the Title or Description that CRAN asks to see single-quoted, covering names like Python, Java, JavaScript, Rust, MATLAB, SAS and Stata. It is the language counterpart to software_names, kept separate because a language name and a package name are different kinds of thing. Single-letter and common-word names are left out so ordinary prose stays quiet, and you can extend the list with Config/checktor/language_names. Like software_names, it judges each mention on its own and skips a quoted longer name such as 'MATLAB Runtime', a link, a DOI, a function call and a double-quoted title.
  • format_names reports a format or markup name written without single quotes in the Title or Description: JSON, HTML, XML, CSS, YAML, TOML, Markdown, LaTeX, TeX and SQL, plus C++, Fortran and Tcl, which CRAN packages write either way. It runs only when you call it, at opinion tier. A census of CRAN in September 2026 found that packages accepted at new-package review in the previous 18 months wrote these names bare 62% of

The NEWS section is longer than shown here.

From NEWS.md in the release

Install

Health

CRAN checks
13OK
Slowest check: 4.8 min · r-oldrel-windows-x86_64
Status changes
  • OK13 OK2026-08-05
  • NOTE12 OK, 1 NOTE2026-08-01
  • OK6 OK2026-07-03
Advisories

none known

Documentation

In release 0.2.0
READMEYes · 229 wordsVignettesYes · 5 · dynamicNEWSYes · 100% structured · mentions 0.2.0Citation fileNoWebsiteYes · pkgdown
Help pages
107 (2 internal)includes a package overview page
Examples that run
99%104 run in a plain check · 1 never run
Exported functions with examples
99%
Documented parameters
99%
Return-value docs
99%
Help pages citing references
1%

Downloads

1.2K
CRAN downloads in the past year
Rank #10,789 · ~3/day · ~101/mo
Daily download trend is not available in this view yet.
32730 days
97590 days
1.2K1 year
Compare downloads with other packages →
Also on27 r2u8 autocran

Repository

28Stars
0Forks
1Open issues
0Open PRs
1Releases
89Commits
1Commit identities
License file reads as AGPL-3.0 · 89 commits · Last activity 2026-10-15 · 0% stars, 30d · Default branch at 0.2.0.9000, ahead of CRAN 0.2.0 (checked 2026-10-21)
Responsiveness
How these are sampled
PRs merged (all time)
75%
Median days to close, 50 most recently updated closed issues
25
Median days to close, 50 most recently updated closed PRs
0

Stars over time

2025-09-05 · 12026-09-18 · 28
PracticesBeta

10 development-tooling and community-health practices detected across 6 families in the upstream repository

Checks run against github.com/coatless-rpkg/checktor on 2026-10-21.

Continuous integration (2)
GitHub ActionsR CMD check workflow

The R CMD check workflow runs on Linux, macOS and Windows, and on R-devel

Governance and community (2)
PR template (inherited from coatless-rpkg)

Funding links: GitHub Sponsors, Patreon, Buy Me a Coffee, thanks.dev

Docs source (3)
pkgdown

GitHub Pages site last deployed 2026-10-15 · The repository has a site deploy workflow

pkgdown site last built 2026-10-15

Reproducibility and dev environment (1)
Dev Container
Show all practicesHide 2 practices
CRAN release process (1)
cran-comments.md
Lint, format, editor (1)
RStudio project
How this is detected·Detection ruleset v4 (2026-10-20)

Dependencies

Declared dependencies
9 external dependencies (excludes base and recommended)

Installing checktor adds 5 packages (3 with compiled code, 1.6 MB of source tarballs). Heaviest: rlang 766 KB, cli 629 KB, xml2 152 KB.

Depends (1)
R >= 4.5.0
Imports (6)
LinkingTo (0)
none
Enhances (0)
none
Reverse dependencies
0direct
0indirect

Nothing depends on this yet.

People & History

People (1)
Author, Maintainer since 0.1.0 (2026), Copyright holder
Releases (2)

Pick two releases to compare their code metrics.

  • 0.2.0Latest
    record
    2026-10-14 · current release · diff ↗ ·
    removed 13 exports
    diagnose_cran_comments_file, diagnose_example_structure, diagnose_missing_examples, diagnose_news_file, diagnose_package_size, diagnose_print_cat_usage, diagnose_readme_relative_links, diagnose_roxygen_usage, diagnose_seed_setting, diagnose_suggested_in_examples, diagnose_tf_usage, diagnose_urls, diagnose_value_tags
    added 84 exports
    ci_report, collect_rd_text, extract_rd_section, find_package_root, lab_acronyms, lab_authors, lab_browser_calls, lab_citation_file, lab_code_exercised, lab_commented_examples, lab_core_usage, lab_cph_role, lab_cran_comments_file, lab_date_format, lab_description_fields, lab_description_file, lab_description_function_quotes, lab_description_length, lab_description_placeholders, lab_description_quoted_quotes, lab_description_starts_with, lab_detect_cores_robustness, lab_donttest_vs_dontrun, lab_encoding_utf8, lab_example_installs, lab_example_interactive, lab_example_internal_ns, lab_example_state, lab_example_structure, lab_example_tf_usage and 54 more
  • 0.1.0
    record
    2026-07-02
  • R
    R 4.6.0 released · 2026-04-24

Package metadata

First published
2026-07-02
Total releases
2 / 1 yrs
License
AGPL (>= 3) OSI
Minimum R
≥ 4.5.0
Download size
471 KB

Cite

Cite this package

Run in R for the authors' preferred citation:

citation("checktor")
Balamuta, J. J. (2026). checktor: Extra CRAN Submission Checks (Version 0.2.0) [Computer software]. https://doi.org/10.32614/CRAN.package.checktor

This package has no citation file, so citation() returns this entry built from DESCRIPTION.

Cite the R Observatory

For a number measured here: a download total, a coverage figure, an archival date.

APA

Balamuta, J. J. (2026). R Observatory: Metrics for checktor version 0.2.0 [Data set]. HJJB, LLC. Data release v2026-10-25. https://doi.org/10.5281/zenodo.21843040

From data release v2026-10-25, which the citation names so these numbers can be found later. More on citing and the projects behind them.

Report a problem with this page →

Privacy choices

These apply to this browser and are stored on this device only. Nothing about your choice is sent to us.

Read the privacy policy