Skip to content

feat: treat a missing parameter as unsatisfied instead of raising - #46

Draft
smandegar wants to merge 1 commit into
mainfrom
tolerate-missing-parameters
Draft

feat: treat a missing parameter as unsatisfied instead of raising#46
smandegar wants to merge 1 commit into
mainfrom
tolerate-missing-parameters

Conversation

@smandegar

Copy link
Copy Markdown
Contributor

What

Feature#enabled? no longer raises when a condition references a parameter that isn't present in the supplied parameters. That condition is treated as unsatisfied instead, so evaluation continues normally (OR across enabledFor, and disabledFor still wins).

Supplying no parameters at all still raises ArgumentError ("At least one parameter is required"), so a call that forgets to pass parameters is still caught.

Why

A feature can reference several parameters (for example one condition on plan and another on account_id), and different call sites may only know a subset of them. Previously, evaluating such a feature from a call site that supplied only some of its parameters raised, even when the supplied parameters were already enough to decide the result. Now a caller can pass just the parameters it has; conditions it cannot evaluate simply do not match.

Behavior

  • Partial parameters: an absent parameter leaves its condition unsatisfied (no raise).
  • Empty parameters on a feature that has parameterized conditions: still raises.
  • Parameter-less conditions (always/never) and a short-circuiting earlier match are unaffected.

Notes

This is a behavioral change: callers that relied on the previous per-parameter "Missing parameter" raise to detect a specific absent parameter will no longer get it (except for the empty-parameters case). Tests and CHANGELOG are updated.

A feature that references several parameters can now be evaluated with only
a subset supplied: an absent parameter leaves its condition unsatisfied rather
than raising. Supplying no parameters at all still raises.

@diff-vader-bot diff-vader-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 Risk: LOW — no substantive findings

✅ Diff Vader · Approved

Council reviewed 5 files · 12 reviewers · 0 findings · $0.36

  • ✅ blast‑radius
  • ✅ correctness
  • ✅ cost
  • ❓ github‑actionsskipped: filter: not applicable to changed files
  • ❓ iacskipped: filter: not applicable to changed files
  • ❓ migration‑safetyskipped: filter: not applicable to changed files
  • ✅ performance
  • ✅ revertibility
  • ✅ security‑tenant‑isolation
  • ❓ supply‑chainskipped: filter: not applicable to changed files
  • ✅ supportability
  • ✅ test‑adequacy

Why: All approval gates passed.

💡 /diff-vader-review <name> adds a one-shot reviewer. Beyond this PR's council, you can request: backup-correctness, loop-design-system.

Comment thread lib/eight_ball/feature.rb

value = parameters[condition.parameter.to_sym]
raise ArgumentError, "Missing parameter #{condition.parameter}" if value.nil?
if value.nil?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

pr-reviewer-blast-radius — confidence 85% (advisory)

This changes the evaluation contract: a condition whose parameter is absent from a non-empty bag is now silently treated as unsatisfied instead of raising. Callers that previously relied on the Missing parameter <name> ArgumentError to detect a specific absent parameter will now get a silent false (feature-off) instead. The PR body explicitly acknowledges this behavioral change and its impact on such callers, so this is a triaged, deliberate change rather than a novel defect — flagging only so downstream consumers are aware the feature may now evaluate to disabled where it previously errored.

React with 👍 / 👎 / 😕 to help us calibrate — why.

Comment thread spec/feature_spec.rb
later = EightBall::Conditions::List.new parameter: 'account_id', values: [1, 2]

feature = EightBall::Feature.new 'Feature', [satisfied, later]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

pr-reviewer-test-adequacy — confidence 85% (advisory)

The should short-circuit before reaching a later condition with an unsupplied parameter test calls feature.enabled? with no parameters, which means the early short-circuit is handled by the EightBall::Conditions::Always path (parameter is nil, so it returns immediately). This doesn't cover the case where a non-parameterized condition short-circuits before a parameterized one when an empty bag is supplied — but that's arguably out of scope. More importantly, the test doesn't verify that omitting parameters when the first condition also requires a parameter (non-short-circuit path) still returns false. This is already covered by other tests, so no gap. Advisory: does this test actually exercise the next false branch introduced in any_satisfied?, or only the return condition.satisfied? branch for parameter-nil conditions?

React with 👍 / 👎 / 😕 to help us calibrate — why.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 changes EightBall::Feature#enabled? evaluation so that when a condition references a parameter that is not present in a non-empty parameters hash, that condition is treated as unsatisfied (instead of raising). An empty parameters hash (or calling enabled? with no args, which defaults to {}) still raises when evaluation reaches a parameterized condition.

Changes:

  • Update feature evaluation to treat missing parameters in a non-empty bag as “unsatisfied”, while preserving an ArgumentError on empty-parameter evaluation.
  • Refresh specs to assert the new behavior, including the empty-parameters error contract.
  • Update README and CHANGELOG to reflect the behavioral change.

Reviewed changes

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

Show a summary per file
File Description
lib/eight_ball/feature.rb Adjusts condition evaluation behavior for missing vs empty parameters and updates YARD docs.
spec/feature_spec.rb Updates and expands unit coverage for the new missing-parameter semantics.
spec/stress_spec.rb Updates contract-oriented stress/spec assertion to match the new behavior.
README.md Updates documentation for parameterized condition behavior (percentage).
CHANGELOG.md Records the behavior change under Unreleased.

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

Comment thread lib/eight_ball/feature.rb
Comment on lines 85 to 87
conditions.any? do |condition|
return condition.satisfied? if condition.parameter.nil?

Comment thread lib/eight_ball/feature.rb
Comment on lines +40 to +42
# @raise [ArgumentError] if +parameters+ is empty and one of the Feature's
# {EightBall::Conditions} requires a parameter. A condition whose parameter
# is simply absent from a non-empty +parameters+ is treated as unsatisfied.
Comment thread spec/feature_spec.rb
Comment on lines +88 to +101
it 'should short-circuit before reaching a later condition with an unsupplied parameter' do
satisfied = EightBall::Conditions::Always.new
later = EightBall::Conditions::List.new parameter: 'account_id', values: [1, 2]

feature = EightBall::Feature.new 'Feature', [satisfied, later]

expect(feature.enabled?).to be true
end

it 'should not raise for a bare feature evaluated with an empty parameters hash' do
feature = EightBall::Feature.new 'NoConditions'

expect(feature.enabled?({})).to be true
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

3 participants