Skip to content

0.7.1: narrow Step::Base#run_once ArgumentError rescue to Runner setup#15

Merged
justi merged 1 commit intomainfrom
feat/run-once-narrow-argumenterror-rescue
Apr 22, 2026
Merged

0.7.1: narrow Step::Base#run_once ArgumentError rescue to Runner setup#15
justi merged 1 commit intomainfrom
feat/run-once-narrow-argumenterror-rescue

Conversation

@justi
Copy link
Copy Markdown
Owner

@justi justi commented Apr 22, 2026

Summary

Follow-up to the Codex review P2 finding on PR #13 (v0.7.0), acknowledged there as a known limitation and tracked for v0.8. This is the first v0.8-planned deliverable from the local v0.8 roadmap — small enough to ship as a 0.7.x patch rather than wait for the batch.

Before: Step::Base#run_once wrapped the entire Runner chain in rescue ArgumentError to convert DSL misconfiguration (e.g. prompt has not been set) into :input_error. Side effect: any ArgumentError raised from adapter code during Runner#call — wrong arity, bad config arg, any programmer bug — was silently coerced into :input_error and re-tried as if the user had supplied bad input.

After: the rescue is scoped to the Runner-construction phase only. DSL configuration errors still produce :input_error. ArgumentError raised during Runner#call propagates to the caller.

The InputValidator inside Runner continues to handle Dry::Types::CoercionError, TypeError, ArgumentError in its own scoped rescue and returns :input_error for bad-input cases. That path is unchanged.

Why it matters

The narrative of v0.7 (CHANGELOG + README + ADR-0020) was "programmer errors propagate, provider errors become :adapter_error". The AdapterCaller already respected that — narrow rescue to RubyLLM::Error + Faraday::Error. But run_once's broader rescue ArgumentError was a backdoor that let adapter-code ArgumentError bugs slip back into :input_error and become retry targets.

This closes that backdoor. Programmer bugs raised during an adapter call now surface loudly instead of being disguised as "user gave bad input."

Test plan

  • bundle exec rspec — 1341 examples, 0 failures, 8 pending (all pending are API-key-gated live LLM tests)
  • New regression specs in retry_integration_spec.rb under "transport error handling":
    • it "propagates ArgumentError from adapter code (programmer bug, not bad input)" — adapter raising ArgumentError now propagates instead of being coerced into :input_error.
    • it "still converts DSL misconfiguration ArgumentError to :input_error (prompt missing)"prompt has not been set still becomes :input_error. Existing BUG 48 adversarial spec (step without prompt → :input_error) also still passes, verifying the narrow path works.
  • Version bump 0.7.00.7.1; CHANGELOG entry added.

Semver positioning

Technically a behavioral change — callers previously relying on ArgumentError from adapter code to produce :input_error results will now see the exception propagate. Shipped as patch (0.7.1) rather than minor (0.8.0) because:

  • No external user base (the previous deprecation-warning cycle was rejected on this same basis in ADR-0020).
  • v0.8.0 is reserved for the larger reach expansion (Chat#with_contract spike) per local ADR-0021.
  • CHANGELOG documents the change clearly.

Copilot AI review requested due to automatic review settings April 22, 2026 05:46
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR narrows Step::Base#run_once’s ArgumentError handling so that only DSL/setup-time misconfiguration is converted into an :input_error result, while ArgumentError raised during adapter execution propagates (treating it as a programmer/runtime error rather than “bad input”).

Changes:

  • Scope rescue ArgumentError to the Runner construction phase in Step::Base#run_once, allowing adapter-phase ArgumentError to bubble up.
  • Add regression specs covering (a) propagating adapter ArgumentError and (b) still converting missing-prompt DSL misconfiguration to :input_error.
  • Bump version to 0.7.1 and document the behavioral change in the changelog.

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
lib/ruby_llm/contract/step/base.rb Refactors run_once to only rescue ArgumentError during Runner setup, not during Runner#call.
spec/ruby_llm/contract/step/retry_integration_spec.rb Adds regression coverage for adapter-phase ArgumentError propagation and prompt-missing :input_error.
lib/ruby_llm/contract/version.rb Version bump to 0.7.1.
CHANGELOG.md Documents the behavioral change in 0.7.1.
Gemfile.lock Updates the local gem version entry to 0.7.1.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

ADR-0021 deliverable 2. Follow-up to Codex review finding P2 on PR #13
(v0.7.0), acknowledged there as known limitation.

Before: Step::Base#run_once had a blanket `rescue ArgumentError` around
the entire Runner chain. Intent was to catch DSL misconfiguration such
as `prompt has not been set` and return it as :input_error. Side effect:
any ArgumentError raised from adapter code during Runner#call — wrong
arity, bad config arg, programmer bug — was silently coerced into
:input_error and re-tried as if the user had supplied bad input.

After: rescue is scoped to the Runner-construction phase only. DSL
configuration errors still produce :input_error (regression test for
`prompt has not been set` kept passing). ArgumentError raised during
Runner#call propagates to the caller. Input-type validation failures
continue to produce :input_error via InputValidator's own scoped rescue,
unchanged.

Two new regression specs under "transport error handling" describe:
- adapter code raising ArgumentError now propagates (was: :input_error)
- DSL misconfiguration (missing prompt) still returns :input_error

Full suite: 1341 examples, 0 failures. Codex review on v0.7.0 explicitly
flagged this case under P2; this closes that follow-up.
@justi justi force-pushed the feat/run-once-narrow-argumenterror-rescue branch from 630b26d to a528b19 Compare April 22, 2026 06:06
@justi justi merged commit 3fe3c86 into main Apr 22, 2026
1 check passed
@justi justi deleted the feat/run-once-narrow-argumenterror-rescue branch April 22, 2026 09:12
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