From 991dc2d2ba4ed819531a742916c9d78593ec7c7c Mon Sep 17 00:00:00 2001 From: Jon Harmon Date: Fri, 15 May 2026 08:59:02 -0500 Subject: [PATCH 1/2] Update ai & condition infrastructure --- .github/skills/create-issue/SKILL.md | 11 ++++-- .github/skills/r-code/SKILL.md | 6 +-- .github/skills/tdd-workflow/SKILL.md | 27 ++++++++++++- DESCRIPTION | 5 ++- R/aaa-conditions.R | 58 ++++++++++++++++++++++++++-- man/dot-pkg_abort.Rd | 12 ++++-- man/dot-pkg_inform.Rd | 40 +++++++++++++++++++ man/dot-pkg_warn.Rd | 40 +++++++++++++++++++ 8 files changed, 182 insertions(+), 17 deletions(-) create mode 100644 man/dot-pkg_inform.Rd create mode 100644 man/dot-pkg_warn.Rd diff --git a/.github/skills/create-issue/SKILL.md b/.github/skills/create-issue/SKILL.md index d5a19b8..8a5762d 100644 --- a/.github/skills/create-issue/SKILL.md +++ b/.github/skills/create-issue/SKILL.md @@ -13,14 +13,14 @@ If `gh` is not authenticated, stop and ask the user to authenticate before conti ## Looking up IDs -The hardcoded IDs below are correct for this repo as of 2026-05-11 21:33:53 UTC. If they ever change, or if you're working in a fork, re-run these queries to get fresh values: +The hardcoded IDs below are correct for this repo as of 2026-05-15 13:57:23 UTC. If they ever change, or if you're working in a fork, re-run these queries to get fresh values: ```bash # Repository node ID -gh api graphql -f query='{ repository(owner: "jonthegeek", name: "beekeeper") { id } }' +gh api graphql -f query='{ repository(owner: "api2r", name: "beekeeper") { id } }' # Available issue type IDs -gh api graphql -f query='{ repository(owner: "jonthegeek", name: "beekeeper") { issueTypes(first: 20) { nodes { id name description } } } }' +gh api graphql -f query='{ repository(owner: "api2r", name: "beekeeper") { issueTypes(first: 20) { nodes { id name description } } } }' ``` ## Issue type @@ -29,6 +29,11 @@ Choose the type that best fits the issue: | Type | ID | Use for | |---|---|---| +| Task | `IT_kwDOCPuMJs4BPtRZ` | A specific piece of work | +| Bug | `IT_kwDOCPuMJs4BPtRc` | An unexpected problem or behavior | +| Feature | `IT_kwDOCPuMJs4BPtRe` | A request, idea, or new functionality | +| Documentation | `IT_kwDOCPuMJs4B5OL_` | Explanations of how or why to do things | +| Infrastructure | `IT_kwDOCPuMJs4B5OMn` | Infrastructure of a project, like GitHub Actions | ## Issue title diff --git a/.github/skills/r-code/SKILL.md b/.github/skills/r-code/SKILL.md index 70350d8..707e335 100644 --- a/.github/skills/r-code/SKILL.md +++ b/.github/skills/r-code/SKILL.md @@ -6,7 +6,7 @@ description: Guide for writing R code. Use when writing new functions, designing # R code -This skill covers how to design and write R functions — including naming conventions, signatures, API conventions, input validation, error handling, and common pitfalls. For documenting functions, use the `document` skill. For tests, use the `tdd-workflow` skill. +This skill covers how to design and write R functions — including naming conventions, signatures, API conventions, input validation, condition handling, and common pitfalls. For documenting functions, use the `document` skill. For tests, use the `tdd-workflow` skill. ## Naming conventions @@ -184,9 +184,9 @@ Keep a function internal when: Internal helpers use a dot prefix (e.g. `.parse_response()`). -## Error handling +## Condition handling -Use `.pkg_abort()` (defined in `R/aaa-conditions.R`) rather than calling `cli::cli_abort()` directly. This wraps `stbl::pkg_abort()` and ensures consistent error class formatting: +Use `.pkg_abort()`, `.pkg_warn()`, and `.pkg_inform()` (defined in `R/aaa-conditions.R`) rather than calling `cli::cli_abort()`, `cli::cli_warn()`, or `cli::cli_inform()` directly. These wrap `stbl` condition helpers and ensure consistent class formatting: ```r .pkg_abort( diff --git a/.github/skills/tdd-workflow/SKILL.md b/.github/skills/tdd-workflow/SKILL.md index a480565..2fd5a3c 100644 --- a/.github/skills/tdd-workflow/SKILL.md +++ b/.github/skills/tdd-workflow/SKILL.md @@ -133,8 +133,31 @@ test_that("process_data() errors on empty input (#42)", { }) ``` -Pass `transform = stbl::.transform_path(path)` to scrub volatile values (e.g. temp -paths) from the snapshot before comparison. +**Warnings thrown by this package** (via `.pkg_warn()`) should be tested with +`stbl::expect_pkg_warning_snapshot()`: + +```r +test_that("process_data() warns on dropped rows (#42)", { + stbl::expect_pkg_warning_snapshot( + process_data(data.frame(value = c(1, NA))), + "beekeeper", + "dropped_rows" + ) +}) +``` + +**Messages thrown by this package** (via `.pkg_inform()`) should be tested with +`stbl::expect_pkg_message_snapshot()`: + +```r +test_that("process_data() informs on defaults used (#42)", { + stbl::expect_pkg_message_snapshot( + process_data(data.frame(value = 1)), + "beekeeper", + "used_defaults" + ) +}) +``` **Errors thrown by `stbl`** (via `stbl::to_*()` / `stbl::stabilize_*()`) should be tested with `stbl::expect_pkg_error_classes()`. Since the message diff --git a/DESCRIPTION b/DESCRIPTION index bd5d47f..025c358 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -28,7 +28,7 @@ Imports: rprojroot, S7, snakecase, - stbl (>= 0.3.0), + stbl (>= 0.3.0.9000), stringr, testthat, tibble, @@ -49,7 +49,8 @@ VignetteBuilder: knitr Remotes: api2r/nectar, - api2r/rapid + api2r/rapid, + wranglezone/stbl Config/roxygen2/version: 8.0.0 Config/testthat/edition: 3 Encoding: UTF-8 diff --git a/R/aaa-conditions.R b/R/aaa-conditions.R index 1e416a3..87fe352 100644 --- a/R/aaa-conditions.R +++ b/R/aaa-conditions.R @@ -1,4 +1,4 @@ -#' Raise a package-scoped error +#' Signal a package-scoped error #' #' @inheritParams .shared-params #' @inheritParams stbl::pkg_abort @@ -7,8 +7,9 @@ .pkg_abort <- function( message, subclass, - call = rlang::caller_env(), - message_env = rlang::caller_env(), + parent = NULL, + call = caller_env(), + message_env = caller_env(), ... ) { stbl::pkg_abort( @@ -17,6 +18,57 @@ subclass, call = call, message_env = message_env, + parent = parent, + ... + ) +} + +#' Signal a package-scoped warning +#' +#' @inheritParams .shared-params +#' @inheritParams stbl::pkg_warn +#' @returns `NULL`, invisibly (called for warning side effect). +#' @keywords internal +.pkg_warn <- function( + message, + subclass, + parent = NULL, + call = caller_env(), + message_env = caller_env(), + ... +) { + stbl::pkg_warn( + "beekeeper", + message, + subclass, + call = call, + message_env = message_env, + parent = parent, + ... + ) +} + +#' Signal a package-scoped message +#' +#' @inheritParams .shared-params +#' @inheritParams stbl::pkg_inform +#' @returns `NULL`, invisibly (called for message side effect). +#' @keywords internal +.pkg_inform <- function( + message, + subclass, + parent = NULL, + call = caller_env(), + message_env = caller_env(), + ... +) { + stbl::pkg_inform( + "beekeeper", + message, + subclass, + call = call, + message_env = message_env, + parent = parent, ... ) } diff --git a/man/dot-pkg_abort.Rd b/man/dot-pkg_abort.Rd index a9b46ce..85a8870 100644 --- a/man/dot-pkg_abort.Rd +++ b/man/dot-pkg_abort.Rd @@ -2,13 +2,14 @@ % Please edit documentation in R/aaa-conditions.R \name{.pkg_abort} \alias{.pkg_abort} -\title{Raise a package-scoped error} +\title{Signal a package-scoped error} \usage{ .pkg_abort( message, subclass, - call = rlang::caller_env(), - message_env = rlang::caller_env(), + parent = NULL, + call = caller_env(), + message_env = caller_env(), ... ) } @@ -19,6 +20,9 @@ formatted with \code{\link[cli:cli_bullets]{cli::cli_bullets()}}.} \item{subclass}{(\code{character}) Class(es) to assign to the error. Will be prefixed by "\{package\}-error-".} +\item{parent}{A parent condition, as you might create during a +\code{\link[rlang:try_fetch]{rlang::try_fetch()}}. See \code{\link[rlang:abort]{rlang::abort()}} for additional information.} + \item{call}{(\code{environment}) The caller environment for error messages.} \item{message_env}{(\code{environment}) The execution environment to use to @@ -31,6 +35,6 @@ evaluate variables in error messages.} Does not return. } \description{ -Raise a package-scoped error +Signal a package-scoped error } \keyword{internal} diff --git a/man/dot-pkg_inform.Rd b/man/dot-pkg_inform.Rd new file mode 100644 index 0000000..bdaa0aa --- /dev/null +++ b/man/dot-pkg_inform.Rd @@ -0,0 +1,40 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/aaa-conditions.R +\name{.pkg_inform} +\alias{.pkg_inform} +\title{Signal a package-scoped message} +\usage{ +.pkg_inform( + message, + subclass, + parent = NULL, + call = caller_env(), + message_env = caller_env(), + ... +) +} +\arguments{ +\item{message}{(\code{character}) The message for the new message condition. +Messages will be formatted with \code{\link[cli:cli_bullets]{cli::cli_bullets()}}.} + +\item{subclass}{(\code{character}) Class(es) to assign to the message. Will be +prefixed by "\{package\}-message-".} + +\item{parent}{A parent condition, as you might create during a +\code{\link[rlang:try_fetch]{rlang::try_fetch()}}. See \code{\link[rlang:abort]{rlang::abort()}} for additional information.} + +\item{call}{(\code{environment}) The caller environment for error messages.} + +\item{message_env}{(\code{environment}) The execution environment to use to +evaluate variables in error messages.} + +\item{...}{Additional parameters passed to \code{\link[cli:cli_abort]{cli::cli_inform()}} and on to +\code{\link[rlang:abort]{rlang::inform()}}.} +} +\value{ +\code{NULL}, invisibly (called for message side effect). +} +\description{ +Signal a package-scoped message +} +\keyword{internal} diff --git a/man/dot-pkg_warn.Rd b/man/dot-pkg_warn.Rd new file mode 100644 index 0000000..b20532f --- /dev/null +++ b/man/dot-pkg_warn.Rd @@ -0,0 +1,40 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/aaa-conditions.R +\name{.pkg_warn} +\alias{.pkg_warn} +\title{Signal a package-scoped warning} +\usage{ +.pkg_warn( + message, + subclass, + parent = NULL, + call = caller_env(), + message_env = caller_env(), + ... +) +} +\arguments{ +\item{message}{(\code{character}) The message for the new warning. Messages will +be formatted with \code{\link[cli:cli_bullets]{cli::cli_bullets()}}.} + +\item{subclass}{(\code{character}) Class(es) to assign to the warning. Will be +prefixed by "\{package\}-warning-".} + +\item{parent}{A parent condition, as you might create during a +\code{\link[rlang:try_fetch]{rlang::try_fetch()}}. See \code{\link[rlang:abort]{rlang::abort()}} for additional information.} + +\item{call}{(\code{environment}) The caller environment for error messages.} + +\item{message_env}{(\code{environment}) The execution environment to use to +evaluate variables in error messages.} + +\item{...}{Additional parameters passed to \code{\link[cli:cli_abort]{cli::cli_warn()}} and on to +\code{\link[rlang:abort]{rlang::warn()}}.} +} +\value{ +\code{NULL}, invisibly (called for warning side effect). +} +\description{ +Signal a package-scoped warning +} +\keyword{internal} From 04b2510cfda5123fa1aec5dbea88ae11d2b0865e Mon Sep 17 00:00:00 2001 From: Jon Harmon Date: Fri, 15 May 2026 09:05:47 -0500 Subject: [PATCH 2/2] Namespace `caller_env()` --- R/aaa-conditions.R | 12 ++++++------ man/dot-pkg_abort.Rd | 4 ++-- man/dot-pkg_inform.Rd | 4 ++-- man/dot-pkg_warn.Rd | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/R/aaa-conditions.R b/R/aaa-conditions.R index 87fe352..4ce7af5 100644 --- a/R/aaa-conditions.R +++ b/R/aaa-conditions.R @@ -8,8 +8,8 @@ message, subclass, parent = NULL, - call = caller_env(), - message_env = caller_env(), + call = rlang::caller_env(), + message_env = rlang::caller_env(), ... ) { stbl::pkg_abort( @@ -33,8 +33,8 @@ message, subclass, parent = NULL, - call = caller_env(), - message_env = caller_env(), + call = rlang::caller_env(), + message_env = rlang::caller_env(), ... ) { stbl::pkg_warn( @@ -58,8 +58,8 @@ message, subclass, parent = NULL, - call = caller_env(), - message_env = caller_env(), + call = rlang::caller_env(), + message_env = rlang::caller_env(), ... ) { stbl::pkg_inform( diff --git a/man/dot-pkg_abort.Rd b/man/dot-pkg_abort.Rd index 85a8870..47c00d4 100644 --- a/man/dot-pkg_abort.Rd +++ b/man/dot-pkg_abort.Rd @@ -8,8 +8,8 @@ message, subclass, parent = NULL, - call = caller_env(), - message_env = caller_env(), + call = rlang::caller_env(), + message_env = rlang::caller_env(), ... ) } diff --git a/man/dot-pkg_inform.Rd b/man/dot-pkg_inform.Rd index bdaa0aa..03836d8 100644 --- a/man/dot-pkg_inform.Rd +++ b/man/dot-pkg_inform.Rd @@ -8,8 +8,8 @@ message, subclass, parent = NULL, - call = caller_env(), - message_env = caller_env(), + call = rlang::caller_env(), + message_env = rlang::caller_env(), ... ) } diff --git a/man/dot-pkg_warn.Rd b/man/dot-pkg_warn.Rd index b20532f..3e7a38d 100644 --- a/man/dot-pkg_warn.Rd +++ b/man/dot-pkg_warn.Rd @@ -8,8 +8,8 @@ message, subclass, parent = NULL, - call = caller_env(), - message_env = caller_env(), + call = rlang::caller_env(), + message_env = rlang::caller_env(), ... ) }