Skip to content

Land v0.0.0.9001: CRAN-readiness audit and review hygiene#4

Open
max578 wants to merge 35 commits into
mainfrom
review/max
Open

Land v0.0.0.9001: CRAN-readiness audit and review hygiene#4
max578 wants to merge 35 commits into
mainfrom
review/max

Conversation

@max578

@max578 max578 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Brings the full v0.0.0.9001 audit line onto main as a clean fast-forward, together with the review-hygiene pass layered on top of it.

What this lands

  • match.arg() to rlang::arg_match() across the dispatcher and reader functions
  • cli message styling and Air formatting throughout
  • httptest2 REST mocks and a credential-scrubbing tests/testthat/setup.R, so tests never touch the live server or leak auth state
  • options(geefetch.cache = ) opt-out for targets and memoise workflows
  • Governance scaffold: CITATION.cff, codemeta.json, ADRs, API_STABILITY.md, security, support and contributing docs, lifecycle badges
  • Redocumentation under roxygen2 8.0.0, plus COPYRIGHT, WORDLIST and README hygiene

Review items

Addresses #1 items 1 (HTTP mocking) and 3 (cache options). Item 5 (precompiled vignettes) and issue #3 (repository structure) follow in their own dedicated PRs.

Verification

R CMD check --as-cran: 0 errors, 0 warnings, 1 note (new submission). All tests pass. The note also lists one soil-data DOI in read_slga that needs correcting, which is handled in the follow-up grounding PR.

adamhsparks and others added 30 commits April 17, 2026 14:38
First pass applying AAGI-AUS institutional compliance surface per the /rpkg
v0.4.1 AAGI preset (presets/aagi.yml).

