R package bycatch (v0.8.0) — seabird bycatch risk assessment.
Maintainer: IslasGECI.
| Command | What it does |
|---|---|
make tests |
Run all tests (devtools::test) |
make coverage |
Run tests + generate HTML coverage report (sends to codecov) |
make format |
Auto-format R/ and tests/ with styler |
make check |
Check formatting only (no auto-fix) — CI fails if unformatted |
make setup |
make clean → devtools::install → check → build → document |
make clean |
Remove *.tar.gz, tests/testthat/_snaps, NAMESPACE |
make install |
Install deps, run checks, build package, update docs (devtools::install → check → build → document) |
make tests_file file=<path> |
Run a single test file (no commit/restore) |
make mutants |
Placeholder (not yet implemented) |
Note:
devtoolsis only available inside Docker. Run tests viadocker exec bycatch_code_ci make tests. The suite takes ~12 minutes. Fast tests (~37s) can be run withmake tests_fast, which skips the slow tests intests/testthat/slow/. Slow tests requiremake tests(ormake tests_slow). After changing any file inR/, rebuild the package withdocker exec bycatch_code_ci make install— the container has a stale installed version by default.Slow test timing (individual files, via
testthat::test_file):
Test file Runtime test_compute_potential_kba.R6m 28s test_render_potential_kba.R5m 0s test_render_representative_assessment.R34s test_render_individual_kde.R23s The two longest tests (
compute_potential_kba,render_potential_kba) both callfindSiteinternally, which is the main bottleneck with 10 individuals andpolyOut=TRUE.make tests_filedoes not work for files inslow/; usetestthat::test_file()directly instead.
make red— format tests, run them. If they fail → stagetests/testthat/*.R→ commit. If they pass →git restore .make green— format R/, run tests. If they pass → stageR/*.R→ commit. If they fail →git restore .make refactor— format both, run tests. If pass → stage all → commit. If fail →git restore .make red_file file=pathetc. — single-file TDD cycle.
All three always run format first (via styler).
When the Makefile targets are too rigid, phases can be managed manually:
- Make changes (test or production code).
- Stage relevant files with
git add. - Run tests via
docker exec bycatch_code_ci make tests. - If tests fail, adjust and repeat. If tests pass, commit.
This gives explicit control over staging boundaries and commit messages.
When renaming a function (no behavioral change):
- Update the test to call the new name.
- Run tests — they should fail (cannot find new name in production).
- Rename the production code.
- Run tests — they should pass.
- Commit both changes together.
This is test-first for renames: the test drives the rename by calling a name that does not exist yet. Every rename follows this Red → Green cycle.
When removing a feature that is no longer needed:
- Remove dead production code.
- Run tests — they should fail (Red-like state).
- Remove the corresponding test(s).
- Run tests — they should pass (Green-like state).
- Commit both changes together.
This is the inverse of test-first: production code is removed first, then the test is removed to restore Green. It is a cleanup cycle distinct from the three standard phases.
Three documents define the architecture:
- Arquitectura en niveles y capas — 3 levels (Level 1 Pure, Level 1 I/O, Level 2 Artifact).
- Guía de estilo — naming conventions for each level.
- Desacoplamiento de análisis y visualización — create_/render_ split, no render_* computes.
| Prefix | Level | Role |
|---|---|---|
compute_* |
1 Pure | In-memory calculation, no I/O |
plot_* |
1 Pure | In-memory ggplot2, no I/O |
.name (dot prefix) |
2 Helper | Private helper called only by Level 2 |
create_* |
2 Artifact | Read → compute → write (exported) |
render_* |
2 Artifact | Read → plot → write (exported) |
get_domain_specific_options |
— | Exported exception (CLI helper) |
R does not allow identifiers starting with underscore. Use dot prefix for private helpers (.adapt_config).
- Level 1 Pure (
compute_*,plot_*): never read/write files, never call Level 1 I/O. - Level 1 I/O (
read_*,write_*,import_*,export_*): only disk I/O, no computation. Third-party I/O calls (readr::read_csv,sf::st_write,ggsave) are used directly by Level 2 — no wrappers. - Level 2 (
create_*,render_*): compose Level 1 functions. Only Make orchestrates Level 2 calls — they never call each other.
sf_use_s2(FALSE) is self-managed by compute_* functions. Pattern:
previous_s2_setting <- sf::sf_use_s2(FALSE)
on.exit(sf::sf_use_s2(previous_s2_setting))plot_* never sets S2 (they only use ggplot2). create_*/render_* are completely unaware of S2 state.
Colony is kept only inside compute_* calls to track2KBA algorithms (tripSplit, tripSummary). plot_* and render_* never receive or use colony.
R/— 6 files. Entrypoint:cli.R(Level 2 functions:create_*,render_*,.adapt_config). Compute layer:representative_assess.R(R6 classTrack2KBA_Wrapper+ standalonecompute_*functions),track_example.R(compute_trips,compute_trips_summary),fisheries_process.R(compute_filtered_*),get_kernels.R(compute_scale_parameters). Exception:get_domain_specific_options.R.tests/testthat/— 9 fast + 4 slow inslow/. Usestestthatedition 3 +testtoolshelpers for file-existence assertions.- Fast:
test_compute_individual_kde.R,test_compute_representative_assessment.R,test_compute_cache.R,test_cli.R,test_fisheries_process.R,test_get_domain_specific_options.R,test_kernels.R,test_representative_assess.R,test_track_example.R. - Slow:
slow/test_compute_potential_kba.R,slow/test_render_*.R.
- Fast:
tests/data/— CSV and RDS fixtures. Paths hardcoded as/workdir/tests/data/…(Docker convention).tests/src/— One-off scripts (e.g.,create_test_fixtures.R). Not part of the test suite.NAMESPACE— roxygen2-generated. Deleted bymake clean, regenerated bymake setup. 8 exported functions.man/— 7.Rdfiles (roxygen2-generated).track2kba/— Read-only reference clone ofBirdLifeInternational/track2kba(master branch, clean checkout). Not a git submodule. Not modified. Used to inspect and study the external package source without depending on GitHub availability. The actual dependency is installed from GitHub viaDESCRIPTIONRemotes:.DESCRIPTION— 4 remote dependencies:BirdLifeInternational/track2kba,IslasGECI/gecioptparse,IslasGECI/testtools,r-quantities/units.
test_representative_assess.RdefinesWrapper_Tester(inheritsTrack2KBA_Wrapperwith emptyinitialize) for isolated unit tests.make tests_file file=<path>runs a single test file without commit/restore.- Coverage script:
tests/testthat/coverage.R(usescovr, sends to codecov). - All paths in tests are
/workdir/…— to run outside Docker, symlink or adjust paths.
tests/src/create_test_fixtures.Rgenerates.rdsfixture files intests/data/. Not part of the test suite — run once, commit the.rdsfiles. Rerun when test fixtures need regeneration:docker exec bycatch_code_ci Rscript tests/src/create_test_fixtures.R.- The script calls internal
compute_*functions viabycatch:::(e.g.,bycatch:::compute_individual_kde()). Internal functions are never exported; usebycatch:::outside the package namespace.
GitHub Actions (.github/workflows/actions.yml): docker build → make check → make coverage → make mutants → push Docker images to Docker Hub. Everything runs inside Docker.
Each commit message follows this format:
- Gitmoji prefix matching the change type (🔥 remove, 🗑️ deprecate, 📝 docs, 🧩 🚧 small step or a bigger plan, etc.).
- Imperative verb immediately after the gitmoji.
- Summary under 72 characters.
- Blank second line.
- Body explains motivation (why, not what). Avoid restating the diff.
- No Conventional Commits prefixes (
feat:,fix:, etc.).
- Formatting:
styleris mandatory.make checkenforces it in CI. - Docs: roxygen2 with
markdown = TRUE. Rundevtools::document()(ormake install) to regenerateNAMESPACEandman/*.Rd.NAMESPACEis gitignored;man/files are untracked. Roxygen2#'tags inR/*.Rare the source of truth — generated files are never committed manually. - OO pattern: R6 classes (not S3/S4) for stateful workflows like
Track2KBA_Wrapper. Being gradually replaced by standalonecompute_*functions (Phase 2, Sprint 6). - Compute/plot layer:
compute_*functions are pure (no I/O, no side effects), return lists or data.frames.plot_*functions are pure, return ggplot2 objects. Disk I/O lives only in exportedcreate_*/render_*functions inR/cli.R. - Cache design: Only
repAssessoutput is cached (two data.frames:assessment_summary,assessment_detail). KDE_surface, UDPolygons, and tracks are fast to recompute and never cached. Colony is used internally bycompute_individual_kdebut never returned or cached. - Spatial:
sf_use_s2(FALSE)is self-managed bycompute_*functions (save, set, restore on exit).plot_*andcreate_*/render_*are unaware of S2 state. Colony is removed from all presentation layers. - C++: C++17 via
.R/Makevars. - License: AGPL-3.0-or-later.