Skip to content

RecipeMetadataRegistry: move combo-box provisioning to UI; route config defects through Result instead of constructor throws #111

Description

@mrcsin

Summary

The domain metadata registry carries UI presentation concerns and reports configuration defects inconsistently with the rest of the config pipeline. Three related findings in one class.

1. UI combo-box concerns live in Core

  • Recipes/ComboBoxItemViewModel.cs:3 — a type named and shaped for Avalonia ComboBox binding sits in the Core domain layer.
  • Recipes/RecipeMetadataRegistry.cs:21-24, 177-205GetComboBoxItems/GetActionComboBoxItems caches whose XML docs reason about "UI bindings (per-row dictionaries on RecipeRowViewModel)" and "the cell factory". The registry even bends its own error contract for the binding pipeline: "Diverges from the Result pattern ... so that UI bindings ... can hold an empty-but-valid reference" (172-176).

Core has no Avalonia reference (good), but the concept leaked: UI presentation changes force Core edits.

Fix: move ComboBoxItemViewModel and both cache methods into SemiStep.UI (e.g. a provider in RecipeGrid) built on the existing Core primitives GetGroup/GetAllActions. The registry keeps one consistent Result-based contract.

2. Config defects throw where the rest of the pipeline returns Result

RecipeMetadataRegistry.cs:81, 107, 224, 244, 257, 274 — six InvalidOperationException throws in the constructor path for configuration defects (unresolved column/property references, string max-length rules). The same class of defects is reported via Result by Configuration/Validation/*. A bad config slipping past validators crashes DI container resolution instead of producing the aggregated report shown in ErrorWindow.

Fix: move EnsureColumnPropertyReferencesResolve and ResolveStringMaxLength rules into CrossReferenceValidator/DefaultValueValidator so all verdicts flow through ConfigFacade; keep constructor throws only as assertions of already-validated input.

3. Inconsistent lazy-cache thread safety

RecipeMetadataRegistry.cs:21-24, 202_comboItemsByGroup is a ConcurrentDictionary with a comment justifying concurrent access, yet _actionComboBoxItems ??= ... two members later is a plain non-thread-safe lazy field. Benign race (worst case a duplicate list), but the class contradicts its own stated concurrency model. Disappears if finding 1 is fixed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions