You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
test: cover the raising-renderer path and pin resolve_feature parity (os-016)
Review follow-ups on the resolve_or_raise refactor:
- resolve_feature now degrades a raising evaluate_and_render into ResolvedFeature.error
instead of propagating it. That path is covered, including its fail-closed empty
candidate list and the scope callout.
- New parity tests pin the one converged call site that does not delegate: resolve_feature
projects exactly the message and candidates that resolve_or_raise raises, across all
three failure kinds.
- test_raises_for_every_failure_kind compares against render_resolution_failure over an
independent evaluate() pass instead of the helper's own return value.
- Dropped two isinstance assertions that could never fail.
Docs: identify_seam.py records that evaluate_or_raise delegates to resolve_or_raise and
stays the seam resolution tests target, systemPatterns.md names the shared helper in the
resolve step, and the resolve_feature design note is rewrapped.
Copy file name to clipboardExpand all lines: memory-bank/systemPatterns.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -48,7 +48,7 @@ flowchart LR
48
48
2.**Parse**: `FeatureChainParser.parse_name` (`feature_chain_parser.py`) returns a frozen `ParsedFeatureName` (`parsed_feature_name.py`) recording exactly what `re` found. `operation_part` is the raw suffix, never a fabricated token.
49
49
3.**Bind** (`feature_chain_parser.py`): `bind_name_captures` binds named captures exclusively by name into an effective `Options`; a captureless pattern is a recognition predicate that identifies the group and binds nothing. A present option value always wins over a name-derived one. A transitional positional fallback (`_legacy_operation_config`) still reverse-looks-up single-capture legacy patterns, pending downstream migration (mloda-registry#327).
50
50
4.**Match**: `match_configuration_feature_chain_parser` validates present values (a bad value raises `PropertyValueRejection`, a `ValueError` verdict rather than a crash) and enforces required presence on the string-named path.
51
-
5.**Resolve** (`prepare/identify_feature_group.py`): `IdentifyFeatureGroupClass.evaluate`runs one non-raising resolution pass, recording per-candidate elimination facts (`EvaluationResult`, `Elimination`) so a failure explains which gate each near-miss failed. Class-definition-time checks reject order-dependent bindings and install guards enforcing `required_when` and name-path required presence; an all-optional matcher that would match any name emits a definition-time warning unless the class sets `ALLOW_UNIVERSAL_MATCHER`.
51
+
5.**Resolve** (`prepare/identify_feature_group.py`): the engine and the resolution test seam both enter through `resolve_or_raise` (the shared evaluate-render-raise helper, built on `evaluate_and_render`), under which `IdentifyFeatureGroupClass.evaluate`remains the non-raising matcher: it runs one resolution pass, recording per-candidate elimination facts (`EvaluationResult`, `Elimination`) so a failure explains which gate each near-miss failed. Class-definition-time checks reject order-dependent bindings and install guards enforcing `required_when` and name-path required presence; an all-optional matcher that would match any name emits a definition-time warning unless the class sets `ALLOW_UNIVERSAL_MATCHER`.
52
52
6.**Materialize defaults at intake, then compute** (os-008): `Engine.add_feature_to_collection` rebinds each resolved feature's options through `options_with_defaults()` as it enters the plan, so default-equivalent twins (same name, one key explicitly set to its declared default) merge through the standard duplicate path with uuid remapping. `ComputeFramework.run_calculate_feature` (`@final`) still calls `FeatureSet.materialize_option_defaults` as an idempotent safety net for direct API use; its twin-collapse ValueError is unreachable from engine-driven requests. `options_with_defaults()` fills only absent keys that declare a concrete default; `NO_DEFAULT` and a declared `None` fill nothing. Presence honors the explicit-`None` policy: a present `None` counts as set only when the spec sets `allow_explicit_none=True`.
53
53
54
54
Which lifecycle stages observe which options view:
0 commit comments