NEO-67: address code review nits on recipe registry

Delegate TryGetDefinition to catalog.TryGetRecipe, cache ordered defs at
construction, and assert unknown recipeId in host DI test.
pull/101/head
VinPropane 2026-05-24 16:58:38 -04:00
parent 2fc3b8f750
commit 95d42803e1
3 changed files with 12 additions and 12 deletions

View File

@ -37,11 +37,11 @@ None.
## Nits ## Nits
- Nit: `RecipeDefinitionRegistry.TryGetDefinition` reads `catalog.ById` directly instead of delegating to `catalog.TryGetRecipe` — consistent with `ItemDefinitionRegistry` (NEO-52), but both bypass the catalogs public lookup helper; harmless for immutable data. - ~~Nit: `RecipeDefinitionRegistry.TryGetDefinition` reads `catalog.ById` directly instead of delegating to `catalog.TryGetRecipe` — consistent with `ItemDefinitionRegistry` (NEO-52), but both bypass the catalogs public lookup helper; harmless for immutable data.~~ **Done.** Registry now delegates to `catalog.TryGetRecipe`.
- Nit: `GetDefinitionsInIdOrder()` allocates a new sorted list on every call — acceptable for prototype HTTP/craft volume; optional future optimization is to cache the ordered list at catalog/registry construction time if hot-path profiling warrants it (same as item registry). - ~~Nit: `GetDefinitionsInIdOrder()` allocates a new sorted list on every call — acceptable for prototype HTTP/craft volume; optional future optimization is to cache the ordered list at catalog/registry construction time if hot-path profiling warrants it (same as item registry).~~ **Done.** Ordered list built once in `RecipeDefinitionRegistry` constructor.
- Nit: `Host_ShouldResolveRegistryFromDi_WhenStartupSucceeds` asserts a known id and enumeration count but not an unknown id in the host context — unit tests cover unknown/null; host test could add one line for symmetry with E3M2-03 acceptance wording (“distinguishable from valid ids in tests”). - ~~Nit: `Host_ShouldResolveRegistryFromDi_WhenStartupSucceeds` asserts a known id and enumeration count but not an unknown id in the host context — unit tests cover unknown/null; host test could add one line for symmetry with E3M2-03 acceptance wording (“distinguishable from valid ids in tests”).~~ **Done.** Host test asserts unknown `recipeId` returns false without throw.
## Verification ## Verification

View File

@ -243,11 +243,14 @@ public class RecipeDefinitionRegistryTests
// Act // Act
var registry = factory.Services.GetRequiredService<IRecipeDefinitionRegistry>(); var registry = factory.Services.GetRequiredService<IRecipeDefinitionRegistry>();
var found = registry.TryGetDefinition("refine_scrap_standard", out var refine); var found = registry.TryGetDefinition("refine_scrap_standard", out var refine);
var unknown = registry.TryGetDefinition("not_a_real_recipe", out var missing);
var list = registry.GetDefinitionsInIdOrder(); var list = registry.GetDefinitionsInIdOrder();
// Assert // Assert
Assert.True(found); Assert.True(found);
Assert.NotNull(refine); Assert.NotNull(refine);
Assert.Equal("process", refine.RecipeKind); Assert.Equal("process", refine.RecipeKind);
Assert.False(unknown);
Assert.Null(missing);
Assert.Equal(8, list.Count); Assert.Equal(8, list.Count);
Assert.Contains(list, r => r.Id == "make_field_stim_mk0" && r.RecipeKind == "make"); Assert.Contains(list, r => r.Id == "make_field_stim_mk0" && r.RecipeKind == "make");
} }

View File

@ -5,6 +5,8 @@ namespace NeonSprawl.Server.Game.Crafting;
/// <summary>Adapter over <see cref="RecipeDefinitionCatalog"/> (NEO-67).</summary> /// <summary>Adapter over <see cref="RecipeDefinitionCatalog"/> (NEO-67).</summary>
public sealed class RecipeDefinitionRegistry(RecipeDefinitionCatalog catalog) : IRecipeDefinitionRegistry public sealed class RecipeDefinitionRegistry(RecipeDefinitionCatalog catalog) : IRecipeDefinitionRegistry
{ {
private readonly IReadOnlyList<RecipeDefRow> _definitionsInIdOrder = BuildDefinitionsInIdOrder(catalog);
/// <inheritdoc /> /// <inheritdoc />
public bool TryGetDefinition(string? recipeId, [NotNullWhen(true)] out RecipeDefRow? definition) public bool TryGetDefinition(string? recipeId, [NotNullWhen(true)] out RecipeDefRow? definition)
{ {
@ -14,18 +16,13 @@ public sealed class RecipeDefinitionRegistry(RecipeDefinitionCatalog catalog) :
return false; return false;
} }
if (catalog.ById.TryGetValue(recipeId, out var row)) return catalog.TryGetRecipe(recipeId, out definition);
{
definition = row;
return true;
}
definition = null;
return false;
} }
/// <inheritdoc /> /// <inheritdoc />
public IReadOnlyList<RecipeDefRow> GetDefinitionsInIdOrder() public IReadOnlyList<RecipeDefRow> GetDefinitionsInIdOrder() => _definitionsInIdOrder;
private static IReadOnlyList<RecipeDefRow> BuildDefinitionsInIdOrder(RecipeDefinitionCatalog catalog)
{ {
var ids = catalog.ById.Keys.OrderBy(k => k, StringComparer.Ordinal).ToArray(); var ids = catalog.ById.Keys.OrderBy(k => k, StringComparer.Ordinal).ToArray();
var list = new List<RecipeDefRow>(ids.Length); var list = new List<RecipeDefRow>(ids.Length);