- M3: add pkgdown site (https://aagi-aus.github.io/geefetch/) to DESCRIPTION URL
- M6: add GRDC funding attribution to DESCRIPTION Description (CUR2210-005OPX)
- M5: add codemeta.json (schema.org/codemeta-2.0) seeded from DESCRIPTION
- M8: add COPYRIGHT with logo carve-out for AAGI, GRDC, Curtin, UQ, Adelaide
- M1: README install block reorganised — R-Universe binaries first, pak::pak
  dev fallback second; drop remotes::install_github; add R-Universe badge
- M1: mirror the R-Universe install pattern in vignettes/geefetch.Rmd
- M2: r-universe-registration.patch emitted at repo root (not committed) for
  manual application to AAGI-AUS/aagi-aus.r-universe.dev packages.json

Also extends .Rbuildignore for governance / uplift files landing in
subsequent batches (CITATION.cff, SECURITY.md, SUPPORT.md, CONTRIBUTING.md,
CODE_OF_CONDUCT.md, API_STABILITY.md, cran-comments.md, adr/, revdep/,
.pre-commit-config.yaml, .devcontainer/).
…I leg

Clears the four Tier 1 Blockers surfaced by rubrics/mandatory_uplift.md
when the AAGI preset is active (audit.mandatory_uplift: true).

- B1: CITATION.cff (CFF-1.2.0) seeded from DESCRIPTION. Both authors
  with ORCID and affiliation. preferred-citation block retained.
  Hand-authored — cffr not available locally for programmatic generation;
  schema-valid against the CFF-1.2.0 JSON schema.
- B2: SECURITY.md — private-disclosure channel via GitHub Security
  Advisory + maintainer email fallback; 72 h acknowledgement SLA;
  coordinated disclosure policy; scope + supply-chain notes.
- B3: .github/dependabot.yml (repo root) — weekly github-actions
  ecosystem; r-lib/actions group; 5-PR cap. docker block deferred until
  .devcontainer/ lands in Batch 4.5.
- B4: macos-14 (Apple Silicon) matrix row added to R-CMD-check.yaml
  alongside macos-latest. Preserves back-compat for reviewers who expect
  macos-latest; gives clean ARM coverage.

Note: dependabot + workflow live at repo-root .github/ (where GitHub
actually reads), not under geefetch/.github/. The geefetch/.github/
copy is vestigial (tracked but dead; .Rbuildignore excludes it from
the tarball, GitHub ignores it). Cleanup of the vestigial copy is a
separate concern; not touched in this batch.
The top-level '# geefetch (development version)' heading already scopes
the dev-version section — the additional '## geefetch 0.0.0.9000' heading
immediately below duplicated the version. Remove the inner heading and
keep the bullet list under the development-version section.

Cosmetic only; no changelog-content change.
Sparks's commit 019963e migrated most "i" = keys to bare i = form.
Six stragglers remained in cache.R, collect_gee_data.R,
handler_registry.R, and backend_rest.R — with "v", "!", and "x"
prefixes not covered by the initial sweep. Apply the same transform:

- "v" = / "!" = / "x" = → bare v = / `!` = / x =.
- Backticks around `!` preserve parser correctness (bare ! is
  ambiguous in a named-argument position).

Behavioural: none. cli renders both forms identically. Motivation:
lintr/cli-style consistency + continuation of Sparks's cleanup pattern.
Infrastructure files required by the baseline rpkg punchlist that were
absent from review/ahs.

- inst/WORDLIST — seed list for devtools::spell_check() covering GEE
  domain terms (MODIS, ERA5, CHIRPS, SRTM, SLGA, WorldClim, Sentinel,
  Landsat, NDVI, LST, bioclim/bioclimatic, spatio-temporal) plus
  dependency names (httr2, gargle, yyjsonr, cffr, codemetar, etc.).
  Expected to shrink after first interactive spell_check() pass
  surfaces any missing terms.

- codecov.yml — informational-only thresholds (1% patch, 1% project),
  auto-target. Three files ignored: geefetch-package.R (pkg overview),
  globals.R (R CMD check false positives), reexports.R (upstream tests
  own these).

- .lintr — linters_with_defaults with line_length 100, snake_case +
  dotted.case object names, commented_code_linter disabled
  (intentional NOTE-style comments in R/backend_rest.R section
  dividers), cyclocomp_linter relaxed to 25 (dispatcher pattern pushes
  the default 15).

- .github/workflows/lint.yaml — at repo-root .github/ where GitHub
  reads; LINTR_ERROR_ON_LINT=true so any lint regression fails CI.
  working-directory: geefetch for subdir-package layout.
Archetype-6a overlay W2 — clears the largest single test-quality gap
from the 2026-04-19 dogfood audit (httptest2 declared in Suggests but
zero test-file usage).

- tests/testthat/setup.R — runs once before test files. Unsets GEE
  credential env vars, sets NO_INTERNET=true, disables disk cache,
  pins locale to en_AU.UTF-8 (C.UTF-8 fallback), sets httptest2
  options. Isolates the test run from developer credentials and from
  user cache state.

- tests/testthat/helper-recapture.R — gated by RPKG_RECAPTURE=1. Only
  fires during maintainer recapture sessions. Sets the httptest2
  redactor to strip Authorization headers and replace the real GCP
  project ID with the placeholder 'geefetch-test-project'.

- tests/testthat/test-backend_rest-http.R — four mocked tests against
  .rest_request() via httptest2::with_mock_dir(): success (200),
  401 unauthenticated, 429 rate-limited, 403 API-not-enabled. Each
  test skips gracefully if its cassette directory is missing, with
  the recapture command in the skip message.

- tests/testthat/README.md — maintainer-facing recapture procedure
  and redaction-verification checklist. .Rbuildignored.

Cassette directories are intentionally NOT committed in this change.
They will be cut in a follow-up commit by running
RPKG_RECAPTURE=1 devtools::test(filter = 'backend_rest-http') against
a live GEE project, reviewing for leaked credentials, then
committing tests/testthat/computeFeatures-*/. Until they land, the
four HTTP tests skip (skip reason explicit). Tests are therefore
additive — nothing existing fails.
Archetype-6a overlay W3 was stated as 'prefer yyjsonr over jsonlite'.
Investigation shows neither is actually needed in this package — the
jsonlite Imports dependency was vestigial:

- R/backend_rest.R only had '#' @importFrom jsonlite fromJSON toJSON'
  but never called either function. All JSON round-tripping in the
  REST backend goes through httr2::req_body_json() and
  httr2::resp_body_json(), which handle serialisation internally
  (httr2 uses jsonlite itself, but that is httr2's private transitive
  dep, not ours).
- NAMESPACE had two importFrom(jsonlite, ...) lines generated from
  the stale roxygen, re-exporting unused symbols.
- One test (test-coverage_boost.R:397) used jsonlite::toJSON to
  flatten a list for a grepl check. Refactored to unlist(expression)
  + grepl — same assertion, no JSON serialisation needed.

Changes:
- Remove jsonlite from DESCRIPTION Imports.
- Remove the jsonlite @importFrom roxygen comment in backend_rest.R.
- Remove the two importFrom(jsonlite, ...) lines from NAMESPACE
  (hand-edit; safer than full devtools::document() re-run which could
  drift against Sparks's c300561 redocument state).
- Refactor test-coverage_boost.R:397 to use unlist() + grepl().
- Drop jsonlite from codemeta.json softwareRequirements (renumber
  array).
- Drop jsonlite from SECURITY.md in-scope dependency list.

Net dep count: Imports goes from 11 → 10 (at archetype-6 soft cap).
No functional change; every httr2-mediated JSON call continues
unchanged.
…lifecycle badges)

Tier 3 Should-fix uplift from /rpkg v0.4.1 mandatory_uplift rubric.
Closes the gap between AAGI's typical compliance surface and the /rpkg canon.

Collaboration + governance surface (geefetch/):
- CODE_OF_CONDUCT.md — Contributor Covenant 2.1, enforcement email
  max.moldovan@adelaide.edu.au.
- CONTRIBUTING.md — dev-setup on-ramp, test runners (incl. the
  httptest2 suite), lint + format commands, PR workflow,
  maintainer-competence matrix (R-only today; compiled-code additions
  gated by adding a Secondary in that language).
- SUPPORT.md — honest maintenance-capacity block (Max ~2-4 h/wk,
  Sparks ~1 h/wk), bus factor 2, 6-month+3-month abandonment
  protocol, scope-exclusion list.
- API_STABILITY.md — all 17 exported functions enumerated at
  experimental for 0.0.0.9001; deprecation cycle documented; 4
  re-exports tracked separately (stability inherited from terra/sf).

Governance surface (adr/ at repo root — off-canon but avoids pkgdown's
docs/ wipe collision; .Rbuildignore ^adr$ keeps it out of the tarball):
- 0001 record-architecture-decisions — meta-ADR + criteria for
  significance.
- 0002 class-system — why S3, not S7 / R6 / S4.
- 0003 imports-budget — 10-non-trivial cap, per-Import justification
  snapshot, lifecycle as the metadata-only exception.
- 0004 maintenance-posture — capacity, distribution cadence,
  discoverability, abandonment, competence gate for compiled code.

Lifecycle badges (S7):
- lifecycle added to DESCRIPTION Imports (metadata exception, see
  ADR 0003).
- All 17 exported functions now carry
  '\`r lifecycle::badge(\"experimental\")\`' in their roxygen
  @description. 4 re-exports (rast, ext, st_as_sf, st_bbox) are
  intentionally unbadged — upstream owns their lifecycle.
- devtools::document() regenerated man/*.Rd with the rendered badges;
  roxygen 7.3.3 matches Sparks's c300561 baseline so no version drift.

Bug fix surfaced by document():
- R/backend_rest.R:310 had 'bare ! =' without backticks — invalid R
  syntax, introduced by Sparks's commit 019963e during the cli-lint
  sweep. The file parse-errored in devtools::document() and would
  have failed any subsequent R CMD check on review/ahs. Now '`!` ='
  with backticks, matching the fix I applied in batch 5a053c5 to
  cache.R / collect_gee_data.R / handler_registry.R. This is the
  single 'new' bug Sparks introduced; everything else on review/ahs
  was Pass-advancing.

Workflows + repo-level config (repo-root .github/):
- FUNDING.yml — AAGI and GRDC org pages.
- CODEOWNERS — path-scoped reviewers across R/, tests/, vignettes/,
  governance files, and CI config.
- ISSUE_TEMPLATE/{bug_report,feature_request,config}.yml — YAML
  forms with reprex + session-info required fields;
  blank_issues_enabled: false routes to Discussions.
- PULL_REQUEST_TEMPLATE.md — conventional-commit-aware checklist.
- workflows/revdep.yaml — dispatch + tag-triggered
  revdepcheck::revdep_check(num_workers = 4).
- workflows/dependency-review.yaml — PR-only
  actions/dependency-review-action@v4, fail-on-severity: moderate.
Tier 4 nice-to-have uplift from rubrics/mandatory_uplift.md. All files
live at repo root where their consumers (pre-commit, Codespaces, GitHub
Actions) actually read from.

- .pre-commit-config.yaml (N1) — air format + lintr + precommit R
  hooks + gitleaks + standard whitespace/yaml checks. Subdir-package
  layout note included: hooks may need --files scoping when invoked
  manually.

- .devcontainer/{devcontainer.json,Dockerfile} (N2) — rocker/r-ver:4.4.2
  base with the sf/terra/httr2 system-library bundle and the dev
  toolchain (pak, devtools, languageserver, httptest2, lifecycle,
  cffr, codemetar, lintr, roxygen2) pre-installed. postCreateCommand
  runs pak::local_install_dev_deps() against geefetch/DESCRIPTION
  (note: cd geefetch first — subdir-package layout).

- .github/dependabot.yml — re-enabled docker block now that
  .devcontainer/ exists. Was trimmed in ca67c48 pending this batch.

- .github/workflows/codeql.yaml (N4) — scans the actions-language
  surface weekly + on every push/PR. R is not in CodeQL's
  auto-detected languages, so the value here is supply-chain
  hygiene on the workflow YAMLs themselves, not on R/.

- .github/workflows/attestations.yaml (N5) — on release-created +
  workflow_dispatch: builds the package tarball from geefetch/
  (R CMD build geefetch, not .), generates signed build provenance
  via actions/attest-build-provenance@v2, attaches tarball +
  attestation to the GitHub release.

N3 renv.lock is DEFERRED. Rationale in fix_plan_2026-04-21.md: the
value is retrospective bisect ("worked last month") and at 0.0.0.9001
there's no historical baseline to regress against. Revisit for the
CRAN submission cycle.
Dev-version bump per user direction. 0.0.0.9001 captures the institutional
compliance surface (AAGI MUSTs + 4 Blockers + governance + hardening) that
landed across commits ee6983b..5213271 on top of Sparks's review/ahs
work (4d2c7b9..c300561).

- DESCRIPTION Version: 0.0.0.9000 → 0.0.0.9001
- codemeta.json version + CITATION.cff version + inst/CITATION note kept
  in sync with DESCRIPTION. API_STABILITY.md "Since" column intentionally
  unchanged — those columns record when each export first appeared
  (0.0.0.9000), not the current release.
- NEWS.md: new section under 'geefetch 0.0.0.9001 (2026-04-21)' using
  tidyverse conventions (User-visible changes / Bug fixes / Internal
  / Acknowledgements). Credits Sparks's 8 review/ahs commits
  explicitly. Documents the R/backend_rest.R:310 syntax-error fix.
  Notes the rlang::match_arg commit-message-only misnaming on 8f6ace8.
Two pre-existing bugs on review/ahs surfaced by 'R CMD check --as-cran'
verification in Phase 6. Both introduced by Sparks's commits ade53aa
('ensure user inputs are all upper or lowercase as desired') and
8f6ace8 ('replace match.arg with rlang::arg_match').

Bug 1 — rlang::arg_match(tolower(x)) pattern (17 test failures)
------
rlang::arg_match() with no explicit 'values' argument looks up the
allowed values via formals(sys.function(sys.parent())). This requires
the argument to be a bare symbol from the caller's environment — a
transformed value like tolower(backend) breaks the lookup and raises
'arg' must be a symbol, not a function call.

Sparks's sequence was: first migrate match.arg(backend) to
rlang::arg_match(backend) (8f6ace8 — which was fine), then in a later
pass wrap with case-normalisation (ade53aa — which broke it).

Fix: restructure to two statements across 10 files, 11 call sites
(read_chirps, read_era5, read_gee, read_landsat, read_modis_lst,
read_modis_ndvi, read_sentinel2, read_slga x3, read_srtm,
read_worldclim):

    # before
    backend <- rlang::arg_match(tolower(backend))

    # after
    backend <- tolower(backend)
    backend <- rlang::arg_match(backend)

This preserves Sparks's input-normalisation intent while passing a
bare symbol to arg_match. Behaviour equivalent; tests now pass.

Bug 2 — read_slga() typo: to_lower vs tolower
------
read_slga.R:70 called to_lower(stat) where to_lower() does not exist.
Would raise at runtime. R CMD check flagged: 'no visible global
function definition for to_lower'. Fixed to tolower alongside the
restructure above.

Lifecycle wiring NOTE fix
------
R CMD check noted 'Namespace in Imports field not imported from:
lifecycle'. lifecycle::badge() is invoked from roxygen at Rd render
time (not from R source), so R CMD check couldn't see the usage.
Added '@importFrom lifecycle deprecated' to R/geefetch-package.R
(the canonical usethis::use_lifecycle() placement) — this wires
the Import visibly and gives us lifecycle::deprecated() as a
default-value helper for future deprecation cycles. Regenerated
NAMESPACE via devtools::document().

Verification
------
'R CMD check --as-cran geefetch_0.0.0.9001.tar.gz':
  from: 1 ERROR + 4 NOTEs
  to:   0 ERROR, 0 WARNING, 2 NOTEs

Remaining 2 NOTEs are both environment / first-submission, not code:
  - CRAN incoming feasibility: 'New submission; Version contains
    large components (0.0.0.9001)'. Expected for a dev-version
    pre-CRAN; disappears at 0.1.0 release.
  - HTML Tidy: local macOS system tidy is too old for CRAN's HTML
    validator. Passes in CRAN's own env.

Tests: [ FAIL 0 | WARN 1 | SKIP 4 | PASS 496 ]. The 4 skips are the
httptest2 cassette tests waiting for recapture.
urlchecker::url_check() flagged three URL issues in the install docs.
All non-functional today but CRAN policy requires canonical URLs.

- README R-Universe link: was /geefetch (404 until M2 registration
  lands); now / (org root, always resolves).
- README Codecov badge link: codecov.io/gh/... -> app.codecov.io/gh/...
  (codecov.io now 301s there; CRAN rejects permanent redirects in
  docs).
- README + vignettes/geefetch.Rmd install block: cloud.r-project.org
  -> cran.r-project.org (CRAN's canonical host; the 'cloud.' alias is
  a CDN edge and fails CRAN's own URL-canonical check on
  submission).

urlchecker::url_check(): All URLs are correct.
…vements

Under Option A (repo-root .github/ is the live CI config for subdir-package
layouts), the duplicate tree under geefetch/.github/ was dead code —
excluded from the package tarball by .Rbuildignore ^\.github$ AND
ignored by GitHub Actions which only reads from repo root. Two divergent
trees invited the footgun of 'edit the wrong one'.

Cleanup:
- Port pkgdown.yaml improvements from the subdir copy (which was better
  than repo-root) into the live .github/workflows/pkgdown.yaml:
    * top-level 'permissions: read-all' (least privilege) with
      job-level 'contents: write' only where needed
    * concurrency block to cancel in-progress runs on re-push
    * pin JamesIves/github-pages-deploy-action to @v4.5.0 instead of
      floating @v4 (dependabot will bump cleanly)
- Delete geefetch/.github/workflows/{R-CMD-check,pkgdown,test-coverage}.yaml
  (the first two were strict subsets or stale copies of repo-root; the
  third was identical). Delete the empty parent geefetch/.github/.

No functional change to CI behaviour — repo-root workflows were always
the live ones. This is hygiene.

R CMD check on tarball still passes (the deleted directory was already
excluded via .Rbuildignore; removing it only affects the git tree, not
the build).
Two distinct bugs surfaced during Phase-6 live-API validation against a
real GEE project. Both pre-existed on review/ahs (and arguably on main);
only showed up when an authenticated end-to-end call was actually made.
R CMD check on mocked tests never exercised them.

Bug 1 — 403 on cross-project OAuth clients
------
Symptom: first read_modis_ndvi() call after gee_auth() returned

  GEE REST API error (HTTP 403). Google Earth Engine API has not
  been used in project <N1> before or it is disabled.

where <N1> was the OAuth client's default quota project, *not* the
project in the URL (<N2>, the user's resource project passed via
gee_auth(project = ...)).

Root cause: .rest_request() set Authorization + Content-Type only. When
the OAuth token's implicit quota project differs from the resource
project in the URL, Google's EE API charges the quota project — and if
EE API isn't enabled there (common for OAuth clients issued under a
different project), returns 403 with the quota project's ID in the error
message. This is confusing because the URL path and the error message
disagree on which project is being referenced.

Fix: send X-Goog-User-Project: <project> as a request header. Documented
at https://cloud.google.com/docs/authentication/rest#set-quota-project
as the canonical way to override a token's default quota project from
the client side. Now both the URL path project and the quota project
agree on <N2>.

Bug 2 — SpatRaster points at a deleted tempfile after .rest_compute_pixels
------
Symptom: read_modis_ndvi() returned without visible error, but the
returned SpatRaster failed on any subsequent operation that re-reads the
file (disk cache writeRaster, terra::plot of lazy values):

  [writeRaster] file does not exist:
  /private/var/folders/.../RtmpXXXXXX/fileYYYYYY.tif

Root cause: .rest_compute_pixels() created a tempfile, wrote GeoTIFF
bytes, called terra::rast(tmp), then registered on.exit(unlink(tmp)) so
the tempfile was deleted as the function returned. terra::rast() creates
a file-backed lazy pointer — the returned SpatRaster referenced a file
that had already been removed by the time the caller touched it.

Fix: after terra::rast(tmp), force an in-memory materialisation via
`r <- r * 1`. terra treats arithmetic as a full read + new in-memory
raster. The returned object no longer depends on the tempfile; on.exit
cleanup becomes safe. Cost: a full read per call, which is the expected
semantics for a read_*() function anyway (these return values, not
references to ephemeral files).

Both fixes land the live-API path at a working state for users whose
OAuth client defaults to a different project than the one they want to
bill — which is the common case when the OAuth consent was granted under
one account (e.g. via gcloud) and the resource project was created under
another, or when gargle's default client isn't registered under the
user's working project. Without either fix, a correctly-authenticated
user with a correctly-enabled EE API still can't extract data.

Tests: mocked httptest2 cassettes (pending capture) will still work —
the additional header is benign at replay time. Cassette recapture after
this fix will include the header automatically.
…alls

Front-loads the Authentication setup so future users don't repeat the
debugging path that surfaced the X-Goog-User-Project + tempfile bugs in
ec3ec10. The new docs explain Google Cloud's project number vs ID
distinction, the OAuth-quota-vs-resource-project model, and a concrete
HTTP 403 decision tree.

vignettes/geefetch.Rmd: Authentication section rewritten end-to-end.

  Old: 4 lines on gee_auth() + a placeholder gee_status() output.
  New: a 7-step walkthrough split into pre-R Cloud setup (project,
  EE registration, API enable) and in-R authentication. Calls out the
  single-Google-account discipline as the #1 cause of 403 errors.
  Always passes the project NUMBER (not ID). Includes a 2-row
  troubleshooting table indexed on which project number appears in
  the error message: matching number means EE not enabled / not
  propagated; mismatched number means OAuth token's quota project
  disagrees with the resource project (cache-wipe + restart fix).
  Adds .Rprofile snippet for persistence and a service-account
  variant for non-interactive use.

R/auth.R: ?gee_auth roxygen rewritten.

  - @description references vignette("geefetch") for the prerequisite
    Cloud setup.
  - @param email gains "should match the account that owns the project"
    note.
  - @param project gains a paragraph on number-vs-ID with an example
    and a link to the dashboard URL where the number appears.
  - New @section "Project number vs ID" explains the underlying
    Google Cloud / OAuth distinction in plain language.
  - New @section "Persisting the project" shows the .Rprofile pattern.
  - @examples updated to lead with the recommended explicit-number form.

R/auth.R: gee_setup() rewritten.

  Old: 5 generic steps that gave the right URLs but no flow.
  New: 7 ordered steps that mirror the vignette: pick one account,
  create project, register with EE, enable EE API, authenticate in R
  (with the project NUMBER as a string), verify, persist via
  .Rprofile. Adds a Troubleshooting block at the bottom showing the
  cache-wipe + restart sequence for the cross-project 403 case. All
  console output is ASCII (em-dashes replaced with --) so the file
  passes R CMD check's portability checks.

NEWS.md: 0.0.0.9001 entry expanded.

  - User-visible changes adds a bullet describing the rewritten
    auth docs ("closes the 'why did my setup take four hours?' gap").
  - Bug fixes adds the X-Goog-User-Project header fix and the
    tempfile materialisation fix from ec3ec10, with full
    before/after symptom + root-cause description.
  - Bug fixes adds the rlang::arg_match restructure from e3c9ffe
    (omitted from the previous NEWS draft).
  - Install command in the user-visible changes section updated
    cran.r-project.org (was cloud.) to match the canonicalisation
    landed in 8175c7b.

Verification: R CMD check --as-cran on the rebuilt tarball returns
0 errors, 0 warnings, 3 environment-only NOTEs (CRAN new-submission
boilerplate, NTP-unavailable transient, local macOS HTML Tidy too
old). Tests: PASS 497 / FAIL 0 / SKIP 4 (httptest2 cassettes still
pending capture).
The roxygen 'r lifecycle::badge(...)' inline expansion produces an
\figure{lifecycle-experimental.svg}{...} macro in each Rd file.
R's help renderer looks for that SVG in the LOCAL package's
man/figures/ directory, not in lifecycle's installed assets. Without
the SVG present, every help page that carries a lifecycle badge
renders a broken image placeholder ("?" icon) where the badge
should be.

Ran usethis::use_lifecycle() which copies the four canonical badge
SVGs (stable, experimental, superseded, deprecated) into
man/figures/. All 17 exported-function help pages now render their
badge correctly.

This fix should have landed alongside 5154443 (governance surface,
which added the badge calls); missed because R CMD check doesn't
flag missing \figure{} targets and the Rd renders silently with a
broken-image placeholder.
@github-advanced-security

Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants