Skip to content

Review, fix 10 confirmed defects, and take the suite from 24 to 115 tests (0.4.0) - #3

Open
peterclark wants to merge 2 commits into
masterfrom
claude/repo-review-plan-u4ap0k
Open

Review, fix 10 confirmed defects, and take the suite from 24 to 115 tests (0.4.0)#3
peterclark wants to merge 2 commits into
masterfrom
claude/repo-review-plan-u4ap0k

Conversation

@peterclark

@peterclark peterclark commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Reviews the gem at 4c1e46f, records the findings in PLAN.md, and implements Phases 1–4 of that plan. Refactoring proposals R1–R5 remain open.

Why

The suite was green — 24 runs, 0 failures — and that green was misleading. No test performed or stubbed an HTTP request, so every method that talks to REDCap was uncovered, and several config assertions passed vacuously as nil == nil. Most of the defects below sat in that gap. Separately, bundle install failed on any modern Bundler because of a bundler ~> 1.13 pin, so the project could not be set up as shipped.

Defects fixed

Each was reproduced against 4c1e46f before being fixed, and each ships with a regression test.

  • Redcap.new silently discarded block configuration. A bare Redcap.new after Redcap.configure { … } rebuilt the configuration from ENV, replacing the credentials the block had just set with nil. The README's documented setup flow did not work.
  • Query values were interpolated into filterLogic unescaped. where(name: "O'Brien") — or anything caller-supplied — closed the string literal early, so the rest was read as filter syntax and could widen the result set.
  • The API token was written to logs on every request whenever client.log = true.
  • update reported failure for multi-record writes, comparing the returned count against a hard-coded 1.
  • Record.find returned a truthy empty record instead of nil when nothing matched, so if (p = Person.find(id)) never guarded anything.
  • flush_cache did not exist unless caching was on at require time, though the README documents calling it.
  • Duplicated record_id in field lists built from string names; Redcap.configure raising LocalJumpError without a block; private not applying to the def self. query internals; five query stubs returning nil silently.

Also changed

Errors now descend from Redcap::ErrorConfigurationError, ResponseError (carrying status/body), ParseError — rather than leaking RestClient:: and JSON:: exceptions. Requests time out (60s default) instead of hanging indefinitely. Defining error behavior was a prerequisite for Phase 4's error-path tests, so this came forward from proposal R3.

Toolchain: dropped the Bundler pin, relaxed rake/hashie, set required_ruby_version >= 3.0, and replaced the dead Travis config with GitHub Actions on Ruby 3.1/3.2/3.3.

Tests: WebMock with disable_net_connect!, so an unstubbed request fails rather than reaching the network, plus a helper that records decoded request bodies — assertions check what the gem sends, not just what it returns. Global state resets between tests, so ordering is safe.

Verification

  • 115 runs, 171 assertions, 0 failures — across five seeds and both cache modes.
  • The new suite was run against the original library in an isolated copy: 56 of 115 fail there, including a named regression for every defect listed above.
  • bundle install && bundle exec rake test now succeeds from clean. gem build produces a valid package.

Two corrections to the plan, made while implementing it

  • The plan's claim that bindir = "exe" was broken was wrongbin/ for dev scripts and exe/ for shipped executables is the standard Bundler layout, and this gem ships none. Changing it would have installed console and setup onto users' PATH. Left as-is.
  • Field names are validated against an identifier pattern rather than against Client#fields, which would have cost a metadata round-trip on every query.

Both are recorded in a status block at the top of PLAN.md.

Known limitations

Nothing is verified against a live REDCap instance; the suite asserts what the gem sends. In particular, backslash-escaping quotes in filterLogic follows the common convention but is not confirmed against REDCap's parser — worth checking before relying on it.

The one-project-per-process ceiling remains: Record's client is a class variable shared with every subclass, so two subclasses cannot use different tokens. That is proposal R1, and it is now documented in the README rather than left implicit.

Released as 0.4.0 rather than the 0.3.2 the plan anticipated, since the error hierarchy and NotImplementedError stubs change observable behavior.

claude added 2 commits August 8, 2026 23:05
Document the repo for future Claude Code sessions and record a review of
the gem at 4c1e46f.

CLAUDE.md covers the commands (including the Bundler pin that blocks
`bundle install` on modern Bundler), the single-endpoint POST design and
its indexed-key wire format, the process-global configuration and shared
class-variable client, and the load-time caching wiring.

PLAN.md records 12 defects, each reproduced against the current code on
Ruby 3.3.6 rather than inferred, and lays out four phases (toolchain,
test harness, defect fixes, coverage) plus five refactoring proposals.
Notable findings: `Redcap.new` silently discards block configuration,
query values are interpolated into filterLogic unescaped, the API token
is written to logs when logging is enabled, and multi-record `update`
reports failure on success.

Documentation only; no library code changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011fTWYMojvbXxVp445oYaJ4
…erage

Executes Phases 1-4 of PLAN.md. Refactoring proposals R1-R5 remain open.

Phase 1 - toolchain. Removed the `bundler ~> 1.13` development pin that
made `bundle install` fail on every Bundler >= 2, relaxed rake and
hashie, set required_ruby_version, and replaced the dead Travis config
with GitHub Actions on Ruby 3.1/3.2/3.3.

Phase 2 - harness. Added WebMock with net connections disabled, so an
unstubbed request fails rather than reaching the network, plus a stub
helper that records decoded request bodies. Global configuration and
Record's client now reset between tests, making the suite
order-independent.

Phase 3 - defects. Fixed all ten confirmed bugs, each with a regression
test: configuration precedence (a bare `Redcap.new` silently discarded
block configuration), unescaped filterLogic interpolation, the token
appearing in log output, `update` reporting failure on multi-record
writes, `find` returning a truthy empty record, `flush_cache` not
existing when caching was off, duplicated record_id in field lists,
`configure` raising without a block, query internals only appearing
private, and the five stubs returning nil.

Phase 4 - coverage. Every method that talks to REDCap is now exercised,
which none were before; 24 examples to 115. Defining error behavior was
a prerequisite, so the Redcap::Error hierarchy and request timeouts came
forward from R3.

Verified by running the new suite against the original library in an
isolated copy: 56 of 115 fail there, including a named regression for
every defect, and all pass here across five seeds and both cache modes.

Released as 0.4.0 rather than 0.3.2 because the error hierarchy and
NotImplementedError stubs change observable behavior.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011fTWYMojvbXxVp445oYaJ4
@peterclark peterclark changed the title Add CLAUDE.md and a phased improvement plan Review, fix 10 confirmed defects, and take the suite from 24 to 115 tests (0.4.0) Aug 8, 2026
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.

2 participants