Skip to content

Enable all remaining linters#294

Merged
sbfnk merged 10 commits intomainfrom
enable-cyclocomp-linter
Feb 27, 2026
Merged

Enable all remaining linters#294
sbfnk merged 10 commits intomainfrom
enable-cyclocomp-linter

Conversation

@sbfnk-bot
Copy link
Collaborator

@sbfnk-bot sbfnk-bot commented Feb 25, 2026

This PR closes #293.

Removes the four "extra exclusion" linters from .lintr that were marked as
"should ideally be removed at some point":

  • cyclocomp_linter (default threshold 15) — reduced complexity of
    check.contact_survey() (21→11), [.contact_survey (17→9), and
    find_unique_key() (17→8) by extracting helper functions. Excluded
    contact_matrix(), download_survey(), and try_merge_additional_files()
    via nolint (too large/deprecated to tackle here).

  • object_usage_linter — works correctly with the existing roxyglobals
    setup (only 3 false positives from cli string interpolation, suppressed with
    nolint). Removed one genuinely unused assignment in deprecated code.

  • line_length_linter (default 80 chars) — wrapped long roxygen @param
    descriptions, code comments, cli messages, test descriptions, and vignette
    code across ~23 files. One unavoidable long line (comma-separated deprecated
    param names in contact_matrix.R) excluded via nolint.

  • indentation_linter — fixed 4 indentation issues across 3 files.

Summary by CodeRabbit

  • New Features

    • Survey filtering by expressions (e.g., polymod[country == "United Kingdom"]).
  • Bug Fixes

    • Improved preprocessing for participant/contact ages and more consistent age-group assignment.
    • Centralised age validation with clearer warnings.
  • Refactor

    • Internal simplifications to filtering and key-detection logic to reduce duplication.
  • Documentation

    • Extensive reflow and clarity improvements across docs, help pages, examples, vignettes, and tests.
  • Chores

    • Enabled additional linters and updated linting configuration.

Co-authored-by: sbfnk <sebastian.funk@lshtm.ac.uk>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 25, 2026

Important

Review skipped

This PR was authored by the user configured for CodeRabbit reviews. By default, CodeRabbit skips reviewing PRs authored by this user. It's recommended to use a dedicated user account to post CodeRabbit review feedback.

To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds small helper functions, refactors age-column/key-resolution logic, introduces preprocessing and validation steps for contact age-group assignment, scopes nolint markers, reorders .lintr entries, and applies widespread documentation, test, and vignette reflowing. No public function signatures changed.

Changes

Cohort / File(s) Summary
Linter config & NEWS
\.lintr, NEWS.md
Reordered/cleaned .lintr (moved backport_linter("3.5.0"), added comment on indentation_linter); documented enabled/disabled linters in NEWS.md.
Age-group preprocessing & imputation
R/assign-age-groups.R
Added steps to convert contact factor columns to integers, handle invalid/missing contact ages (drop_invalid_contact_ages, drop_missing_contact_ages), adjust participant age-group breaks, and explicitly create/apply age_breaks/age_groups before assigning contact age groups.
Cyclomatic complexity refactors
R/check.R, R/subset-contact-survey.R, R/load-survey-utils.R
Extracted helpers check_age_column, resolve_filter_target, and find_pair_key; replaced duplicated/complex inline logic in check.contact_survey, [.contact_survey, and find_unique_key.
Load / survey utilities & messaging
R/load-survey-utils.R
Refactored find_unique_key to delegate pair-key search to find_pair_key; added lint-scoped regions and adjusted CLI messaging/line-continuations for longitudinal/merge blocks.
Scoped nolint & small helpers
R/checkers.R, R/deprecated.R
Added targeted # nolint directives around complex/legacy regions and a nolint on a constructed warning string; removed an unused temporary assignment in download_survey.
R source docs & tiny simplifications
R/*.R (e.g., R/as_contact_survey.R, R/clean.R, R/contact-matrix-utils.R, R/contact_matrix.R, R/new_contact_survey.R, R/pop_age.R, R/survey.R, R/utils.R, R/wpp_age.R, ...)
Extensive roxygen reflowing and wording/formatting edits; occasional removal of intermediate assignments/returns; no functional changes.
Man pages
man/*.Rd (add_age.Rd, as_contact_survey.Rd, check.Rd, clean.Rd, contact_matrix.Rd, get_survey.Rd, matrix_plot.Rd, new_contact_survey.Rd, pop_age.Rd, survey.Rd, wpp_age.Rd)
Line-wrapping and formatting changes only; semantics unchanged.
Tests & snapshots
tests/testthat/*, tests/testthat/_snaps/matrix.md
Shortened/reworded test descriptions and snapshot headers; formatting-only changes, assertions preserved.
Vignettes
vignettes/intro.qmd, vignettes/socialmixr.Rmd
Reflowed code examples to multi-line, indented calls; no behavioral changes.

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I nibbled through tangled code with a hop and a twitch,
Pulled helpers from burrows to make branches less rich.
Docs fluffed like fur, tests trimmed with a twitchy paw,
Linters wake, carrots offered — I celebrate with a gnaw! 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Enable all remaining linters' is clear and directly summarizes the main objective of the PR, which is to enable the four remaining disabled linters (cyclocomp_linter, object_usage_linter, line_length_linter, and indentation_linter) with corresponding code fixes throughout the codebase.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (3)
tests/testthat/test-matrix.r (2)

1141-1153: Formatting and description update for symmetric norm test — also flagged by air.

The test description is clearer now. Note that the air formatter suggested slightly different formatting for the contact_matrix() calls on lines 1144–1146 and 1149–1151.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/testthat/test-matrix.r` around lines 1141 - 1153, Update the formatting
of the two contact_matrix(...) calls inside the test_that("symmetric matrices
with large norm weights warn", ...) to match the air formatter suggestions:
place each argument on its own line with consistent indentation and no trailing
commas/spaces so the calls for expect_snapshot_warning(contact_matrix(...)) and
expect_warning(contact_matrix(...)) mirror each other and are aligned; keep the
same arguments (survey = polymod, age_limits = c(0, 90), symmetric = TRUE) and
preserve the use of expect_snapshot_warning and expect_warning and the test_that
description.

47-51: Indentation changes conflict with air formatter suggestions.

The air formatter (reviewdog) has already flagged different indentation preferences for these lines. You may want to reconcile with the air suggestions or suppress them if intentionally diverging.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/testthat/test-matrix.r` around lines 47 - 51, Indentation of the
multi-line logical expression is inconsistent with the air formatter; fix the
continuation indentation for the expression involving
polymod11$participants$part_age and polymod11$participants$dayofweek so that
logical operators and parentheses are aligned per air rules (put the binary
operators at the end of the preceding lines and align subsequent lines with the
opening parenthesis), e.g. reflow the two clauses so both
"(polymod11$participants$part_age %in% ... & polymod11$participants$dayofweek
%in% ...)" blocks have consistent indentation and operator placement; run the
air formatter (or reviewdog) to verify the change.
R/check.R (1)

95-97: ⚠️ Potential issue | 🟠 Major

format-suggest blocker still present in wrapped conditions.

These condition blocks still differ from the formatter/reviewdog suggestion and are likely the CI blocker reported in this PR.

🧩 Suggested formatting fix
-  if (
-    !(id.column %in%
-        colnames(x$participants) &&
-        id.column %in% colnames(x$contacts))
-  ) {
+  if (
+    !(
+      id.column %in% colnames(x$participants) &&
+      id.column %in% colnames(x$contacts)
+    )
+  ) {
@@
-  if (!check_age_column(
-    x$participants, participant.age.column, "Participant"
-  )) {
+  if (
+    !check_age_column(
+      x$participants,
+      participant.age.column,
+      "Participant"
+    )
+  ) {
@@
-  if (!check_age_column(x$contacts, contact.age.column, "Contact")) {
+  if (
+    !check_age_column(
+      x$contacts,
+      contact.age.column,
+      "Contact"
+    )
+  ) {

As per coding guidelines: **/*.{R,r} “Run lintr::lint_package() to check for style issues and fix any in files you modified before committing”.

Also applies to: 106-113

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@R/check.R` around lines 95 - 97, The boolean expression using id.column and
colnames(x$participants)/colnames(x$contacts) is line-wrapped in a way that
violates the formatter; reformat the condition so the entire negation and
logical AND are split across lines consistently (for example place the opening
parenthesis after ! and put each operand on its own indented line with the && at
the end or start as your style guide requires), apply the same formatting fix to
the similar block that references id.column, colnames(x$participants) and
colnames(x$contacts) later, and run lintr::lint_package() to ensure the style
passes CI.
🧹 Nitpick comments (2)
tests/testthat/test-agegroups.r (1)

112-112: Minor: test description lost the (brackets) qualifier.

The (brackets) suffix was removed (likely for line length), but the test at line 114 specifically tests notation = "brackets". The companion test at line 119 still says (dashes). The asymmetry is slightly confusing but not a functional issue.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/testthat/test-agegroups.r` at line 112, Update the test description
string for the test_that("agegroups_to_limits round-trips with
limits_to_agegroups", ...) to include the qualifier "(brackets)" so it matches
the fact that this test calls agegroups_to_limits/limits_to_agegroups with
notation = "brackets"; keep the companion test that mentions "(dashes)"
unchanged. This ensures the test name reflects the specific notation parameter
used and removes the asymmetry between the two related tests.
tests/testthat/test-plot.r (1)

26-35: Consider de-duplicating these two legend tests.

Both blocks currently test the same call; either merge them or make one cover a distinct case to keep test intent sharper.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/testthat/test-plot.r` around lines 26 - 35, The two tests in
tests/testthat/test-plot.r both call matrix_plot(dta$matrix, min.legend = 4,
max.legend = 40) and are redundant; either merge them into a single test (keep
one of the test_that blocks, remove the duplicate) or change one to exercise a
different legend scenario (e.g., different min.legend/max.legend or ad-hoc vs
default legend) so they validate distinct behavior—update the test names
("contact matrix can be plotted with ad-hoc legend" and "contact matrix plotted
with ad-hoc legend values") accordingly and keep the pdf()/dev.off() wrappers
around the single consolidated or modified test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@man/contact_matrix.Rd`:
- Around line 128-130: The documentation for the weights argument contains a
typo: change "column names(s)" to "column name(s)" (or "column names") in the
description for the weights parameter (the \item{weights}{...} entry) so the
user-facing Rd text reads correctly and clearly; update the text inside the
\item{weights} block in man/contact_matrix.Rd accordingly.
- Line 174: The rendered help contains a leaked lint directive text "# nolint
line_length_linter."—remove that token from the roxygen source comment that
documents contact_matrix (the block listing deprecated args like survey.pop,
age.limits, sample.participants, etc.), then regenerate the Rd file by running
devtools::document() so the cleaned text is emitted; ensure only the deprecation
badge/text remains in the roxygen comment and no inline "# nolint" tokens are
present in the source roxygen block for contact_matrix.

In `@R/matrix_plot.R`:
- Around line 30-33: The roxygen docs for parameters xlab and ylab state
defaults with “(years)” but the function implementation (parameters xlab and
ylab in matrix_plot) uses “(year)”; update the docblock to match the code by
changing the default strings in the `@param` descriptions to use “(year)” so the
documented defaults match the implementation (or alternatively change the
function defaults to “(years)” if you prefer that plural form) — ensure the
`@param` lines for xlab and ylab and the actual default values in the matrix_plot
function are identical.

In `@tests/testthat/_snaps/matrix.md`:
- Line 232: Update the snapshot heading text that currently reads "# warning if
day of week weigh requested but not present" to correct the typo: change "weigh"
to "weight" so it reads "# warning if day of week weight requested but not
present"; locate the exact header string in the snapshot file and make this
single-word correction to keep wording consistent.

---

Duplicate comments:
In `@R/check.R`:
- Around line 95-97: The boolean expression using id.column and
colnames(x$participants)/colnames(x$contacts) is line-wrapped in a way that
violates the formatter; reformat the condition so the entire negation and
logical AND are split across lines consistently (for example place the opening
parenthesis after ! and put each operand on its own indented line with the && at
the end or start as your style guide requires), apply the same formatting fix to
the similar block that references id.column, colnames(x$participants) and
colnames(x$contacts) later, and run lintr::lint_package() to ensure the style
passes CI.

In `@tests/testthat/test-matrix.r`:
- Around line 1141-1153: Update the formatting of the two contact_matrix(...)
calls inside the test_that("symmetric matrices with large norm weights warn",
...) to match the air formatter suggestions: place each argument on its own line
with consistent indentation and no trailing commas/spaces so the calls for
expect_snapshot_warning(contact_matrix(...)) and
expect_warning(contact_matrix(...)) mirror each other and are aligned; keep the
same arguments (survey = polymod, age_limits = c(0, 90), symmetric = TRUE) and
preserve the use of expect_snapshot_warning and expect_warning and the test_that
description.
- Around line 47-51: Indentation of the multi-line logical expression is
inconsistent with the air formatter; fix the continuation indentation for the
expression involving polymod11$participants$part_age and
polymod11$participants$dayofweek so that logical operators and parentheses are
aligned per air rules (put the binary operators at the end of the preceding
lines and align subsequent lines with the opening parenthesis), e.g. reflow the
two clauses so both "(polymod11$participants$part_age %in% ... &
polymod11$participants$dayofweek %in% ...)" blocks have consistent indentation
and operator placement; run the air formatter (or reviewdog) to verify the
change.

---

Nitpick comments:
In `@tests/testthat/test-agegroups.r`:
- Line 112: Update the test description string for the
test_that("agegroups_to_limits round-trips with limits_to_agegroups", ...) to
include the qualifier "(brackets)" so it matches the fact that this test calls
agegroups_to_limits/limits_to_agegroups with notation = "brackets"; keep the
companion test that mentions "(dashes)" unchanged. This ensures the test name
reflects the specific notation parameter used and removes the asymmetry between
the two related tests.

In `@tests/testthat/test-plot.r`:
- Around line 26-35: The two tests in tests/testthat/test-plot.r both call
matrix_plot(dta$matrix, min.legend = 4, max.legend = 40) and are redundant;
either merge them into a single test (keep one of the test_that blocks, remove
the duplicate) or change one to exercise a different legend scenario (e.g.,
different min.legend/max.legend or ad-hoc vs default legend) so they validate
distinct behavior—update the test names ("contact matrix can be plotted with
ad-hoc legend" and "contact matrix plotted with ad-hoc legend values")
accordingly and keep the pdf()/dev.off() wrappers around the single consolidated
or modified test.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 253c381 and 033c9a1.

📒 Files selected for processing (39)
  • .lintr
  • NEWS.md
  • R/as_contact_survey.R
  • R/assign-age-groups.R
  • R/check.R
  • R/checkers.R
  • R/clean.R
  • R/contact-matrix-utils.R
  • R/contact_matrix.R
  • R/deprecated.R
  • R/lists.R
  • R/load-survey-utils.R
  • R/matrix_plot.R
  • R/new_contact_survey.R
  • R/pop_age.R
  • R/subset-contact-survey.R
  • R/survey.R
  • R/utils.R
  • R/wpp_age.R
  • man/add_age.Rd
  • man/as_contact_survey.Rd
  • man/check.Rd
  • man/clean.Rd
  • man/contact_matrix.Rd
  • man/get_survey.Rd
  • man/matrix_plot.Rd
  • man/new_contact_survey.Rd
  • man/pop_age.Rd
  • man/survey.Rd
  • man/wpp_age.Rd
  • tests/testthat/_snaps/matrix.md
  • tests/testthat/test-agegroups.r
  • tests/testthat/test-convert-factor-to-integer.R
  • tests/testthat/test-matrix.r
  • tests/testthat/test-plot.r
  • tests/testthat/test-survey-country-population.R
  • tests/testthat/test-weigh.R
  • vignettes/intro.qmd
  • vignettes/socialmixr.Rmd

Co-authored-by: sbfnk <sebastian.funk@lshtm.ac.uk>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
R/check.R (1)

1-31: cli_warn message: missing \\ continuation and call parameter

Two minor inconsistencies in check_age_column's cli_warn (lines 25–29):

  1. Raw newlines in the format string. The string spans multiple source lines without \\ line-continuations. Unlike every other multi-line cli_warn/cli_abort in this file (e.g. lines 86–88, 100–103, 122–124) which use \\ to produce a single paragraph, this string contains embedded \n characters and leading spaces on the continuation lines that will appear verbatim in the rendered warning.

  2. Missing call parameter. All warning helpers in checkers.R accept and forward call = rlang::caller_env() so that the warning points to the user-facing call site. check_age_column omits this, so the warning will appear to originate from check_age_column itself rather than from check.contact_survey. Since the function is @noRd, adding a call parameter keeps it consistent and forward-compatible if it is reused elsewhere.

♻️ Proposed fix
+check_age_column <- function(df, age_column, label,
+  call = rlang::caller_env()) {
   if (age_column %in% colnames(df)) {
     return(TRUE)
   }

   exact_col <- paste(age_column, "exact", sep = "_")
   min_col <- paste(age_column, "est_min", sep = "_")
   max_col <- paste(age_column, "est_max", sep = "_")

   if (
     (exact_col %in% colnames(df)) ||
       (min_col %in% colnames(df) && max_col %in% colnames(df))
   ) {
     return(TRUE)
   }

   cli::cli_warn(
-    "{label} age column {.arg {age_column}} or columns to
-   estimate {tolower(label)} age ({.arg {exact_col}} or {.arg {min_col}}
-   and {.arg {max_col}}) do not exist in the {tolower(label)} data frame."
+    "{label} age column {.arg {age_column}} or columns to estimate \\
+    {tolower(label)} age ({.arg {exact_col}} or {.arg {min_col}} \\
+    and {.arg {max_col}}) do not exist in the {tolower(label)} data frame.",
+    call = call
   )
   FALSE
 }

Then forward call at the two call sites in check.contact_survey:

-  if (!check_age_column(x$participants, participant.age.column, "Participant")) {
+  if (!check_age_column(x$participants, participant.age.column, "Participant",
+    call = rlang::caller_env())) {

-  if (!check_age_column(x$contacts, contact.age.column, "Contact")) {
+  if (!check_age_column(x$contacts, contact.age.column, "Contact",
+    call = rlang::caller_env())) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@R/check.R` around lines 1 - 31, The cli::cli_warn in check_age_column uses a
multi-line string with raw newlines and missing the standard call forwarding;
update the cli::cli_warn call in check_age_column to use backslash
line-continuations (\"\\\") so the message is a single paragraph and add call =
rlang::caller_env() to the cli::cli_warn invocation. Then, in
check.contact_survey where check_age_column is invoked, forward the caller
environment by passing call = rlang::caller_env() (or otherwise propagate the
call argument) so warnings point to the user-facing call site.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@R/load-survey-utils.R`:
- Around line 273-279: The nolint markers are mispaired causing cyclocomp
suppression (started earlier at the first "# nolint start: cyclocomp_linter.")
to close too early; update the block around the construction of key_code (in the
try_merge_additional_files / load-survey-utils.R code) so that the "# nolint
start: object_usage_linter." paired with its corresponding "# nolint end" does
not close the cyclocomp suppression prematurely — either move the second "#
nolint end" to after the end of the try_merge_additional_files block (after the
code that follows key_code) so the two starts/end markers pair correctly, or
replace the block-level markers with per-line "# nolint" annotations on the
specific lines (e.g., the key_code lines) to avoid mispairing.

---

Nitpick comments:
In `@R/check.R`:
- Around line 1-31: The cli::cli_warn in check_age_column uses a multi-line
string with raw newlines and missing the standard call forwarding; update the
cli::cli_warn call in check_age_column to use backslash line-continuations
(\"\\\") so the message is a single paragraph and add call = rlang::caller_env()
to the cli::cli_warn invocation. Then, in check.contact_survey where
check_age_column is invoked, forward the caller environment by passing call =
rlang::caller_env() (or otherwise propagate the call argument) so warnings point
to the user-facing call site.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 033c9a1 and 56d5f62.

📒 Files selected for processing (12)
  • R/check.R
  • R/checkers.R
  • R/clean.R
  • R/contact_matrix.R
  • R/load-survey-utils.R
  • R/matrix_plot.R
  • R/new_contact_survey.R
  • R/survey.R
  • man/contact_matrix.Rd
  • man/matrix_plot.Rd
  • tests/testthat/test-matrix.r
  • tests/testthat/test-survey-country-population.R
✅ Files skipped from review due to trivial changes (2)
  • tests/testthat/test-survey-country-population.R
  • man/contact_matrix.Rd
🚧 Files skipped from review as they are similar to previous changes (5)
  • man/matrix_plot.Rd
  • R/survey.R
  • R/new_contact_survey.R
  • R/contact_matrix.R
  • tests/testthat/test-matrix.r

sbfnk-bot and others added 2 commits February 25, 2026 13:52
Co-authored-by: sbfnk <sebastian.funk@lshtm.ac.uk>
Co-authored-by: sbfnk <sebastian.funk@lshtm.ac.uk>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
R/check.R (1)

9-10: ⚠️ Potential issue | 🔴 Critical

Fix check_age_column signature formatting — pipeline is failing because of this.

The # nolint: indentation_linter. comment suppresses lintr, but the format-suggest.yaml pipeline runs the air formatter, which has its own formatting rules and is not affected by nolint. The pipeline error at lines 9–15 will keep blocking until the signature is reformatted to the style air expects (one argument per line, closing paren on its own line).

🔧 Proposed fix (matches the air formatter's suggestion from the previous review)
-check_age_column <- function(df, age_column, label,
-  call = rlang::caller_env()) { # nolint: indentation_linter.
+check_age_column <- function(
+  df,
+  age_column,
+  label,
+  call = rlang::caller_env()
+) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@R/check.R` around lines 9 - 10, The function signature for check_age_column
is currently on a single line with a trailing "# nolint: indentation_linter."
which the air formatter rejects; reformat the signature to one argument per line
with the closing parenthesis on its own line (e.g. split df, age_column, label,
and call = rlang::caller_env() each onto separate lines) and remove or relocate
the nolint comment so the air formatter can accept the style; ensure the
function name check_age_column and the default argument call =
rlang::caller_env() remain unchanged.
🧹 Nitpick comments (1)
R/check.R (1)

99-100: Avoid nolint workaround — reformat the compound condition instead.

The two # nolint: indentation_linter. suppressions exist only because the logical expression inside !(... && ...) isn't broken at a point that satisfies the indentation linter. Restructuring the condition eliminates the need for the suppression:

♻️ Proposed refactor
-  if (
-    !(id.column %in%
-      colnames(x$participants) && # nolint: indentation_linter.
-      id.column %in% colnames(x$contacts)) # nolint: indentation_linter.
-  ) {
+  part_has_id <- id.column %in% colnames(x$participants)
+  cont_has_id <- id.column %in% colnames(x$contacts)
+  if (!(part_has_id && cont_has_id)) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@R/check.R` around lines 99 - 100, The compound logical check inside the
negation uses a single-line && split with nolint comments; refactor the
condition in the function that performs the check (the expression referencing
id.column, x$participants and x$contacts) so the logical operands are split onto
separate lines (e.g., test each membership separately and combine with && on its
own line or negate each part as appropriate) to satisfy the indentation linter
and remove both "# nolint: indentation_linter." comments; ensure the logic of
the overall !(...) expression is preserved after reformatting.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@R/check.R`:
- Around line 9-10: The function signature for check_age_column is currently on
a single line with a trailing "# nolint: indentation_linter." which the air
formatter rejects; reformat the signature to one argument per line with the
closing parenthesis on its own line (e.g. split df, age_column, label, and call
= rlang::caller_env() each onto separate lines) and remove or relocate the
nolint comment so the air formatter can accept the style; ensure the function
name check_age_column and the default argument call = rlang::caller_env() remain
unchanged.

---

Nitpick comments:
In `@R/check.R`:
- Around line 99-100: The compound logical check inside the negation uses a
single-line && split with nolint comments; refactor the condition in the
function that performs the check (the expression referencing id.column,
x$participants and x$contacts) so the logical operands are split onto separate
lines (e.g., test each membership separately and combine with && on its own line
or negate each part as appropriate) to satisfy the indentation linter and remove
both "# nolint: indentation_linter." comments; ensure the logic of the overall
!(...) expression is preserved after reformatting.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 56d5f62 and 56caf82.

📒 Files selected for processing (3)
  • R/check.R
  • R/load-survey-utils.R
  • tests/testthat/test-agegroups.r

sbfnk-bot and others added 2 commits February 25, 2026 15:33
Co-authored-by: sbfnk <sebastian.funk@lshtm.ac.uk>
Co-authored-by: sbfnk <sebastian.funk@lshtm.ac.uk>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
.lintr (1)

1-10: Consider pinning cyclocomp_linter and line_length_linter parameters explicitly for stability across lintr versions.

The current .lintr config relies on linters_with_tags(tags = NULL) to implicitly enable cyclocomp_linter and line_length_linter with their built-in defaults (complexity_limit = 15L and length = 80L). While these defaults currently match your intended thresholds, explicitly configuring them guards against silent changes if a future lintr release alters its defaults:

🔧 Proposed explicit configuration
 linters: linters_with_tags(
     tags = NULL, # include all linters
     object_name_linter = NULL,
     undesirable_function_linter = NULL,
     implicit_integer_linter = NULL,
     todo_comment_linter = NULL,
     function_argument_linter = NULL,
     indentation_linter = NULL, # air handles indentation via style.yaml
+    cyclocomp_linter(complexity_limit = 15L),
+    line_length_linter(length = 80L),
     backport_linter("3.5.0")
   )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.lintr around lines 1 - 10, The lintr config currently relies on
linters_with_tags(tags = NULL) which implicitly enables cyclocomp_linter and
line_length_linter with default values; explicitly add
cyclocomp_linter(complexity_limit = 15L) and line_length_linter(length = 80L)
into the linters list (alongside other nulled linters) so their thresholds are
pinned and won’t change if lintr defaults change, e.g. include references to
cyclocomp_linter and line_length_linter inside the linters_with_tags(...) call.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@R/check.R`:
- Around line 30-36: The cli::cli_warn call that builds the multi-line glue
string using variables label, age_column, exact_col, min_col, and max_col uses
single backslashes before physical newlines; replace each single "\" with "\\"
in that string literal so the R parser produces a single backslash in the
resulting string (which glue recognises as the continuation marker), and make
this change consistently wherever similar multi-line glue strings are used
(e.g., the other cli::cli_warn/cli::cli_abort occurrences).
- Around line 30-36: The cli::cli_warn call's glue string uses a single
backslash for physical-line continuation, which produces an unrecognized escape
in R string literals; update the string so each physical-newline continuation
uses a double backslash (i.e. replace each "\" before the newline with "\\"),
preserving the same message and the interpolated symbols (label, age_column,
exact_col, min_col, max_col) so glue continues to join the lines correctly.

---

Nitpick comments:
In @.lintr:
- Around line 1-10: The lintr config currently relies on linters_with_tags(tags
= NULL) which implicitly enables cyclocomp_linter and line_length_linter with
default values; explicitly add cyclocomp_linter(complexity_limit = 15L) and
line_length_linter(length = 80L) into the linters list (alongside other nulled
linters) so their thresholds are pinned and won’t change if lintr defaults
change, e.g. include references to cyclocomp_linter and line_length_linter
inside the linters_with_tags(...) call.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 56caf82 and 4fa736c.

📒 Files selected for processing (5)
  • .lintr
  • NEWS.md
  • R/check.R
  • R/clean.R
  • tests/testthat/test-matrix.r
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/testthat/test-matrix.r
  • NEWS.md

Co-authored-by: sbfnk <sebastian.funk@lshtm.ac.uk>
@sbfnk
Copy link
Collaborator

sbfnk commented Feb 25, 2026

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 25, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@R/check.R`:
- Around line 54-56: The roxygen comment in R/check.R describing the
fallback-column requirement is missing the word "exist" (reads "... must (see
the `estimated.participant.age` option in [contact_matrix()])"); update the
documentation text in that roxygen block so both occurrences of the phrase read
"... must exist (see the `estimated.participant.age` option in
[contact_matrix()])" to produce grammatically correct help output. Ensure you
change both places in the same doc block where the fallback-column requirement
is described.
- Around line 107-108: The warning message in R/check.R incorrectly references
the parameter name `{.arg id.columns}`; update the string to use the actual
function argument `{.arg id.column}` so the warning reads "{.arg id.column}
{.val {id.column}} does not exist in both the participants and contacts data
frames." Locate the message construction that references `id.column` (the code
assembling the warning) and replace the plural token `id.columns` with
`id.column` to ensure the parameter name in the warning matches the function
signature.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4fa736c and 6f29a44.

📒 Files selected for processing (1)
  • R/check.R

sbfnk-bot and others added 3 commits February 25, 2026 19:17
Co-authored-by: sbfnk <sebastian.funk@lshtm.ac.uk>
Co-authored-by: sbfnk <sebastian.funk@lshtm.ac.uk>
Co-authored-by: sbfnk <sebastian.funk@lshtm.ac.uk>
@sbfnk sbfnk added this pull request to the merge queue Feb 27, 2026
Merged via the queue into main with commit e547c73 Feb 27, 2026
13 checks passed
@sbfnk sbfnk deleted the enable-cyclocomp-linter branch February 27, 2026 09:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enable cyclocomp_linter and reduce cyclomatic complexity

2 participants