From f8050240bab072b34ba0dd834f6c6c869313b38e Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 15 May 2026 16:46:18 +0000 Subject: [PATCH] fix: resolve build errors and warnings - Fixed IReadOnlyDictionary to IDictionary conversion error in RuleBlockGraphView. - Added missing NormalizeToDeterministicJson definition in RuleValidator. - Fixed early returns masking validation errors in RuleBlockGraph. --- WorldSim.Engine/Rules/RuleBlockGraph.cs | 49 +++++++++++--------- WorldSim.Engine/Rules/RuleValidator.cs | 13 ++++-- WorldSim.Godot/Scripts/RuleBlockGraphView.cs | 4 +- 3 files changed, 40 insertions(+), 26 deletions(-) diff --git a/WorldSim.Engine/Rules/RuleBlockGraph.cs b/WorldSim.Engine/Rules/RuleBlockGraph.cs index 81d6391..13ff0f5 100644 --- a/WorldSim.Engine/Rules/RuleBlockGraph.cs +++ b/WorldSim.Engine/Rules/RuleBlockGraph.cs @@ -102,28 +102,32 @@ public static RuleBlockGraphValidationResult ToRuleDefinition(RuleBlockGraphDto var duplicateBlockId = graph.Blocks.GroupBy(block => block.BlockId, StringComparer.Ordinal).FirstOrDefault(group => group.Count() > 1)?.Key; if (duplicateBlockId is not null) errors.Add($"Block id `{duplicateBlockId}` is duplicated."); + var localErrors = new List(); + var conditionBlocks = graph.Blocks.Where(block => block.Kind == RuleBlockKind.Condition).OrderBy(block => block.BlockId, StringComparer.Ordinal).ToArray(); - if (conditionBlocks.Length != 1) errors.Add("Block graph must contain exactly one condition block."); + if (conditionBlocks.Length != 1) localErrors.Add("Block graph must contain exactly one condition block."); - var effectBlocks = graph.Blocks.Where(block => block.Kind == RuleBlockKind.Effect).OrderBy(block => ReadInt(block, "effectIndex", errors, block.BlockId)).ThenBy(block => block.BlockId, StringComparer.Ordinal).ToArray(); - if (effectBlocks.Length == 0) errors.Add("Block graph must contain at least one effect block."); + var effectBlocks = graph.Blocks.Where(block => block.Kind == RuleBlockKind.Effect).OrderBy(block => ReadInt(block, "effectIndex", localErrors, block.BlockId)).ThenBy(block => block.BlockId, StringComparer.Ordinal).ToArray(); + if (effectBlocks.Length == 0) localErrors.Add("Block graph must contain at least one effect block."); RuleCondition? condition = null; if (conditionBlocks.Length == 1) { - condition = ReadCondition(conditionBlocks[0], errors); + condition = ReadCondition(conditionBlocks[0], localErrors); } var effects = new List(effectBlocks.Length); for (var expectedIndex = 0; expectedIndex < effectBlocks.Length; expectedIndex++) { var block = effectBlocks[expectedIndex]; - var index = ReadInt(block, "effectIndex", errors, block.BlockId); - if (index != expectedIndex) errors.Add($"Effect block `{block.BlockId}` must have contiguous `effectIndex` {expectedIndex}."); - var effect = ReadEffect(block, errors); + var index = ReadInt(block, "effectIndex", localErrors, block.BlockId); + if (index != expectedIndex) localErrors.Add($"Effect block `{block.BlockId}` must have contiguous `effectIndex` {expectedIndex}."); + var effect = ReadEffect(block, localErrors); if (effect is not null) effects.Add(effect); } + errors.AddRange(localErrors); + ValidateWires(graph, conditionBlocks.SingleOrDefault()?.BlockId, effectBlocks.Select(block => block.BlockId).ToArray(), errors); if (errors.Count > 0 || condition is null || effects.Count != effectBlocks.Length) @@ -191,33 +195,36 @@ private static int BlockEffectIndex(RuleBlockDto block) => private static RuleEffect? ReadEffect(RuleBlockDto block, ICollection errors) { - if (!ReadEnum(block, "kind", errors, out RuleEffectKind kind) || kind != RuleEffectKind.AdjustTraitWeight) + var localErrors = new List(); + if (!ReadEnum(block, "kind", localErrors, out RuleEffectKind kind) || kind != RuleEffectKind.AdjustTraitWeight) { - errors.Add($"Effect block `{block.BlockId}` must use `AdjustTraitWeight`."); - return null; + localErrors.Add($"Effect block `{block.BlockId}` must use `AdjustTraitWeight`."); } - if (!ReadEnum(block, "targetKind", errors, out RuleTargetKind targetKind) || targetKind != RuleTargetKind.AllAgents) + if (!ReadEnum(block, "targetKind", localErrors, out RuleTargetKind targetKind) || targetKind != RuleTargetKind.AllAgents) { - errors.Add($"Effect block `{block.BlockId}` must target `AllAgents`."); - return null; + localErrors.Add($"Effect block `{block.BlockId}` must target `AllAgents`."); } - if (!ReadEnum(block, "trait", errors, out RuleTraitKind trait)) + if (!ReadEnum(block, "trait", localErrors, out RuleTraitKind trait)) { - errors.Add($"Effect block `{block.BlockId}` has unsupported `trait`."); - return null; + localErrors.Add($"Effect block `{block.BlockId}` has unsupported `trait`."); } - var deltaText = ReadParameter(block, "delta", errors); + var deltaText = ReadParameter(block, "delta", localErrors); if (!float.TryParse(deltaText, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out var delta)) { - errors.Add($"Effect block `{block.BlockId}` requires numeric `delta`."); - return null; + localErrors.Add($"Effect block `{block.BlockId}` requires numeric `delta`."); + } + + if (delta is < -1f or > 1f) localErrors.Add($"Effect block `{block.BlockId}` `delta` must stay within [-1.0, 1.0]."); + + foreach(var err in localErrors) + { + errors.Add(err); } - if (delta is < -1f or > 1f) errors.Add($"Effect block `{block.BlockId}` `delta` must stay within [-1.0, 1.0]."); - return errors.Count > 0 ? null : new RuleEffect(kind, new RuleTarget(targetKind), trait, delta); + return localErrors.Count > 0 ? null : new RuleEffect(kind, new RuleTarget(targetKind), trait, delta); } private static void ValidateWires(RuleBlockGraphDto graph, string? conditionBlockId, IReadOnlyList effectBlockIds, ICollection errors) diff --git a/WorldSim.Engine/Rules/RuleValidator.cs b/WorldSim.Engine/Rules/RuleValidator.cs index ddd2324..fa8219a 100644 --- a/WorldSim.Engine/Rules/RuleValidator.cs +++ b/WorldSim.Engine/Rules/RuleValidator.cs @@ -223,7 +223,7 @@ private static bool TryParseEnum(string? text, out TEnum value) return false; } - private static string BuildNormalizedPreview(RuleDefinition rule) + public string NormalizeToDeterministicJson(RuleDefinition rule) { var preview = new { @@ -247,13 +247,20 @@ private static string BuildNormalizedPreview(RuleDefinition rule) }, trait = effect.Trait, delta = effect.Delta - }).ToArray(), - runtimeStatus = "Ready: safe validation, deterministic queueing, activation, and runtime trait effects are wired into the simulation loop." + }).ToArray() }; return JsonSerializer.Serialize(preview, PreviewSerializerOptions); } + private string BuildNormalizedPreview(RuleDefinition rule) + { + var previewJson = NormalizeToDeterministicJson(rule); + var document = JsonSerializer.Deserialize>(previewJson, SerializerOptions)!; + document["runtimeStatus"] = "Ready: safe validation, deterministic queueing, activation, and runtime trait effects are wired into the simulation loop."; + return JsonSerializer.Serialize(document, PreviewSerializerOptions); + } + private sealed record RuleJsonDocument( int? Id, string? Name, diff --git a/WorldSim.Godot/Scripts/RuleBlockGraphView.cs b/WorldSim.Godot/Scripts/RuleBlockGraphView.cs index d5c6ebd..d9ed404 100644 --- a/WorldSim.Godot/Scripts/RuleBlockGraphView.cs +++ b/WorldSim.Godot/Scripts/RuleBlockGraphView.cs @@ -167,7 +167,7 @@ private RuleBlockGraphDto BuildEditedGraph(RuleBlockGraphDto source) { if (block.Kind == RuleBlockKind.Condition) { - var copy = new SortedDictionary(block.Parameters, StringComparer.Ordinal) + var copy = new SortedDictionary(block.Parameters.ToDictionary(kvp => kvp.Key, kvp => kvp.Value), StringComparer.Ordinal) { ["nodeId"] = _nodeIdInput.Text.Trim(), ["resourceId"] = _resourceIdInput.Text.Trim(), @@ -178,7 +178,7 @@ private RuleBlockGraphDto BuildEditedGraph(RuleBlockGraphDto source) if (block.Kind == RuleBlockKind.Effect) { - var copy = new SortedDictionary(block.Parameters, StringComparer.Ordinal) + var copy = new SortedDictionary(block.Parameters.ToDictionary(kvp => kvp.Key, kvp => kvp.Value), StringComparer.Ordinal) { ["trait"] = _traitInput.Text.Trim(), ["delta"] = _deltaInput.Text.Trim()