Skip to content

feat: per-candidate elimination reasons in resolution failure facts (#854) - #867

Merged
TomKaltofen merged 2 commits into
mainfrom
feat/854-per-candidate-elimination-reasons
Jul 21, 2026
Merged

feat: per-candidate elimination reasons in resolution failure facts (#854)#867
TomKaltofen merged 2 commits into
mainfrom
feat/854-per-candidate-elimination-reasons

Conversation

@TKaltofen

Copy link
Copy Markdown
Collaborator

What

Per-candidate elimination reasons in resolution failure facts (os-011, was #854; part of #760).

Candidates eliminated by a compute-framework pin, the link filter, frameworks the run did not enable, capability rejection, an option-value rejection, or a domain/scope mismatch previously vanished from failure messages, leaving a generic "No feature groups found". They are now recorded during the single resolution pass and named in the message.

Changes

  • EvaluationResult.eliminations: a per-candidate Elimination(stage, reason) recorded at the first gate each non-winning, name-matching candidate fails, within the single decision pass.
  • Failure messages gain a shared near-miss block naming each eliminated candidate and its reason (option value, domain, scope, compute framework, compute framework pin, links).
  • The capture/render precedence duplication is gone: the renderer alone owns precedence and projects the recorded eliminations; rendering calls no provider-overridable hook.
  • Capability reasons name only the run-enabled frameworks (no wider declared-but-disabled universe); the standalone "Unsupported compute framework(s)" message folds into the near-miss block.

Review

Two independent deep reviews (Claude Opus and codex) ran on the first commit. Accepted findings fixed in the second commit: value_rejection is recorded only for criteria-failing candidates (matched or winning candidates are never re-probed, and a losing rejector is captured even when a sibling wins), "Did you mean" suggestions that only echo a named near-miss are suppressed, the scope callout is no longer glued to a near-miss bullet, and the resolution-error docs are refreshed.

Testing

tox green: 7153 passed, 170 skipped; ruff format/check clean; pip-licenses clean; mypy --strict clean (882 files); bandit OK.

@TKaltofen
TKaltofen requested a review from TomKaltofen as a code owner July 21, 2026 10:12
…854)

Record why each near-miss FeatureGroup dropped during the single resolution
pass and expose it on EvaluationResult.eliminations. Failure messages now name
candidates removed by option-value rejection, domain, scope, capability,
non-enabled frameworks, framework pin, or links, which previously vanished.
The capture/render precedence duplication is gone: the renderer owns precedence
and projects the recorded eliminations from a single hook-free pass.
…view (#854)

Record value_rejection inline for criteria-failing candidates only, so a losing
rejector is captured even when a sibling wins and matched, winning, or abstract
candidates are never re-probed (no validator rerun, no winner in eliminations).
Suppress "Did you mean" suggestions that only echo an already-named near-miss.
Place the scope callout before the near-miss block in the abstract-only message
instead of gluing it to the last bullet. Refresh the resolution-error docs to
the new near-miss wording.
@TKaltofen
TKaltofen force-pushed the feat/854-per-candidate-elimination-reasons branch from 54a3d09 to 45028dc Compare July 21, 2026 12:54
@TomKaltofen
TomKaltofen merged commit 727fdae into main Jul 21, 2026
18 checks passed
@TomKaltofen
TomKaltofen deleted the feat/854-per-candidate-elimination-reasons branch July 21, 2026 14:31
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