
Stability, Deprecation and the Contract
Youzhi
Yu
University of Chicago
Source: vignettes/articles/stability.Rmd
stability.RmdCode that calls this package, and results saved from it, should keep working. This page says what that promise covers, how anything in it is changed, and what happens when an engine the package wraps disappears.
What is stable
| Part | The promise |
|---|---|
| Exported functions and their arguments | Not removed or renamed without the deprecation cycle below |
The ggcpt result |
Slots and columns are only ever added;
changepoints$cp is always the last observation before the
change (cp_convention = "left") |
| Condition classes and their fields | Branch on ggchangepoint_unsupported, not
on the wording. Messages may be reworded in any release; classes and the
fields listed in ?ggchangepoint-conditions may not |
| The JSON schema |
as_json() writes schema 1.x. Fields are
only added within 1.x; removing or renaming one makes it 2.0, and
cpt_import() refuses a major version it does not know |
| A saved result | A ggcpt is a list of plain data:
readRDS() reads it in any R session, with no packages
installed. Only $fit, the engine’s own object, needs the
engine |
A caller that uses the classes, not the words:
res <- tryCatch(cpt_detect(rnorm(50), method = "wbs", family = "poisson"),
ggchangepoint_unsupported = function(e) e)
class(res)[1:3]
#> [1] "ggchangepoint_unsupported" "ggchangepoint_error"
#> [3] "error"
res$supported
#> [1] "gaussian"What is not
- Printed output, plot styling and message wording. They are for people and get better.
-
$fit. Its structure belongs to the engine and changes when the engine does. -
Numbers that depend on an engine’s version. Every
result records the versions that made it (
fit$versions),print()notes when the installed engine has moved on, andcpt_verify()re-runs a saved result and reports what changed. -
The measurement tables (
cpt_runtimes,cpt_null_sizes, …). Their columns are stable; their values are re-measured each release, which is the point of them. - Anything reached with
:::.
How something changes
-
A default that changes results is announced in NEWS
under “Changes to results”, with the old behaviour one argument away.
0.6.0 has three: a two-observation minimum segment for the
changepointengines,cpm’s false-alarm budget scaling with the series, andcpt_consensus()requiring a majority by default. -
A deprecated function or argument warns once per
session (through
lifecycle) for at least two minor releases, then errors for one, then goes. NEWS lists it under “Deprecated” with its replacement. - A breaking change is made only in a minor release before 1.0, and only in a major one after it, listed under “Breaking changes” with the reason.
When an engine leaves CRAN
Thirty-odd engines are in Suggests, and CRAN archives
packages as a matter of routine. When one goes:
- the method stays in
cpt_methods()and its wrapper and tests stay in the package, skipped, so it returns the day the engine does; -
cpt_detect()says where the engine can still be installed from (fpop, archived in September 2026, installs from R-Forge) and names the installed methods that detect the same kind of change; - a scheduled check (the all-engines workflow) compares every declared dependency with the live CRAN index each week, so an archival is found by the check, not by a user.
Versioned results
fit <- cpt_detect(Nile, method = "strucchange")
str(fit$versions)
#> List of 5
#> $ engine : chr "strucchange"
#> $ engine_version: chr "1.6-0"
#> $ ggchangepoint : chr "0.6.0"
#> $ r : chr "4.6.1"
#> $ created : chr "2026-09-26T14:20:06+0000"glance(fit) carries the engine version as a column, so a
table of results made across a year of package updates says which engine
made which row.