0.4.0 - 2026-07-13
Release Notes
Precision release driven by the top-300 CRAN audit: the corpus total fell
from ~23,300 diagnostics to ~6,500 (-72%) while every confirmed real bug
in the audit's regression list still surfaces, and the new rule family
found previously unknown bugs (scales !length(x) == 1 guards among
them).
Added
-
Typed and required parameter metadata in typeshed signatures, including
numeric mode unions and strict validation throughry typeshed validate. -
R-compatible exact, partial, and positional call-argument matching with
RY090for unknown named arguments,RY091for missing required arguments,
andRY092for provable argument type mismatches. -
Runtime custom typeshed loading through the
typeshedkey inry.tomland
repeatable--typeshedflags. Flat and nested stub layouts are supported,
later directories replace earlier packages, and editor diagnostics use the
same workspace configuration. -
The embedded typeshed is now a vendored snapshot of the standalone
r-typeshedrepository, with schema-version validation and source metadata. -
New mis-parenthesization rule family:
RY093(comparison inside
length()/nchar()/abs(), also detected inside&&/||operands),
RY095(!x == ynegation-comparison precedence), andRY096
(hasArg()naming a non-formal of the enclosing function). -
RY094: printf-family (sprintf/gettextf) literal format strings are
checked against the supplied argument count. -
RY097: files whose top-level statements are mostly unparseable (Ratfor
sources, broken fixtures) collapse into a single info diagnostic instead
of hundreds of spurious errors. -
RY098: a parameter default referencing a body-local is flagged when an
execution path can force the default before the local is assigned;
the idiomatic late-bound default stays silent. -
Confidence tiers: every diagnostic carries
high/medium/low
confidence, output is ranked by tier, diagnostics undertests/,
data-raw/,demo/,vignettes/, andinst/are demoted one tier, and
--min-confidencefilters both output and exit code. A symbol used in
value position that only resolves to a function from another namespace is
reported at high confidence with the resolution target in the message. -
Baseline workflow for incremental adoption:
ry check --write-baseline
snapshots current diagnostics (line-number-free matching) and
--baseline/ thebaselineconfig key subtracts them from later runs. -
Package-aware scan contexts:
tests/testthat/files see the package's
own namespace,testthat, DESCRIPTIONDepends/Suggests, and
helper-*.R/setup-*.Rbindings;data-raw/,demo/, andvignettes/
attachDepends;.Rbuildignorepatterns (Perl regexes) are respected
without ever excludingR/ortests/. -
NSE completion: rlang
{{ }}embrace is recognized as a mask escape
(typos inside it still flagged), and the.data$col/.data[["col"]]/
.env$varpronouns resolve against the mask schema or lexical scope. -
Minimum-viable S4 modeling: in-package
setClass/setGeneric/
setMethodare collected across files and dispatched on receiver class,
@slot access is modeled, and vector names survivet()and
data.frame()construction. -
Scope and flow fixes:
inherits(x, "cls")guards narrow types,
useDynLib(.fixes=)prefixes resolve native-routine symbols, R6/S7
method bodies seeself/private/super, top-level
assign(..., envir = asNamespace(...))binds, and replacement-function
assignments (dimnames<-and friends) keep the target bound. -
User-defined infix operators (
%op%) preserve their operands in the AST;
zeallot/future%<-%/%->%destructuring introduces its pattern
bindings when a package defining the operator is in scope. -
Data-driven semantics via new
injectsstub metadata:withr::with_*
path injection and R6/S7 method-environment bindings now come from the
typeshed instead of hardcoded checker logic. -
Derived NSE for user-defined functions: a parameter whose first use is a
defusing call (enquo,enexpr,ensym,quo,substitute,
match.call, ...) marks call-site arguments as unevaluated, so
arrow-style test helpers (compare_dplyr_binding(.input %>% ...)) stop
producing unbound-variable noise. -
testthat helper/setup files now propagate their
library()/require()
attachments (not just bindings) to test files, and the helper filename
match covers allhelper*/setup*prefixes. -
The data-mask gate is fully data-driven: any loaded package whose stub
declaresevalmetadata gets NSE treatment (rlist, patrick, bench, ...),
and user-defined S3 methods inherit the eval metadata of a stubbed
generic with the same name (dtplyr/dbplyr verb methods). -
foreach(i = ..., p = ...) %do%/%dopar%/%op% { ... }binds the loop
variables in the body regardless of the operator alias used. -
attach(x)marks the scope's search path as unanalyzable, silencing
unbound-variable diagnostics for legacy attach-style scripts. -
Type narrowing applies to expression-position
if(e.g.
x <- if (is.function(f)) f(1) else f). -
Tidyverse NSE metadata is now GENERATED from installed-package Rd docs
(gen_nse_metadata.Rin r-typeshed reads the<data-masking>/
<tidy-select>argument markers), giving full dplyr/tidyr coverage and
a new tidyselect stub; dynamically registered S3 methods inherit their
generic's NSE metadata. -
.binds inside data-masked arguments (dplyrdo(), pipe idioms), for
both%>%and the native|>pipe. -
Defused-parameter derivation covers
{{ }}embrace usage and exclusive
enquos(...)-style...defusal in user functions. -
Inside a data-masked argument with an unknown schema, lexically resolved
symbols infer as opaque — mask columns may shadow them, so their lexical
types no longer drive arithmetic/comparison diagnostics. -
Rcpp modeled as a first-class package:
sourceCpp()carries the new
scope_effect: unknown_bindingsstub metadata (compiled exports are
unknowable),cppFunction()returns a function, andbase::attachnow
uses the same data-driven mechanism instead of a hardcoded recognizer. -
tinytest scan context: files under
inst/tinytest/see the package's
own namespace,tinytest, and DESCRIPTION Depends/Suggests, mirroring
the testthat context.
Changed
RY_NO_INSTALLED_LIBRARIES=1disables resolution of imported-package
exports from the machine's R installation; the ecosystem regression
harness sets it so committed snapshots are environment-independent.- The ecosystem harness report writer is implemented in R (jsonlite)
instead of python3; the harness now requiresRscript. - Typeshed auditing and stub generation removed from this repository's CI
and scripts — they live in r-typeshed, whose CI runs them.
Install ry-cli 0.4.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/sims1253/ry/releases/download/v0.4.0/ry-cli-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/sims1253/ry/releases/download/v0.4.0/ry-cli-installer.ps1 | iex"Download ry-cli 0.4.0
| File | Platform | Checksum |
|---|---|---|
| ry-cli-aarch64-apple-darwin.tar.gz | Apple Silicon macOS | checksum |
| ry-cli-x86_64-apple-darwin.tar.gz | Intel macOS | checksum |
| ry-cli-aarch64-pc-windows-msvc.zip | ARM64 Windows | checksum |
| ry-cli-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| ry-cli-aarch64-unknown-linux-gnu.tar.gz | ARM64 Linux | checksum |
| ry-cli-x86_64-unknown-linux-gnu.tar.gz | x64 Linux | checksum |