diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index a6cf9d3..76dac5b 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -59,7 +59,7 @@ jobs: - name: Fail if an unexpected page reached the site run: | set -eu - allowed="404 authors index LICENSE LICENSE-text" + allowed="404 authors index LICENSE LICENSE-text NOTICE" # An empty result set is not a pass. A loop over nothing exits 0, so a build # that produced no pages at all would report "all declared" — the guard diff --git a/.github/workflows/update-citation-cff.yaml b/.github/workflows/update-citation-cff.yaml index bd3552e..7512d85 100644 --- a/.github/workflows/update-citation-cff.yaml +++ b/.github/workflows/update-citation-cff.yaml @@ -27,7 +27,7 @@ jobs: - name: Update CITATION.cff run: | Rscript -e ' - x <- cffr::cff_create() + x <- cffr::cff_create(authors_roles = c("aut", "cre", "cph")) x$references <- NULL; x$doi <- NULL; x$repository <- NULL x$identifiers <- Filter(function(i) !grepl("CRAN.package", i$value, fixed = TRUE), unclass(x$identifiers)) if (!length(x$identifiers)) x$identifiers <- NULL diff --git a/CLAUDE.md b/CLAUDE.md index 2451dfc..be71ce4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -133,6 +133,7 @@ Configurable via `cd_seasons()`. Default: standard meteorological (DJF, MAM, JJA - `scripts/rag_departure_framing_build.R` — ragnar store for departure framing - Naming: `rag__.R` (`noun_verb`, mirrors the `cd_*` function convention) - `data-raw/make_hexsticker.R` — hex sticker (reads from DESCRIPTION) +- `data-raw/readme_figure.R` — the README figure and the `cd_summary()` output pasted under its example, from one live run; its marked block is the README example verbatim, so re-run it and repaste when the catalog gains a year (#142) - `data-raw/example_*.R` — bundled AOIs + context geodata for vignettes ## Vignettes diff --git a/DESCRIPTION b/DESCRIPTION index abe90d5..c2ee2d6 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,5 +1,5 @@ Package: cd -Title: Climate Departure Analysis from ERA5-Land Reanalysis +Title: How far any BC watershed's climate has shifted from your chosen baseline Version: 0.6.12 Date: 2026-10-17 Authors@R: c( @@ -8,13 +8,15 @@ Authors@R: c( affiliation = "New Graph Environment Ltd.")), person("New Graph Environment Ltd.", role = c("cph", "fnd")) ) -Description: Compute climate anomalies from ERA5-Land reanalysis data for - custom areas of interest. Producer functions download ERA5-Land - monthly means, derive variables (VPD, RH, soil moisture), and publish - Cloud-Optimized GeoTIFFs with a static STAC catalog. Consumer - functions query the catalog, crop to AOI, compute baselines and - anomalies for arbitrary reference periods, and run trend analysis - (Mann-Kendall and Theil-Sen). +Description: Measures how far the climate of any area in British Columbia + has moved from a chosen reference period: air temperature, + precipitation, humidity, soil moisture and snow, by season and year + since 1950, with trends (Mann-Kendall and Theil-Sen). Reads ERA5-Land + reanalysis from a public STAC catalog of Cloud-Optimized GeoTIFFs, and + daily air temperature at points. The baseline, anomaly and trend + functions take any annual series, such as streamflow. Includes the + functions that build and publish the catalog. Under active + development. License: MIT + file LICENSE URL: https://github.com/NewGraphEnvironment/cd, https://newgraphenvironment.github.io/cd/ diff --git a/NOTICE.md b/NOTICE.md new file mode 100644 index 0000000..e4a2067 --- /dev/null +++ b/NOTICE.md @@ -0,0 +1,25 @@ +# NOTICE + +cd's climate data are derived from ERA5-Land, produced by ECMWF for the Copernicus Climate Change Service and distributed under the [Creative Commons Attribution 4.0 International licence](https://creativecommons.org/licenses/by/4.0/) (CC BY 4.0). + +> Contains modified Copernicus Climate Change Service information. + +ERA5-Land: Muñoz-Sabater, J., et al. (2021). ERA5-Land: a state-of-the-art global reanalysis dataset for land applications. *Earth System Science Data*, 13, 4349–4383. + +cd reads ERA5-Land from the [DestinE Earth Data Hub](https://earthdatahub.destine.eu/), aggregates and derives variables from it (seasonal and annual means and totals, vapour pressure deficit, relative humidity, soil moisture, snow metrics, and daily local-day air temperature), and publishes the results to `s3://stac-era5-land`. + +## Redistributed data + +The example and vignette data in `inst/` are built from these sources (scripts in `data-raw/`): + +| Source | Licence | +|---|---| +| ERA5-Land, as processed by cd | CC BY 4.0 (above) | +| BC Freshwater Atlas: watershed groups, lakes, rivers, streams | [Open Government Licence – British Columbia](https://www2.gov.bc.ca/gov/content/data/policy-standards/open-data/open-government-licence-bc) | +| Ecoregion Ecosystem Classification of British Columbia | Open Government Licence – British Columbia | +| BC Geographical Names (town points) | Not yet confirmed ([#151](https://github.com/NewGraphEnvironment/cd/issues/151)) | +| Digital Road Atlas (highways) | Not yet confirmed ([#151](https://github.com/NewGraphEnvironment/cd/issues/151)) | +| Fish & Wildlife Compensation Program Peace Region boundary, and the Peace layers clipped or masked to it | Not yet confirmed ([#151](https://github.com/NewGraphEnvironment/cd/issues/151)) | +| `bcgov/bc_climate_anomaly` (`inst/extdata/example_climate.tif`) | Not yet confirmed ([#151](https://github.com/NewGraphEnvironment/cd/issues/151)) | + +> Contains information licensed under the Open Government Licence – British Columbia. diff --git a/README.md b/README.md index f1aeffb..c28e50b 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,16 @@ -# cd +# cd cd hex sticker -Climate Departure Analysis from ERA5-Land Reanalysis + +[![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental) + -## Overview +> How far any BC watershed's climate has shifted from your chosen baseline -cd fetches [ERA5-Land](https://www.ecmwf.int/en/era5-land) hourly reanalysis (1950–present, ~9 km native grid) from the [DestinE Earth Data Hub](https://earthdatahub.destine.eu/), subsets to British Columbia, aggregates to monthly, seasonal, and annual periods, derives additional climate variables (vapour pressure deficit and relative humidity from temperature + dewpoint via the Tetens equation; soil moisture as a 4-depth mean) and snow-pack variables (snow water equivalent, snowfall, snowmelt, snow cover, plus annual derived scalars: peak SWE, snowfall fraction, snowmelt 50% day-of-year, peak weekly melt rate), and writes Cloud-Optimized GeoTIFFs alongside a static SpatioTemporal Asset Catalog (STAC) in a public S3 bucket. A monthly GitHub Action keeps the catalog current. On the consumer side, R functions (`cd_catalog`, `cd_extract`, `cd_baseline`, `cd_anomaly`, `cd_trend`, `cd_compare`, `cd_summary`, `cd_plot_timeseries`, `cd_plot_comparison`) read the COGs directly via GDAL's `/vsicurl/` — no credentials, no tile server — crop to a user-supplied area of interest, compute baselines and anomalies for arbitrary reference periods, and run Mann-Kendall and Theil-Sen trend statistics. All baseline and comparison logic stays on the consumer side, so reference periods are not baked into the served data. +cd measures how much the climate of a watershed or any other area in British Columbia has changed: air temperature, precipitation, humidity, soil moisture and snow, by season and year since 1950, compared with whatever reference period you choose, with the trend and how much it has moved. It reads ERA5-Land reanalysis from a public catalog that needs no account, so restoration can be planned and monitored against the climate a site has now rather than the one it had. It also gives daily air temperature at any point in the province, for stream-temperature models and degree-day work, and its baseline and trend steps take any annual series, such as streamflow or stream temperature. + +Bar chart of annual mean air temperature in the Kootenay Lake watershed group from 1950 to 2025, as the difference from the 1951 to 1980 average, with a dashed trend line rising about 1.9 degrees + +*Annual mean air temperature in the Kootenay Lake watershed group, compared with its 1951–1980 average. Red years were warmer, blue years cooler; the dashed line is the trend since 1951.* ## Installation @@ -12,115 +18,61 @@ cd fetches [ERA5-Land](https://www.ecmwf.int/en/era5-land) hourly reanalysis (19 pak::pak("NewGraphEnvironment/cd") ``` -## Quick start +cd is under active development and its functions change between releases (see [NEWS](https://newgraphenvironment.github.io/cd/news/index.html)). Pin a release for reproducible work: `pak::pak("NewGraphEnvironment/cd@vX.Y.Z")`. + +The example below also needs sf, Kendall and zyp: `pak::pak(c("sf", "Kendall", "zyp"))`. + +## Example + +Extract a series for an area, compare it with a baseline, and test the trend. This is the run behind the figure above: ```r library(cd) -# Load the live STAC catalog and an example area of interest catalog <- cd_catalog() aoi <- sf::st_read( system.file("extdata", "example_aoi_kotl.gpkg", package = "cd"), quiet = TRUE ) -# Extract zonal mean time series -ts <- cd_extract(catalog, aoi) - -# Compute baseline and anomalies -bl <- cd_baseline(ts, baseline_years = 1951:1955) +ts <- cd_extract(catalog, aoi, variables = "tmean", periods = "annual") +bl <- cd_baseline(ts, baseline_years = 1951:1980) ano <- cd_anomaly(ts, bl) - -# Trend analysis trn <- cd_trend(ano, trend_start = 1951) -# Reporting table cd_summary(trn) - -# Compare time windows directly -cd_compare(ts, window_a = 1956:1960, window_b = 1951:1955) +#> # A tibble: 1 × 7 +#> Parameter Period Slope Years `Total Change` Unit `p-value` +#> +#> 1 Mean temperature Annual 0.025 75 1.9 °C 0 ``` -## Caching - -`cd_extract()` and `cd_crop()` cache each COG on first read, so repeated -extractions, report renders, and vignette rebuilds pull each file from S3 -**once** and read locally thereafter — turning recurring S3 egress into a -one-time cost. Caching is on by default (`cache = TRUE`). - -```r -# First call downloads; later calls read the local cache. -ts <- cd_extract(catalog, aoi) # cache = TRUE by default - -cd_cache_info() # where the cache lives + size -cd_cache_clear() # wipe it -cd_extract(catalog, aoi, cache = FALSE) # bypass the cache for one call -``` +Files are cached after the first read and downloaded again only when they are republished. Extracted rows record which commit of cd built each file they came from. -Freshness is checked with a cheap HTTP HEAD (S3 ETag), so the monthly -catalog republish is picked up automatically; `cd_cache_fetch(href, -refresh = TRUE)` forces a re-download. For a fully-offline session set -`options(cd.cache_revalidate = FALSE)` to serve cached copies without any -network call. +## Learn more -**Stopgap without the cache.** If you read COGs through GDAL directly -(e.g. raw `terra::rast("/vsicurl/...")` outside `cd_crop()`), you can cut -repeat egress within a session by enabling GDAL's `/vsicurl/` cache: - -```r -Sys.setenv(VSI_CACHE = "TRUE", VSI_CACHE_SIZE = "100000000") # 100 MB -Sys.setenv(GDAL_HTTP_MAX_RETRY = "3", GDAL_HTTP_RETRY_DELAY = "1") -``` - -This only persists within one R session; the `cd_*` cache above persists -across sessions, which is what kills recurring report-dev egress. - -## Data - -The producer pipeline fetches ERA5-Land hourly reanalysis from -[DestinE Earth Data Hub](https://earthdatahub.destine.eu/), derives -additional variables (VPD, RH, soil moisture), aggregates to monthly, -seasonal, and annual periods on a single EPSG:4326 BC grid, and writes -Cloud-Optimized GeoTIFFs alongside a static SpatioTemporal Asset -Catalog (STAC) in a public S3 bucket. - -- Catalog (JSON): -- Region: BC (~48–60° N, 114–140° W), 1950–2025, ~9 km native grid -- Variables (15): - - **Core climate** (7): tmean, tmax, tmin, prcp, vpd, rh, soil_moisture - - **Snow monthly natives** (4): swe, snowfall, snowmelt, snow_cover - - **Snow annual derived** (4): swe_max, snowfall_fraction, snowmelt_doy_50, snowmelt_rate_peak -- Periods: seasonal (DJF/MAM/JJA/SON) and annual for monthly-native vars; annual only for snow_max / snowfall_fraction / snowmelt_doy_50 / snowmelt_rate_peak - -The catalog is consumable directly outside R — for example, in QGIS via -the STAC plugin, in `gdalcubes`, or with any STAC-aware client. The -`cd_catalog()` consumer function reads the catalog URL by default. - -## Architecture - -cd has a strict producer / consumer split, kept separate so reference periods, baselines, and statistical choices are not baked into the published data: +- [Climate Departure for the FWCP Peace Region](https://newgraphenvironment.github.io/cd/articles/peace-fwcp.html): trends, snowpack and the spatial pattern across a large northern region, by ecoregion and watershed group. +- [Climate Departure for the Kootenay Lake Region](https://newgraphenvironment.github.io/cd/articles/kootenay-lake.html): the same report for the southern Kootenays, where precipitation changes sharply from east to west. +- [How the Weather Has Changed in Three Northern BC Watersheds](https://newgraphenvironment.github.io/cd/articles/northern-bc.html): a short, plain-language story for readers with no climate background. +- [Function reference](https://newgraphenvironment.github.io/cd/reference/) -| Side | Functions | Where it runs | -|---|---|---| -| **Producer** | `cd_fetch()`, `cd_derive()`, `cd_aggregate()`, `cd_cog_write()`, `cd_stac_catalog()`, `cd_stac_item()`, `cd_s3_push()`, plus `scripts/backfill_edh_*.py` and `scripts/pipeline_*_edh.R` | A monthly GitHub Action pulls fresh ERA5-Land data from DestinE EDH, derives variables, writes COGs, rebuilds the STAC catalog, and pushes to `s3://stac-era5-land`. Run by maintainers; users do not need to run it. | -| **Consumer** | `cd_catalog()`, `cd_extract()`, `cd_crop()`, `cd_baseline()`, `cd_anomaly()`, `cd_trend()`, `cd_compare()`, `cd_summary()`, `cd_plot_timeseries()`, `cd_plot_comparison()`, `cd_periods()`, `cd_seasons()`, `cd_cache_*()` | Reads COGs directly via `/vsicurl/` — no credentials, no tile server. All baseline selection and statistical work (Mann-Kendall, Theil-Sen, Welch's t, Mann-Whitney U) happen client-side on the cropped time series. | +## Ecosystem -Anyone can compute climate departure against any baseline period, in any AOI, with whatever statistical test they prefer — without re-publishing the underlying data. +| Package | Role | +|---|---| +| **cd** | Climate departure: baselines, anomalies and trends, and ERA5-Land climate (this package) | +| [wet](https://github.com/NewGraphEnvironment/wet) | Stream flow and water temperature for BC's Freshwater Atlas | -## Roadmap +cd computes the departures from wet's yearly station values. -- **BEC zone shift analysis** ([#59](https://github.com/NewGraphEnvironment/cd/issues/59)) — methodology lit review for biogeoclimatic ecosystem classification (BEC) shifts under climate change, alongside the existing temperature / precipitation+drying / interpretation-framing methodology stacks. -- **Vignette templates** — `peace-fwcp` and `kootenay-lake` are reference implementations of the regional reporting pattern. Future regional vignettes follow the same structure (trends → recent vs pre-warming → spatial → per-ecoregion → snowpack) so cross-region findings are directly comparable. +## Data and methods it builds on +The climate data are [ERA5-Land](https://www.ecmwf.int/en/era5-land) ([Muñoz-Sabater et al. 2021](https://doi.org/10.5194/essd-13-4349-2021)), produced by ECMWF for the Copernicus Climate Change Service and read from the [DestinE Earth Data Hub](https://earthdatahub.destine.eu/). The published layers contain modified Copernicus Climate Change Service information, under CC BY 4.0. Trends are Mann-Kendall tests with Theil-Sen slopes, from the [Kendall](https://cran.r-project.org/package=Kendall) and [zyp](https://cran.r-project.org/package=zyp) packages. cd's core climate variables and its ecoregion and watershed framing follow [`bcgov/bc_climate_anomaly`](https://github.com/bcgov/bc_climate_anomaly), a Shiny app by the Province of British Columbia (Aseem Sharma and contributors). -## Links +## Citation -- [Function reference](https://newgraphenvironment.github.io/cd/reference/) -- Vignettes: - - [Climate Departure for the FWCP Peace Region](https://newgraphenvironment.github.io/cd/articles/peace-fwcp.html) - - [Climate Departure for the Kootenay Lake Region](https://newgraphenvironment.github.io/cd/articles/kootenay-lake.html) - - [How the Weather Has Changed in Three Northern BC Watersheds](https://newgraphenvironment.github.io/cd/articles/northern-bc.html) — a short, plain-language story for readers with no climate background +Cite cd with `citation("cd")`. -## Acknowledgements +## License -This package is inspired by [`bcgov/bc_climate_anomaly`](https://github.com/bcgov/bc_climate_anomaly), a Shiny app developed by the Province of British Columbia (Aseem Sharma and contributors) that visualizes monthly, seasonal, and annual climate anomalies for temperature, precipitation, humidity, vapor pressure, and soil moisture across BC. The variable set and the eco-region / watershed framing in `cd` follow directly from that work. `bc_climate_anomaly` is licensed under the Apache License 2.0. +MIT © New Graph Environment Ltd. See [LICENSE](LICENSE.md). The ERA5-Land data it ships and publishes are CC BY 4.0; see [NOTICE](NOTICE.md). diff --git a/_pkgdown.yml b/_pkgdown.yml index 8d5472f..3cbd06f 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -2,3 +2,45 @@ url: https://newgraphenvironment.github.io/cd/ template: bootstrap: 5 +reference: +- title: Read the data + desc: Climate series for an area, or daily air temperature at points. + contents: + - cd_catalog + - cd_catalog_default + - cd_extract + - cd_extract_daily + - cd_crop +- title: Departures and trends + desc: Compare a series with a baseline or between two windows, test its trend, and tabulate the result. These take any annual series in cd's long format. + contents: + - cd_baseline + - cd_anomaly + - cd_compare + - cd_trend + - cd_summary +- title: Plots + contents: + - cd_plot_timeseries + - cd_plot_comparison +- title: Variables, periods and seasons + contents: + - cd_variables + - cd_periods + - cd_seasons +- title: Cache + desc: Files are cached after the first read and downloaded again only when they are republished. + contents: + - starts_with("cd_cache_") +- title: Publishing the catalog + desc: For maintainers. A scheduled workflow uses these to write the published files and catalog; users do not need them. + contents: + - cd_aggregate + - cd_cog_write + - cd_stac_catalog + - cd_s3_push +- title: Downloading from the Copernicus Climate Data Store + desc: An alternative route to monthly ERA5-Land through the Copernicus Climate Data Store. The published catalog is not built this way. + contents: + - cd_fetch + - cd_derive diff --git a/data-raw/readme_figure.R b/data-raw/readme_figure.R new file mode 100644 index 0000000..70be56e --- /dev/null +++ b/data-raw/readme_figure.R @@ -0,0 +1,51 @@ +# Build the README figure and the output its example shows (#142) +# +# Generates: +# man/figures/readme-kotl-tmean.png (annual mean air temperature departure +# for the Kootenay Lake watershed group, +# with its trend) +# and prints the cd_summary() table pasted under the README example. +# +# The code between the two `README example` markers is the README's example, +# so the figure and the pasted output come from the same run. Run from the +# package root when the catalog gains a year. +# +# Prerequisites: network access to the live catalog. + +Sys.setenv( + GDAL_HTTP_MAX_RETRY = "3", + GDAL_HTTP_RETRY_DELAY = "2" +) + +# The checkout's cd, not an installed one (#135). +pkgload::load_all(export_all = FALSE, quiet = TRUE) + +# --- README example --------------------------------------------------------- +catalog <- cd_catalog() +aoi <- sf::st_read( + system.file("extdata", "example_aoi_kotl.gpkg", package = "cd"), + quiet = TRUE +) + +ts <- cd_extract(catalog, aoi, variables = "tmean", periods = "annual") +bl <- cd_baseline(ts, baseline_years = 1951:1980) +ano <- cd_anomaly(ts, bl) +trn <- cd_trend(ano, trend_start = 1951) + +cd_summary(trn) +# --- end README example ----------------------------------------------------- + +print(cd_summary(trn)) + +p <- cd_plot_timeseries(ano, trend = trn) + + ggplot2::theme_minimal(base_size = 15) + + ggplot2::theme(legend.position = "none") + + ggplot2::labs(y = "Difference from 1951–1980\naverage (°C)") + +out <- "man/figures/readme-kotl-tmean.png" +# png() gives an opaque white background, which survives a dark web page. +grDevices::png(out, width = 7, height = 3.5, units = "in", res = 150, + bg = "white") +print(p) +grDevices::dev.off() +message("Wrote ", out) diff --git a/man/cd-package.Rd b/man/cd-package.Rd index e0fb49b..c5f7fa1 100644 --- a/man/cd-package.Rd +++ b/man/cd-package.Rd @@ -4,11 +4,11 @@ \name{cd-package} \alias{cd} \alias{cd-package} -\title{cd: Climate Departure Analysis from ERA5-Land Reanalysis} +\title{cd: How far any BC watershed's climate has shifted from your chosen baseline} \description{ \if{html}{\figure{logo.png}{options: style='float: right' alt='logo' width='120'}} -Compute climate anomalies from ERA5-Land reanalysis data for custom areas of interest. Producer functions download ERA5-Land monthly means, derive variables (VPD, RH, soil moisture), and publish Cloud-Optimized GeoTIFFs with a static STAC catalog. Consumer functions query the catalog, crop to AOI, compute baselines and anomalies for arbitrary reference periods, and run trend analysis (Mann-Kendall and Theil-Sen). +Measures how far the climate of any area in British Columbia has moved from a chosen reference period: air temperature, precipitation, humidity, soil moisture and snow, by season and year since 1950, with trends (Mann-Kendall and Theil-Sen). Reads ERA5-Land reanalysis from a public STAC catalog of Cloud-Optimized GeoTIFFs, and daily air temperature at points. The baseline, anomaly and trend functions take any annual series, such as streamflow. Includes the functions that build and publish the catalog. Under active development. } \seealso{ Useful links: @@ -20,11 +20,11 @@ Useful links: } \author{ -\strong{Maintainer}: Allan Irvine \email{al@newgraphenvironment.com} (\href{https://orcid.org/0000-0002-3495-2128}{ORCID}) +\strong{Maintainer}: Allan Irvine \email{al@newgraphenvironment.com} (\href{https://orcid.org/0000-0002-3495-2128}{ORCID}) (New Graph Environment Ltd.) Other contributors: \itemize{ - \item New Graph Environment Ltd. [copyright holder] + \item New Graph Environment Ltd. [copyright holder, funder] } } diff --git a/man/figures/readme-kotl-tmean.png b/man/figures/readme-kotl-tmean.png new file mode 100644 index 0000000..8b4c54f Binary files /dev/null and b/man/figures/readme-kotl-tmean.png differ diff --git a/planning/archive/2026-10-issue-142-readme-convention-rewrite/README.md b/planning/archive/2026-10-issue-142-readme-convention-rewrite/README.md new file mode 100644 index 0000000..2b20f07 --- /dev/null +++ b/planning/archive/2026-10-issue-142-readme-convention-rewrite/README.md @@ -0,0 +1,13 @@ +## Outcome + +Rewrote cd's README to soul's `readme.md` convention at the user's direction (simple, plain language, a figure from committed code): a plain opening naming what cd measures and what restoration decision it informs, with daily point temperatures and any-series baselines as one clause each; a figure of the Kootenay Lake watershed group's annual temperature departure from a 1951–1980 baseline, built by `data-raw/readme_figure.R`; one example whose code is that script's marked block and whose output is pasted from the same run. The function table (with the internal `cd_stac_item()`), roadmap, caching section and data inventory came out; the VPD fix stays in NEWS. DESCRIPTION Title/Description, the README tagline and the GitHub About now say the same thing; the citation workflow passes `authors_roles` so New Graph Environment Ltd. becomes a CITATION.cff author; `_pkgdown.yml` groups the reference index in seven sections. Writing attribution for the ERA5-Land data the package ships produced `NOTICE.md`, and reviewing it surfaced bundled data with unconfirmed licences (#151). Learned: a per-file licence list kept failing review because a glob or category stood in for its members (rounds 1–3 each found one inside the previous fix); listing by source, with the unresolved ones pointed at an issue, ended it on an enumeration of the 7 external sources `data-raw/` reads. + +## Measurement + +README 962 → 626 words (`wc -w`, including the example's code and output). No forecast was set; the floor is the convention's fixed sections. Example result: Kootenay Lake (KOTL) annual mean temperature trend 0.025 °C/yr over 75 years (1951–2025), total change 1.9 °C. Review: plan review + 3 code-check rounds, 1 + 5 + 1 + 2 findings; filed #150 (anomaly axis label) and #151 (bundled data licences). + +## Evidence + +`planning/archive/2026-10-issue-142-*/review-*.md` + +Closed by: PR #152 diff --git a/planning/archive/2026-10-issue-142-readme-convention-rewrite/findings.md b/planning/archive/2026-10-issue-142-readme-convention-rewrite/findings.md new file mode 100644 index 0000000..4d9aad3 --- /dev/null +++ b/planning/archive/2026-10-issue-142-readme-convention-rewrite/findings.md @@ -0,0 +1,50 @@ +# Findings — README: add daily point temperatures and any-series consumers; drop internal function (#142) + +## Issue context + +## Problem + +The architecture and data sections are accurate (v0.6.7), but recent consumer capabilities are missing, and one function listed as part of the API is internal. + +## Findings + +**Shipped but not in the README (underselling)** +- Daily point temperatures, `cd_extract_daily()` (v0.6.0), for stream-temperature and degree-day work +- Consumer functions accept any annual series, such as streamflow and stream temperature (v0.5.0) +- Per-file checksums and run provenance (v0.6.3 to v0.6.5) + +**Stale** +- README.md:105 lists `cd_stac_item()` as a producer function; it is internal and not exported +- The quick start uses a toy `1951:1955` baseline (README.md:31); the vignettes use `1951:1980` +- The VPD unit fix (Pa to hPa, v0.6.7) is not mentioned + +## Tasks + +- [ ] Add the shipped capabilities above +- [ ] Remove `cd_stac_item()` from the function list +- [ ] Use a realistic baseline in the quick start +- [ ] Group the `_pkgdown.yml` reference index by purpose. It has no `reference:` sections today, so the docs site shows a flat alphabetical list. + +## Context + +Audited 2026-10-14 against `origin/main` @ `5611c59`, from README, DESCRIPTION, NEWS, NAMESPACE and vignettes. Verify each item against the code before acting. Versions cited are where a capability landed. + +The New Graph website will describe this package from its README (NewGraphEnvironment/newgraphenvironment.github.io#53), so the README is the source of truth for the public one-liner. Plain language in the opening paragraph: what it does today, and what restoration planning, implementation or monitoring decision it informs. + +## Plan-gate notes (2026-10-17) + +- README on main: 962 words (`wc -w`), sections Overview, Installation, Quick start, Caching, Data, Architecture, Roadmap, Links, Acknowledgements. +- `cd_stac_item()` is not in NAMESPACE (confirmed); it appears only in the Architecture table, which the rewrite removes. +- `_pkgdown.yml` has `url` and `template` only, no `reference:`. +- DESCRIPTION `Description` says producer functions "download ERA5-Land monthly means": true of the legacy `cd_fetch()` (CDS), not of the EDH pipeline CI runs. +- `update-citation-cff.yaml` calls `cffr::cff_create()` with default roles, so New Graph Environment Ltd. (`cph`, `fnd`) is not a citation author. +- `example_aoi_kotl.gpkg` is the KOTL watershed group, ~9,339 km². + +## README rewrite (Phase 2) + +- Words: 962 on main -> 593 (`wc -w`, includes the code block and pasted output). No forecast was set; the floor is the convention's fixed sections: opening, figure, install + pin line, example with output, three vignette lines, ecosystem table, data and methods, citation, license. +- Removed: Overview inventory, Caching section (now one sentence), Data inventory (15 variables, extent, years), Architecture function table (with `cd_stac_item()`), Roadmap, Acknowledgements (folded into "Data and methods it builds on"). +- Claims checked against code: catalog periods are annual + four seasons (59 items; no monthly layers), so the opening says "by season and year"; `cd_sha` is "Git commit of the cd code that built the file read" (`R/cd_extract.R:30`, `R/cd_extract_daily.R:90`), hence "commit", not "version"; trends are `Kendall::MannKendall` + `zyp::zyp.sen` (`R/cd_trend.R:74-75`). +- No ERA5-Land / Copernicus attribution existed anywhere in the repo or `catalog.json`; added the C3S "contains modified Copernicus Climate Change Service information" sentence and Muñoz-Sabater et al. 2021 (doi:10.5194/essd-13-4349-2021, resolves to ESSD 13/4349). +- Ecosystem roles copied from wet's README (cd's own row) and link's (wet, gq). +- Mechanical: all 6 functions named are exported; all 15 links return 200. diff --git a/planning/archive/2026-10-issue-142-readme-convention-rewrite/progress.md b/planning/archive/2026-10-issue-142-readme-convention-rewrite/progress.md new file mode 100644 index 0000000..9d38cb9 --- /dev/null +++ b/planning/archive/2026-10-issue-142-readme-convention-rewrite/progress.md @@ -0,0 +1,15 @@ +# Progress — README: add daily point temperatures and any-series consumers; drop internal function (#142) + +## Session 2026-10-17 + +- Plan-mode exploration — phases approved by user (scope widened to a full `readme.md`-convention rewrite at the user's direction) +- Created branch `142-readme-add-daily-point-temperatures-and` off main +- Scaffolded PWF baseline from issue #142 with approved phases +- Next: start Phase 1 +- Phase 1: `data-raw/readme_figure.R` run against the live catalog (07:26 UTC, 4 s with the cache warm). KOTL annual tmean, 1951:1980 baseline: slope 0.025 °C/yr over 75 years, total change 1.9 °C. PNG 1050 x 525, min alpha 1 (opaque); text legible at a ~700 px column. +- Phase 2: README rewritten to the convention, 962 -> 593 words; exports and links checked. +- Phase 3: DESCRIPTION Title/Description and README tagline in step; cffr call passes authors_roles (local cff_create shows New Graph Environment Ltd. as second author); GitHub About set to the tagline (was: "Climate departure analysis from ERA5-Land reanalysis. Producer pipeline publishes monthly-refreshed COGs + STAC catalog for BC; ..."). +- Phase 4: `_pkgdown.yml` reference grouped in six sections (variables/periods/seasons split out of "Read the data" for clarity; `starts_with("cd_cache_")`); `check_pkgdown()` clean; home and reference index built to scratch, figure copied to `reference/figures/`, page screenshot reviewed. +- code-check round 1 (spawned 07:34 UTC): 5 findings, 4 fixed, 1 accepted; filed #150 (anomaly axis label) and #151 (bundled data licences). Tests: FAIL 0 | PASS 768 (6 pre-existing warnings in cd_plot_comparison). +- code-check round 2 (spawned 07:44 UTC): 1 finding, inside round 1's NOTICE fix; fixed by naming files; #151 extended. Enumerated all 18 bundled data files against NOTICE (table in review-round2.md). +- code-check round 3 (spawned 07:50 UTC): mechanism named (a label standing for its members); 2 findings, both from the per-file NOTICE; NOTICE rewritten by source; terminal enumeration of 7 external sources in review-round3.md. diff --git a/planning/archive/2026-10-issue-142-readme-convention-rewrite/review-1.md b/planning/archive/2026-10-issue-142-readme-convention-rewrite/review-1.md new file mode 100644 index 0000000..19fb523 --- /dev/null +++ b/planning/archive/2026-10-issue-142-readme-convention-rewrite/review-1.md @@ -0,0 +1,25 @@ +# Plan review 1 (#142) — Plan agent, 2026-10-17, spawned 07:26 UTC + +Read-only reviewer; findings returned as reply text and transcribed here in summary. 22 items. + +| # | Finding | Disposition | +|---|---|---| +| 1 | Glob selectors `cd_plot_*` / `cd_cache_*` are not valid pkgdown | Already avoided: topics listed, `starts_with("cd_cache_")`; `check_pkgdown()` clean | +| 2 | No NOTICE though repo ships ERA5-Land-derived rasters (`inst/extdata/example_climate.tif`, `example_daily/`, `inst/vignette-data/`) | Fixed: `NOTICE.md`, `NOTICE` added to pkgdown.yaml `allowed` | +| 3 | Example needs sf, Kendall, zyp (Suggests) after a default install | Fixed: one line after Installation | +| 4 | Ecosystem wording: cd row from wet's README; add relationship line | Fixed: "cd computes the departures from wet's yearly station values." (wet README wording) | +| 5 | gq listed but no vignette depends on or calls gq | Fixed: gq row dropped | +| 6 | Copernicus licence/attribution unconfirmed | Confirmed CC-BY-4.0 from CDS catalogue API `collections/reanalysis-era5-land`; sentence kept without a year | +| 7 | Figure y-axis reads "Mean temperature (°C)" on an anomaly plot | Fixed in `data-raw/readme_figure.R` (`labs(y = "Difference from 1951–1980 average (°C)")`); package default filed as an issue | +| 8 | "downloaded once" false: ETag revalidation re-downloads republished files | Fixed: "downloaded again only when they are republished" | +| 9 | Relative `CITATION.cff` link 404s on pkgdown (build-ignored) | Fixed: `citation("cd")` only | +| 10 | About / Title / tagline must be one string | Done in Phase 3 (About read back) | +| 11 | DESCRIPTION + authors_roles in same PR so merge regenerates CITATION.cff | Done (same PR) | +| 12 | NEWS/version for this PR | Left to `/gh-pr-merge` | +| 13 | Example output and figure go stale when 2026 lands | Accepted; script header says re-run when the catalog gains a year | +| 14 | "by season and year" correct | — | +| 15 | Maintainer section mixes legacy `cd_fetch` | Section described as "Building the published data", not "the pipeline" | +| 16 | Scope removals fit the convention | — | +| 17-22 | Acceptance: example == script markers; enumerate claims; links on both renderings; pkgdown checks; About read-back; word counts | Folded into Phase 5 / code-check | + +Also: "version" vs "commit" for `cd_sha` — fixed to "which commit of cd built each file". diff --git a/planning/archive/2026-10-issue-142-readme-convention-rewrite/review-round1.md b/planning/archive/2026-10-issue-142-readme-convention-rewrite/review-round1.md new file mode 100644 index 0000000..7207be2 --- /dev/null +++ b/planning/archive/2026-10-issue-142-readme-convention-rewrite/review-round1.md @@ -0,0 +1,78 @@ +# Code-check round 1: branch 142-readme-add-daily-point-temperatures-and (vs main @ 59a5122) + +Reviewer read every changed file in full, the readme.md and writing.md conventions, the R sources behind each claim, the live catalog and daily manifest, live COG tags, wet's origin/main, bcgov/bc_climate_anomaly. Built the pkgdown home and ran `pkgdown::check_pkgdown()` on a `git archive HEAD` copy in the scratchpad (no problems found; NOTICE.html built; README links rewritten to LICENSE.html / NOTICE.html; no unexpected root pages). Every external link in README.md and NOTICE.md answers 200. + +Disclosure: one `gdalinfo -stats` on `inst/extdata/example_climate.tif` wrote an `.aux.xml` sidecar into the repo. It was deleted right away, and `git status` showed the tree clean afterwards. Nothing else in the repo was touched. + +## Findings + +- **[false-claim, low]** `_pkgdown.yml:46-47` (Cache section): "Each file is downloaded once and read locally after that." `cd_cache_fetch()` revalidates with a HEAD on every call and downloads again when the ETag changes, so a republished file is downloaded again. The README says the opposite, correctly: "downloaded again only when they are republished". Two published texts disagree, and the pkgdown one is wrong. Fix: e.g. "Each file is downloaded once, and again only when it is republished." + +- **[false-claim, low]** `_pkgdown.yml:48-56` ("Building the published data": "The catalog is built and published by a scheduled workflow; users do not need these"). The section lists `cd_fetch()` and `cd_derive()`, and neither is called anywhere in `scripts/`. They are the CDS-based fallback: `cd_fetch` downloads from the Copernicus CDS, and `cd_derive` builds tmax/tmin by its own route, not the local-day route the published layers use. CLAUDE.md says they ship "for users who want a CDS-based fallback, but are not what runs in CI". Under this heading they read as part of what builds the published data, which they are not. Fix: either give them their own line ("an alternative CDS route; not used for the published catalog"), or move them out of the section. `cd_aggregate`, `cd_cog_write`, `cd_stac_catalog` and `cd_s3_push` are used by `pipeline_*_edh.R`, so the claim holds for those. + +- **[false-claim, low]** `README.md:84` "cd's variables and its ecoregion and watershed framing follow bcgov/bc_climate_anomaly". cd has 15 variables, and 8 of them are snow (swe, snowfall, snowmelt, snow_cover, swe_max, snowfall_fraction, snowmelt_doy_50, snowmelt_rate_peak). bc_climate_anomaly's `app.R` has no snow variable: "snow"/"swe" match 0 times, while tmean, tmax, tmin, prcp, vpd, rh and soil all appear. The quantifier covers the whole set, and only the 7 core variables follow it. Fix: "cd's core climate variables …" (or "its temperature, precipitation, humidity and soil-moisture variables"). + +- **[fragile / convention gap, low]** `README.md:88` "Cite cd with `citation("cd")`", together with the `update-citation-cff.yaml` change (commit cfe7745, "NGE as a citation author"). `citation("cd")` reads `inst/CITATION`, whose `author =` keeps only `"aut"` roles. Rendered from this branch's DESCRIPTION it gives "Irvine A (2026). _cd: …_. New Graph Environment Ltd." with NGE only as `organization`, not as an author. After the workflow runs, CITATION.cff will list NGE as an author. The README points readers to the citation that leaves NGE out, which readme.md §9 requires ("Citation from CITATION.cff, with New Graph Environment Ltd. as an author"). link's inst/CITATION is identical, so this is a fleet pattern, not something this branch introduced. Either add `"cph"` to the inst/CITATION filter, or accept it and say so. + +- **[licence gap, low; pre-existing, partly outside #142's NOTICE task]** `NOTICE.md`. The README's License line ("see NOTICE") makes NOTICE the place for third-party data terms, but NOTICE covers only ERA5-Land. Two other gaps: + (a) The package also ships BC government data: FWA watershed groups in `inst/extdata/example_aoi_*.gpkg`, and ecoregions, lakes, rivers, highways, towns and the BC outline in `inst/extdata/context_*.gpkg` (from fwapg and the BC WFS via bcdata, per `data-raw/example_aoi_*.R` and `example_context_*.R`). That data is under the Open Government Licence – British Columbia, which requires an attribution statement, and none is given anywhere. + (b) `inst/extdata/example_climate.tif` is not output of cd's EDH pipeline, which is what NOTICE's paragraph implies. `data-raw/example_climate_tmean.R` crops it from bc_climate_anomaly's `tmean_ano_annual_1950_+_res25.nc`, the Province's processing of CDS ERA5-Land at 0.25° (the file's pixel size is 0.25). bc_climate_anomaly has no licence file (GitHub reports `license: null`). Calling it "modified ERA5-Land data, under CC BY 4.0" is defensible as to the ultimate source, but the Province's intermediate product is not credited. The old README's acknowledgement credited it; the new one credits only the variable framing. + Neither gap makes a sentence in the diff false. Both are real attribution gaps in the file this branch introduces for that purpose. + +## Claims checked (verdict) + +README.md +1. Tagline "Climate departure for BC: how far the climate of any area has moved from any baseline, from ERA5-Land": true. It matches the GitHub About exactly (`gh repo view`), and the DESCRIPTION Title is consistent with it. +2. "air temperature, precipitation, humidity, soil moisture and snow, by season and year since 1950": true. The live catalog has 59 items: 11 variables × {annual, winter, spring, summer, fall} plus 4 annual-only, and every item starts 1950-01-01. +3. "compared with whatever reference period you choose, with the trend and how much it has moved": true (`cd_baseline(baseline_years=)`, `cd_trend`, `cd_summary` Total Change). +4. "public catalog that needs no account": true. `cd_catalog_default()` is the public https S3 URL, and the catalog fetched anonymously. +5. "daily air temperature at any point in the province": true. The cube covers 47.95–60.05 N, 140.05–113.95 W, and the manifest lists 228 files, 1950–2025. Coastal no-data cells move to a neighbour, as documented. +6. "baseline and trend steps take any annual series, such as streamflow or stream temperature": true (`?cd_anomaly` input contract; wet's `wet_window_stats`/`wet_temp_gsdd` feed them). +7. Figure alt "1950 to 2025 … dashed trend line rising about 1.9 degrees": true. The image shows 1950–2025 bars and a dashed line from about −0.35 to about 1.53. The first trend line is dashed (`cd_plot_timeseries`). +8. Caption "Red years were warmer, blue cooler; dashed line is the trend since 1951": true. The fill is `>= 0` → `#d73027`, else `#4575b4`, and `trend_start = 1951`. +9. "The example below also needs sf, Kendall and zyp": true. Only `cd_trend` calls `check_installed(c("Kendall","zyp"))`, sf is needed for `st_read`, and the example does not plot. +10. Pin `@vX.Y.Z`: tags of that form exist (v0.6.12 latest). +11. "This is the run behind the figure above": true. Same code as `data-raw/readme_figure.R` (accepted). +12. Pasted output (Mean temperature, Annual, 0.025, 75, 1.9, °C, 0): consistent with `cd_summary()` (75 = 1951–2025; Total Change = round(slope × n, 1); long_name). Output accepted as a real run. +13. "Files are cached after the first read and downloaded again only when they are republished": true for `cd_extract` (default `cache = TRUE`, ETag revalidation). +14. "Extracted rows record which commit of cd built each file": true. `cd_sha` is read from the file's `CD_SHA` tag, and the live `tmean_annual.tif` and `daily/tmean_daily_1950.tif` both carry `CD_SHA`. All 59 catalog items carry `processing:software.cd`. +15. Learn-more titles and URLs: they match the three `vignettes/*.Rmd` titles and all answer 200. The one-line descriptions are consistent with CLAUDE.md. +16. Ecosystem: wet's role matches wet's About verbatim. "cd computes the departures from wet's yearly station values": true (wet docs and vignette call `cd::cd_baseline/anomaly/trend`). +17. ERA5-Land, ECMWF for C3S, read from EDH: true (producer). The CC BY 4.0 licence is confirmed on the CDS catalogue API (`license: CC-BY-4.0`). The Muñoz-Sabater 2021 DOI resolves. +18. "Mann-Kendall tests with Theil-Sen slopes, from Kendall and zyp": true (`Kendall::MannKendall`, `zyp::zyp.sen`). +19. "cd's variables … follow bc_climate_anomaly": partly false (finding 3). "Shiny app by the Province … (Aseem Sharma and contributors)": consistent (its sole contributor is aseemsharma1, and the app's watermark names the BC Ministry of Forests). +20. Citation via `citation("cd")`: works, but leaves NGE out as an author (finding 4). +21. License "MIT © NGE … ERA5-Land data it ships and publishes are CC BY 4.0": true as far as it goes (finding 5 covers the non-ERA5 data). + +NOTICE.md +22. CC BY 4.0 and the "Contains modified Copernicus Climate Change Service information" wording: true. +23. ERA5-Land reference (ESSD 13, 4349–4383): correct. +24. "reads from EDH, aggregates and derives (seasonal and annual means and totals, VPD, RH, soil moisture, snow metrics, daily local-day air temperature), publishes to s3://stac-era5-land": true for the published data. Not how `example_climate.tif` was made (finding 5b). +25. Redistributed-file list: all three paths exist and are ERA5-Land-derived. No other ERA5-derived data file is tracked (git ls-files). The README figure is derived output, not data. + +DESCRIPTION / man/cd-package.Rd +26. Title and Description: each clause is true (STAC of COGs, daily at points, any annual series, "Includes the functions that build and publish the catalog" = `cd_cog_write`/`cd_stac_catalog`/`cd_s3_push`/`cd_aggregate`, used by the pipelines). The Rd matches DESCRIPTION. + +_pkgdown.yml +27. All 25 exports are indexed, and `check_pkgdown()` finds no problems. +28. "Climate series for an area, or daily air temperature at points": true. +29. Departures desc: true. +30. Cache desc: false (finding 1). +31. Building desc: misleading for cd_fetch/cd_derive (finding 2). + +Workflows +32. `pkgdown.yaml` allowlist + NOTICE: correct. pkgdown renders NOTICE.html, and the guard strips both extensions. +33. `update-citation-cff.yaml` `authors_roles = c("aut","cre","cph")`: cffr 1.4.2 accepts it. Tested on a copy of DESCRIPTION, it yields Irvine plus `name: New Graph Environment Ltd.`, and the title updates. + +data-raw/readme_figure.R +34. Runs from the checkout (`load_all`), opaque white png, and the example block is identical to the README. No defects. The top-level `cd_summary(trn)` autoprints and the table is then printed again, which is harmless. + +## Triage (session) + +| Finding | Disposition | +|---|---| +| pkgdown Cache desc "downloaded once" | Fixed: same wording as README | +| `cd_fetch`/`cd_derive` under "Building the published data" | Confirmed (only a comment in `backfill_edh_all.py:207` names `cd_derive`); split into "Publishing the catalog" and "Downloading from the Copernicus Climate Data Store" | +| "cd's variables follow bc_climate_anomaly" | Fixed: "core climate variables" | +| `citation("cd")` lists NGE as organization, CFF as author | Accepted: `inst/CITATION` pattern shared with link; cross-repo rule in soul#426 territory | +| NOTICE: example_climate.tif not cd's ERA5-Land; BC data unattributed | Fixed: example_climate.tif removed from the ERA5-Land list; FWA + ecoregions attributed under OGL-BC (licences read from the BC Data Catalogue API). GNS towns and DRA highways are "Access Only", and bc_climate_anomaly has no licence: filed #151 | diff --git a/planning/archive/2026-10-issue-142-readme-convention-rewrite/review-round2.md b/planning/archive/2026-10-issue-142-readme-convention-rewrite/review-round2.md new file mode 100644 index 0000000..86d2351 --- /dev/null +++ b/planning/archive/2026-10-issue-142-readme-convention-rewrite/review-round2.md @@ -0,0 +1,79 @@ +# Code-check round 2: branch 142-readme-add-daily-point-temperatures-and (vs main @ 59a5122) + +Reviewer read every changed file in full (README.md, NOTICE.md, DESCRIPTION, man/cd-package.Rd, _pkgdown.yml, data-raw/readme_figure.R, both workflow diffs), viewed the figure, and read soul's readme.md. It checked round 1's four fixes against the code and data. The bundled gpkgs were inspected from copies in the scratchpad: layers and row counts read with sqlite3, provenance traced through data-raw/. The vignette rds files were read with readRDS and hold no sf geometry. BC Data Catalogue licences were read from the CKAN API. All 14 external links in README.md and NOTICE.md answer 200. Nothing in the repo was written except this file. + +## Findings + +- **[false-claim / licence gap, low]** `NOTICE.md:18`: "It also redistributes, in `inst/extdata/example_aoi_*.gpkg` and `inst/extdata/context_*.gpkg`, watershed groups, lakes, rivers and streams from the BC Freshwater Atlas and ecoregions …, under the Open Government Licence – British Columbia." The glob `example_aoi_*.gpkg` matches `example_aoi_fwcp_peace.gpkg`. That file holds neither Freshwater Atlas nor ecoregion data. It is the Fish & Wildlife Compensation Program's Peace Region boundary, read from a local file (`data-raw/example_aoi_fwcp_peace.R`: `~/Projects/gis/sern_peace_fwcp_2023/fwcp_peace_region.geojson`), with no recorded origin or licence. Round 1's fix 4 brought this file under the OGL-BC sentence by glob, so it now reads as OGL-BC data. The other three `example_aoi_*` files are derived from FWA (watershed groups via bcdata/fwapg), which checks out. Suggested fix: add `example_aoi_fwcp_peace.gpkg` to cd#151 beside example_climate.tif, towns and highways. Optionally name the three FWA AOI files in NOTICE rather than globbing. (`example_aoi.gpkg` falls outside the glob, which is correct: it is a plain bbox.) + +No other defects. Round 1's fixes 1–3 are correct as written (verdicts below). + +## Round 1 fixes reviewed + +1. `_pkgdown.yml` Cache desc, "Files are cached after the first read and downloaded again only when they are republished": true. `cd_cache_fetch()` downloads again only on a refresh, or when the ETag differs (size when there is no ETag). With revalidation off, or when the HEAD fails, it serves the local copy. "Only when" is a necessary condition, and the code honours it. The wording matches README.md:52. One edge, pre-existing and outside the diff: the cache key is `rlang::hash(href)`, so an rlang release that changed the hash would re-download unchanged files. Not flagged. +2. "Publishing the catalog" (cd_aggregate, cd_cog_write, cd_stac_catalog, cd_s3_push): each is called by `scripts/pipeline_stage3_edh.R` / `pipeline_update_edh.R`, the scheduled workflow's entry points. True. "Downloading from the Copernicus Climate Data Store" (cd_fetch: CDS monthly means plus daily stats; cd_derive: from cd_fetch's GRIBs): true. "The published catalog is not built this way": true, since neither is called in scripts/ (only a comment in backfill_edh_all.py names cd_derive). +3. README "cd's core climate variables and its ecoregion and watershed framing follow bcgov/bc_climate_anomaly": true. Its app.R names tmean, tmax, tmin, prcp, vpd, rh and soil_moisture, has no snow variable, and mentions watershed 19 times and ecoregion/ecoprovince 25 times. +4. NOTICE redistribution lists: `inst/extdata/example_daily/` comes from cd's own daily cube (`data-raw/example_daily.R`), 2002, so true. `inst/vignette-data/` holds 3 rds files of series and tables (no geometry) and 3 tifs of departures and normals from cd's catalog, so true. The OGL-BC paragraph: FWA Watershed Groups, Lakes, Rivers and Stream Network and the Ecoregion Ecosystem Classification are all "Open Government Licence - British Columbia" in the BC Data Catalogue API, so true for those layers. The `bc` outline in context_northern_bc.gpkg is a union of FWA watershed groups, so it is covered. The attribution sentence is the OGL-BC wording. The one exception is the finding above. Towns and highways are cd#151 (accepted). + +## Claims enumerated (verdict) + +README.md +- Tagline: same text as the GitHub About (`gh repo view`) and consistent with the DESCRIPTION Title. True. +- Opening, "air temperature, precipitation, humidity, soil moisture and snow, by season and year since 1950 … whatever reference period … the trend and how much it has moved": true (variables registry, `cd_baseline(baseline_years=)`, `cd_trend`, Total Change). +- "public catalog that needs no account": true (anonymous https S3). +- "daily air temperature at any point in the province": true (`cd_extract_daily`, cube on the 121 × 261 BC grid). +- "baseline and trend steps take any annual series, such as streamflow or stream temperature": true (`?cd_anomaly` contract; wet feeds them). +- Figure: alt text and caption match the image (1950–2025 bars; red `>= 0`, blue below; dashed trend from about −0.35 to about 1.53 ≈ 1.9; trend since 1951 = `trend_start = 1951`). The opaque white background comes from `png(bg = "white")`. Made by the committed `data-raw/readme_figure.R`. True. +- Install: pak line, a pin placeholder, and a NEWS link (200). "Also needs sf, Kendall and zyp": true. `cd_trend` calls `check_installed(c("Kendall","zyp"))` and the example calls `sf::st_read`. Nothing else in the example needs a Suggests package. +- Example: signatures match (`cd_extract(catalog, aoi, variables, periods)`, `cd_baseline(x, baseline_years)`, `cd_anomaly(x, baseline)`, `cd_trend(x, trend_start)`, `cd_summary(trend)`). The code is identical to the script block. The output was accepted. +- "Files are cached … downloaded again only when they are republished": true (see fix 1). +- "Extracted rows record which commit of cd built each file": true (`cd_sha` from the file's `CD_SHA` tag). +- Learn more: the three titles match `vignettes/*.Rmd` titles, the URLs answer 200, and the descriptions are consistent with the vignettes. True. +- Ecosystem: wet's role is word-for-word as in wet's README and About. cd's row matches wet's README row for cd. "cd computes the departures from wet's yearly station values" is the same sentence wet's README uses. True. +- Data and methods: ERA5-Land by ECMWF for C3S, read from EDH, is true of the producer. CC BY 4.0 and "modified Copernicus … information" are true. Mann-Kendall / Theil-Sen via Kendall and zyp is true. The bc_climate_anomaly sentence is true (fix 3). +- Citation `citation("cd")`: works. The NGE role gap was accepted. +- License: MIT © NGE, and the LICENSE.md and NOTICE.md links exist. The ERA5-Land CC BY 4.0 line is true. example_climate.tif is cd#151, accepted. + +NOTICE.md +- ERA5-Land licence, attribution wording and Muñoz-Sabater 2021 reference (ESSD 13, 4349–4383; the DOI resolves): true. +- "reads from EDH, aggregates and derives (…), publishes to s3://stac-era5-land": true of the published data. +- Redistributed data: see fix 4 and the finding. + +DESCRIPTION / man/cd-package.Rd +- Title and Description: each clause is true. The Rd matches DESCRIPTION. + +_pkgdown.yml +- All 25 NAMESPACE exports are indexed, each exactly once (the `starts_with("cd_cache_")` selector covers 4). +- "Read the data", "Departures and trends", Cache, Publishing and CDS descriptions: true (above). + +Workflows +- `pkgdown.yaml`: "NOTICE" added to the allowlist. Correct, since NOTICE.md renders to NOTICE.html. +- `update-citation-cff.yaml`: `authors_roles = c("aut","cre","cph")` is what readme.md §9 prescribes. + +data-raw/readme_figure.R +- Loads the checkout (`load_all`). `system.file()` resolves to the source inst/ under pkgload, and the PNG is opaque. No defects. + +## Triage (session) + +Finding confirmed (`data-raw/example_aoi_fwcp_peace.R:3,12` reads a local geojson); it sits inside round 1's fix 4, so the loop now ends only on an enumeration. Fix: NOTICE names each OGL file instead of a glob; `example_aoi_fwcp_peace.gpkg` added to #151. + +### Enumeration: every bundled data file (18) against NOTICE + +| File | Source (data-raw) | Licence | In NOTICE | +|---|---|---|---| +| extdata/context_fwcp_peace.gpkg | FWA lakes/rivers/streams/wsgs, ecoregions (OGL); towns GNS, highways DRA (Access Only) | OGL + #151 | yes, minus towns/highways | +| extdata/context_kootenay_lake.gpkg | same layers | OGL + #151 | yes, minus towns/highways | +| extdata/context_northern_bc.gpkg | FWA rivers/lakes, `bc` = union of FWA wsgs; towns GNS | OGL + #151 | yes, minus towns | +| extdata/example_aoi_fwcp_peace.gpkg | local FWCP boundary geojson | unknown | no — #151 | +| extdata/example_aoi_kootenay_lake.gpkg | bcdata FWA watershed groups | OGL | yes | +| extdata/example_aoi_kotl.gpkg | bcdata 51f20b1a (FWA watershed groups) | OGL | yes | +| extdata/example_aoi_northern_bc.gpkg | FWA watershed groups + stream network (fwapg) | OGL | yes | +| extdata/example_aoi.gpkg | hand-made bbox | none (own) | n/a | +| extdata/example_catalog.json | STAC metadata for example_climate.tif | none (own) | n/a | +| extdata/example_climate.tif | bc_climate_anomaly NetCDF | unknown | no — #151 | +| extdata/example_daily/{tmean,tmax,tmin}_daily_2002.tif (3) | cd daily cube (ERA5-Land) | CC BY 4.0 | yes | +| extdata/peace_wsg_ecoregion_commentary.csv | overlap % computed from bundled wsgs × ecoregions, plus authored text | own, derived from OGL | covered by OGL statement | +| vignette-data/*.tif (3) | cd catalog (ERA5-Land) | CC BY 4.0 | yes | +| vignette-data/*.rds (3) | cd extracts (ERA5-Land) + AOI names/areas from FWA/ecoregions | CC BY 4.0 + OGL | yes | + +Every file is either named in NOTICE under a verified licence, own work, or in #151. Nothing listed in NOTICE carries data outside its stated licence. diff --git a/planning/archive/2026-10-issue-142-readme-convention-rewrite/review-round3.md b/planning/archive/2026-10-issue-142-readme-convention-rewrite/review-round3.md new file mode 100644 index 0000000..8060638 --- /dev/null +++ b/planning/archive/2026-10-issue-142-readme-convention-rewrite/review-round3.md @@ -0,0 +1,79 @@ +# Code-check round 3: branch 142-readme-add-daily-point-temperatures-and (vs main @ 59a5122) + +The reviewer read README.md, NOTICE.md, DESCRIPTION, _pkgdown.yml, data-raw/readme_figure.R, the diffs to man/cd-package.Rd and both workflows, and viewed the figure. Every gpkg was inspected from a copy in the scratchpad (layers, columns and row counts via sqlite3). Each bundled file was traced to its `data-raw/` script. The vignette rds files were read with readRDS. The live daily cube was read over /vsicurl/ into a scratch R session. Nothing in the repo was written except this file. + +## Mechanism + +All five earlier findings share one assumption: **a label or a category (a glob, a group heading, a familiar member) was taken to stand for its members, and nothing checked the members.** "downloaded once" described the usual cache path. A "Building the published data" heading took in a function the pipeline never calls. "cd's variables" was written from the core seven. A NOTICE line about "cd's ERA5-Land product" took in a file from another source. `example_aoi_*.gpkg` matched by name and not by content. + +Round 2's fix applied the same assumption one level down. It treated **the FWCP boundary as one file**, `example_aoi_fwcp_peace.gpkg`, and moved that file to #151. But the boundary is also geometry, and geometry flows into whatever is clipped or masked by it. The enumeration table follows each file's *source tables*, not the *geometry operations* applied to them. So any file whose content was cut by a boundary of a different licence is labelled with its source tables' licence alone. + +## Findings + +- **[false-claim, low] `NOTICE.md:21`**: "`inst/extdata/context_fwcp_peace.gpkg` … (every layer except `towns` and `highways`)" under OGL-BC. In that file, `rivers`, `streams` and `ecoregions` are **clipped to the FWCP Peace boundary**, the very boundary round 2 moved to #151 as of unknown licence: + - `data-raw/example_context_fwcp_peace.R:19` reads `example_aoi_fwcp_peace.gpkg`. + - `:62-70` builds rivers as `ST_Intersection(geom, )`. + - `:76-82` builds streams the same way. + - `:130-131` builds ecoregions as `st_intersection(ecoregions_bc, aoi_3005)`, and `area_km2` is the clipped area. + + The outer edges of those three layers *are* the FWCP boundary, so the file redistributes it inside layers NOTICE labels OGL-BC. `lakes` (bbox `ST_Intersects`, not clipped) and `wsgs` (selected by a code list, not clipped) are pure FWA. Downstream of the clipped ecoregions are `inst/extdata/peace_wsg_ecoregion_commentary.csv` (`data-raw/peace_wsg_ecoregion_commentary.R:23,32` intersects with that layer) and `inst/vignette-data/peace_fwcp.rds`. The boundary also reaches `inst/vignette-data/peace_fwcp_departure_tmean.tif`, which NOTICE lists only as modified ERA5-Land: it is `terra::mask(departure, aoi)` with `aoi` = the FWCP boundary (`data-raw/peace_fwcp_vignette_data.R:30-31,137`). #151 names only `example_aoi_fwcp_peace.gpkg`. + + Suggested fix: in NOTICE, list `context_fwcp_peace.gpkg` as `lakes` and `wsgs` only, or add "clipped to the FWCP Peace boundary (see #151)". Extend #151's FWCP bullet to the files that carry the boundary: the clipped layers in `context_fwcp_peace.gpkg`, the masked `peace_fwcp_departure_tmean.tif`, and the derived `peace_wsg_ecoregion_commentary.csv` and `peace_fwcp.rds`. + +- **[false-claim, low] `planning/active/review-round2.md` enumeration, and `NOTICE.md:16-22` coverage.** The table closes with "Every file is either named in NOTICE under a verified licence, own work, or in #151". Three rows contradict it: + - `peace_wsg_ecoregion_commentary.csv` reads "covered by OGL statement", but NOTICE's OGL list does not name it. + - `vignette-data/*.rds` reads "CC BY 4.0 + OGL / yes", but NOTICE names `inst/vignette-data/` only under ERA5-Land. `kootenay_lake.rds$wsg_eco_overlap` and the ecoregion `area_km2` values are computed from FWA and ecoregion geometry. + - `vignette-data/*.tif` reads CC BY only, but each is masked to an AOI. Two of those AOIs are FWA-derived (OGL) and one is FWCP (above). + + So NOTICE's "in:" lists omit OGL-derived content in the csv and in vignette-data. The closing OGL attribution sentence is present, so the practical gap is small. The table header's "(18)" is also wrong: its rows cover 20 data files (21 under `inst/` with `inst/CITATION`). All 20 have a row, so the population is complete. + +No other defects. + +## Where the mechanism reaches, checked place by place + +| Place | Claim about a set | Members checked | Verdict | +|---|---|---|---| +| NOTICE:3 | "cd's climate data are derived from ERA5-Land" | example_climate.tif is not | accepted (#151) | +| NOTICE:9 | derived variables list | registry: means/totals, vpd, rh, soil, snow metrics, daily | true | +| NOTICE:13 | example_daily/ = ERA5-Land daily 2002 | 3 tifs, `data-raw/example_daily.R` | true | +| NOTICE:14 | vignette-data = modified ERA5-Land | 3 tif (cd_crop of the catalog), 3 rds (no sf geometry; all classes read) | true, but they also carry OGL/FWCP-derived content (finding 2) | +| NOTICE:20 | 3 example_aoi files = watershed groups and watersheds | kootenay_lake = union of 4 FWA WSGs; kotl = FWA WSG (bcdc 51f20b1a); northern_bc = 3 WSGs + 2 Bulkley parts (FWA watershed at measure) | true | +| NOTICE:21 | context_* every layer except towns/highways | kootenay_lake: clipped by the FWA AOI, so OGL; northern_bc: rivers, lakes, `bc` from FWA; fwcp_peace: rivers/streams/ecoregions clipped by FWCP | **false for fwcp_peace** (finding 1) | +| README:9 | "air temperature, precipitation, humidity, soil moisture and snow … since 1950" | 15 variables; one contiguous span | true | +| README:9 | "daily air temperature at any point in the province" | live cube 2002 band 1, 20,000 random points in FWA-BC: 220 fall in no-data cells, 9 have no data in the 3×3 window (0.045%); `cd_extract_daily` documents the fallback and the NA warning | true in substance | +| README:9 / DESCRIPTION | baseline and trend steps take any annual series | `?cd_anomaly` contract | true | +| README:46 | "Files are cached after the first read" | `cd_extract(cache = TRUE)` and `cd_extract_daily(cache = TRUE)` defaults; `cd_cache_fetch` ETag | true | +| README:46 | "Extracted rows record which commit … built each file" | `cd_sha` from the file's `CD_SHA` tag in both extractors | true | +| README:73 | Mann-Kendall / Theil-Sen from Kendall and zyp | `R/cd_trend.R:74-75` | true | +| README:73 | core variables follow bc_climate_anomaly | R2 verified | true | +| README:81 | "The ERA5-Land data it ships and publishes are CC BY 4.0" | ERA5-derived files only | true | +| README fig/caption/alt | 1950–2025, red warmer / blue cooler, trend since 1951, ~1.9 | PNG viewed; slope 0.025 × 75 years | true | +| _pkgdown "Read the data" | series for an area, or daily at points | 5 functions | true | +| _pkgdown "Departures and trends" | "These take any annual series in cd's long format" | cd_summary takes a trend table, cd_anomaly takes a series plus a baseline | true as a chain reading; not flagged | +| _pkgdown Cache | revalidation wording | R2 verified | true | +| _pkgdown Publishing | the scheduled workflow uses these | cd_aggregate and cd_cog_write in stage3 and update; cd_stac_catalog; cd_s3_push (also pushes the daily cube via `_publish.R:274`) | true | +| _pkgdown CDS | not how the catalog is built | not called in scripts/ | true | +| DESCRIPTION / Rd | each clause | as above | true; the Rd matches | +| pkgdown.yaml allowlist | adds NOTICE | NOTICE.md renders to NOTICE.html | correct | +| update-citation-cff | `authors_roles =` | cffr 1.4.2 has the argument; the workflow installs current cffr | correct | +| Pin advice | `@vX.Y.Z` | tags are `v0.6.x` | true | + +## Triage (session) + +Both findings confirmed against `data-raw/example_context_fwcp_peace.R` and `peace_fwcp_vignette_data.R`. The per-file NOTICE kept gaining qualifiers (convention: consider dropping the claim), so NOTICE now makes no per-file claims: it names each **source** with its licence, and points unresolved ones to #151. #151's FWCP bullet widened to every file clipped or masked to the boundary. + +### Terminal enumeration: every external source read by `data-raw/` (7) + +From a grep of every `bcdc_query_geodata()`, `FROM `, `st_read()`, `rast()`, `cd_catalog()`/`cd_extract*()` call in `data-raw/example_*.R`, `*_vignette_data.R` and `peace_wsg_ecoregion_commentary.R` (the vignette and commentary scripts read only cd and the bundled gpkgs): + +| Source | Read by | NOTICE row | +|---|---|---| +| ERA5-Land (cd catalog, daily cube) | example_daily, *_vignette_data | CC BY 4.0 | +| FWA wsgs/lakes/rivers/streams (bcdata, fwapg) | example_aoi_*, example_context_* | OGL-BC | +| Ecoregions `d00389e0` | example_context_fwcp_peace, _kootenay_lake | OGL-BC | +| GNS geographical names | example_context_* | #151 | +| DRA `transport_line` | example_context_fwcp_peace, _kootenay_lake | #151 | +| FWCP boundary (local geojson) | example_aoi_fwcp_peace (+ files clipped/masked to it) | #151 | +| bc_climate_anomaly NetCDF | example_climate_tmean | #151 | + +7 of 7 sources have a NOTICE row. `example_aoi.gpkg` and `example_catalog.json` are hand-made. Loop ends on this enumeration. diff --git a/planning/archive/2026-10-issue-142-readme-convention-rewrite/review-round4.md b/planning/archive/2026-10-issue-142-readme-convention-rewrite/review-round4.md new file mode 100644 index 0000000..4a03ea2 --- /dev/null +++ b/planning/archive/2026-10-issue-142-readme-convention-rewrite/review-round4.md @@ -0,0 +1,40 @@ +# Review round 4 — HEAD f6c4a21 (Title / tagline / About, #142) + +Reviewed 2026-10-17. Scope: is "How far any BC watershed's climate has shifted from your +chosen baseline" true against the code, and does the new Title break anything mechanical. + +## Findings + +**[Low]** DESCRIPTION:2, README.md:7 — "any BC watershed" does not hold for a watershed on a +small offshore island. `cd_crop()` (R/cd_crop.R:36) is `terra::crop(snap = "out", mask = TRUE)` +and `cd_extract()` (R/cd_extract.R:77) takes `global(mean, na.rm = TRUE)`; ERA5-Land is +land-only, so 10,835 of the 31,581 cells in the live `tmean_annual` COG are NA. Measured: +a 0.01° polygon inland near Squamish (-123.01, 49.61) returns 1.76 °C for 1950 (sub-cell +inland watersheds are fine, the touched cell counts), while a 0.02° polygon on Triangle +Island (-129.08, 50.86) returns `NaN`, silently, with no warning. Not new to this commit: +the DESCRIPTION `Description` and the README opening already say "any area", so the Title +inherits the same overstatement. Whether a watershed in the Freshwater Atlas sits entirely +on sea cells was not checked. Acceptable as is for a one-line tagline; noted so the +silent `NaN` is a known limit, not a surprise. + +## Checked and clean + +- `cd_extract()`: takes any `sf`/`sfc`/`SpatVector` polygon, reprojects if the CRS differs + (R/cd_crop.R:30-35). True for any polygon on land. +- `cd_baseline()`: any `baseline_years` vector; years outside the data warn, not error + (R/cd_baseline.R:31-40). "your chosen baseline" holds. +- Extent: grid 47.95–60.05 N, 140.05–113.95 W covers all of BC. "climate" = temperature, + precipitation, humidity (rh, vpd), soil moisture and snow, per `cd_variables()`. +- `read.dcf("DESCRIPTION")` parses; `tools:::.check_package_description()` returns no + problems; `tools::checkRd("man/cd-package.Rd")` is silent (an apostrophe is not special in Rd). +- `inst/CITATION` evaluates to title "cd: How far any BC watershed's climate has shifted + from your chosen baseline"; BibTeX output well formed. +- cffr (the workflow's own recipe, written to a scratch path): YAML writes `''` for the + apostrophe, `yaml::read_yaml()` round-trips it, `cff_validate()` TRUE for both `title` + and `preferred-citation$title`. The committed CITATION.cff still carries an older title + ("Climate Departure Analysis…"), which predates this commit and the workflow regenerates + on the next push to main touching DESCRIPTION. +- pkgdown home (built to a scratch destination): `… • cd` and `og:title` + carry the new Title, apostrophe intact inside double-quoted attributes. +- GitHub About matches the Title exactly (`gh repo view`). +- No stale copy of the previous Title outside `planning/archive/` and `docs/`. diff --git a/planning/archive/2026-10-issue-142-readme-convention-rewrite/task_plan.md b/planning/archive/2026-10-issue-142-readme-convention-rewrite/task_plan.md new file mode 100644 index 0000000..e59f2de --- /dev/null +++ b/planning/archive/2026-10-issue-142-readme-convention-rewrite/task_plan.md @@ -0,0 +1,47 @@ +# Task: README: add daily point temperatures and any-series consumers; drop internal function (#142) + +The architecture and data sections are accurate (v0.6.7), but recent consumer capabilities are missing, and one function listed as part of the API is internal. + +Scope set at the plan gate (2026-10-17): rewrite the README to soul's `readme.md` convention — simple, plain language, a figure from committed code, not too much detail. Function tables, roadmap, caching section and the data inventory come out; the VPD unit fix stays in NEWS. + +## Phase 1: Figure from committed code + +- [x] `data-raw/readme_figure.R` (local only, `pkgload::load_all()`): live catalog, `example_aoi_kotl.gpkg` (Kootenay Lake watershed group, ~9,300 km²), annual tmean, `cd_baseline(1951:1980)` -> `cd_anomaly()` -> `cd_trend(trend_start = 1951)` -> `cd_plot_timeseries()`; writes `man/figures/readme-kotl-tmean.png` (opaque white background) and prints the `cd_summary()` table for the README example +- [x] Check the PNG at its published width (~700 px column): type legible, no transparency + +## Phase 2: README rewrite, in the convention's order + +- [x] Title line with hex sticker (`alt` text added), lifecycle-experimental badge, one-line tagline +- [x] Opening: what cd is (how far BC's climate has moved from a chosen baseline, for any area), the data (ERA5-Land reanalysis since 1950, served as a public self-updating catalog, no credentials), what it informs (which watersheds are warming or losing snow, for restoration planning and monitoring); one clause each for daily point temperatures (stream-temperature and degree-day work), any annual series (streamflow, stream temperature), and each value naming the file build it came from +- [x] Figure + alt text + one-line caption +- [x] Installation, then the "under active development / see NEWS / pin `@vX.Y.Z`" line +- [x] Example: the Phase 1 code with a `1951:1980` baseline, shown with its real pasted `cd_summary()` output; one sentence that files are cached after first read +- [x] Learn more: one line per vignette (peace-fwcp, kootenay-lake, northern-bc), then the function reference +- [x] Ecosystem: cd, wet (and gq only if a vignette uses it), roles worded as in link's README +- [x] Data and methods it builds on: ERA5-Land (Copernicus/ECMWF) via DestinE Earth Data Hub with the Copernicus attribution sentence, Mann-Kendall / Theil-Sen, and the `bcgov/bc_climate_anomaly` inspiration (replaces Acknowledgements) +- [x] Citation (points to `CITATION.cff` / `citation("cd")`) and License +- [x] Record word count before/after in findings.md + +## Phase 3: Texts that travel with the README + +- [x] DESCRIPTION `Title` in step with the tagline; `Description` in step with the opening (drops the stale "download ERA5-Land monthly means"), ends "Under active development."; `devtools::document()` +- [x] `update-citation-cff.yaml`: `cff_create(authors_roles = c("aut", "cre", "cph"))` so New Graph Environment Ltd. is a citation author +- [x] GitHub About via `gh repo edit NewGraphEnvironment/cd --description "…"`, same words as the tagline + +## Phase 4: Grouped reference index + +- [x] `_pkgdown.yml` `reference:` sections: Read the data (`cd_catalog`, `cd_catalog_default`, `cd_crop`, `cd_extract`, `cd_extract_daily`, `cd_variables`, `cd_periods`, `cd_seasons`); Departures and trends (`cd_baseline`, `cd_anomaly`, `cd_compare`, `cd_trend`, `cd_summary`); Plots (`cd_plot_*`); Cache (`cd_cache_*`); Publishing the data, for maintainers (`cd_fetch`, `cd_derive`, `cd_aggregate`, `cd_cog_write`, `cd_stac_catalog`, `cd_s3_push`) +- [x] `pkgdown::check_pkgdown()` clean; `pkgdown::build_home()` locally and look at the rendered page and figure + +## Phase 5: Close out + +- [x] Edit #142's body: scope is the convention rewrite; VPD fix left to NEWS +- [x] Mechanical checks: every function the README names is exported; every link resolves +- [x] `/code-check branch` with every README/DESCRIPTION claim enumerated against code + +## Validation + +- [x] Tests pass +- [x] `/code-check` clean (each commit, or once over the branch with `/code-check branch`) +- [x] PWF checkboxes match landed work +- [x] `/planning-archive` on completion