diff --git a/src/Cli.Tests/ValidateConfigTests.cs b/src/Cli.Tests/ValidateConfigTests.cs
index fe985f1a34..6e3f0fb1d5 100644
--- a/src/Cli.Tests/ValidateConfigTests.cs
+++ b/src/Cli.Tests/ValidateConfigTests.cs
@@ -883,6 +883,72 @@ public void TestChildWithEntitiesAndAutoentitiesResolvingZeroLogsNamedWarning()
VerifyAutoentityZeroDiscoveredWarning(loggerMock, expectedFileNameInMessage: "child-db.json");
}
+ ///
+ /// Child config with only autoentities that resolve to >0 entities is valid.
+ /// Simulates the production code path where the metadata provider stores resolution
+ /// counts on the root (merged) config rather than on the child config directly.
+ /// This is the regression test for the bug where child-config autoentities caused
+ /// "No entities found" even when they were expanded successfully.
+ /// Covers child truth-table row C5 (DS=1, E=0, AE=1, resolved>0, counts on root).
+ ///
+ [TestMethod]
+ public void TestChildWithDataSourceAndAutoentitiesResolvingEntitiesIsValid()
+ {
+ // Child has no explicit entities; only autoentities.
+ RuntimeConfig childConfig = BuildTestConfig(
+ hasDataSource: true,
+ entities: new(),
+ autoentities: new() { { "ae1", BuildSimpleAutoentity() } });
+ childConfig.IsChildConfig = true;
+
+ RuntimeConfig rootConfig = BuildTestConfig(
+ hasDataSource: false, entities: new(),
+ dataSourceFiles: new DataSourceFiles(new[] { "child-db.json" }));
+ rootConfig.ChildConfigs.Add(("child-db.json", childConfig));
+
+ // Simulate production: metadata provider stores counts in the root config,
+ // NOT directly on the child config.
+ rootConfig.AutoentityResolutionCounts["ae1"] = 3;
+
+ RuntimeConfigValidator validator = BuildValidator(rootConfig);
+ validator.ValidateDataSourceAndEntityPresence(rootConfig);
+
+ Assert.AreEqual(0, validator.ConfigValidationExceptions.Count,
+ "Child config with autoentities that resolved entities should pass validation.");
+ }
+
+ ///
+ /// Both root and child configs have autoentities that resolve to >0 entities.
+ /// Resolution counts for both are stored only on the root config (as the metadata
+ /// provider does at runtime). Validation must pass for both configs.
+ ///
+ [TestMethod]
+ public void TestRootAndChildBothWithAutoentitiesResolvingEntitiesIsValid()
+ {
+ RuntimeConfig childConfig = BuildTestConfig(
+ hasDataSource: true,
+ entities: new(),
+ autoentities: new() { { "child-ae", BuildSimpleAutoentity() } });
+ childConfig.IsChildConfig = true;
+
+ RuntimeConfig rootConfig = BuildTestConfig(
+ hasDataSource: true,
+ entities: new(),
+ dataSourceFiles: new DataSourceFiles(new[] { "child-db.json" }),
+ autoentities: new() { { "root-ae", BuildSimpleAutoentity() } });
+ rootConfig.ChildConfigs.Add(("child-db.json", childConfig));
+
+ // Simulate production: metadata provider stores ALL counts in the root config.
+ rootConfig.AutoentityResolutionCounts["root-ae"] = 2;
+ rootConfig.AutoentityResolutionCounts["child-ae"] = 4;
+
+ RuntimeConfigValidator validator = BuildValidator(rootConfig);
+ validator.ValidateDataSourceAndEntityPresence(rootConfig);
+
+ Assert.AreEqual(0, validator.ConfigValidationExceptions.Count,
+ "Root and child configs both with autoentities that resolved entities should pass validation.");
+ }
+
///
/// Helper: verifies that the autoentity-discovered-zero warning was logged at least once,
/// optionally also checking that the formatted message contains a child config file name.
diff --git a/src/Core/Configurations/RuntimeConfigValidator.cs b/src/Core/Configurations/RuntimeConfigValidator.cs
index 1c9f8b9ecd..c8a6c6e2c9 100644
--- a/src/Core/Configurations/RuntimeConfigValidator.cs
+++ b/src/Core/Configurations/RuntimeConfigValidator.cs
@@ -739,6 +739,18 @@ private void ValidateRootConfig(RuntimeConfig runtimeConfig)
// Validate each child config independently.
foreach ((string fileName, RuntimeConfig childConfig) in runtimeConfig.ChildConfigs)
{
+ // The metadata provider stores autoentity resolution counts on the root (merged)
+ // config. Copy those counts to the child config so per-child validation can find
+ // them. Only copy if the child hasn't already been populated (e.g. in unit tests).
+ foreach (KeyValuePair ae in childConfig.Autoentities)
+ {
+ if (!childConfig.AutoentityResolutionCounts.ContainsKey(ae.Key)
+ && runtimeConfig.AutoentityResolutionCounts.TryGetValue(ae.Key, out int count))
+ {
+ childConfig.AutoentityResolutionCounts[ae.Key] = count;
+ }
+ }
+
ValidateNonRootConfig(childConfig, configName: fileName);
}
}