diff --git a/SVSim.Database/Models/Config/GuildConfig.cs b/SVSim.Database/Models/Config/GuildConfig.cs
new file mode 100644
index 00000000..bfb5d670
--- /dev/null
+++ b/SVSim.Database/Models/Config/GuildConfig.cs
@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace SVSim.Database.Models.Config;
+
+///
+/// Guild-feature configuration: membership caps, search caps, stamp palette,
+/// and chat-polling intervals. All collection defaults live in
+/// (not property initializers) to survive the
+/// GameConfigService tier-merge correctly.
+///
+[ConfigSection("Guild")]
+public sealed class GuildConfig
+{
+ public int MaxMemberNum { get; init; } = 30;
+ public int MaxSubLeaderNum { get; init; } = 2;
+ public int SearchResultCap { get; init; } = 50;
+ public int ChatPollIdleSeconds { get; init; } = 10;
+ public int ChatPollActiveSeconds { get; init; } = 3;
+ public List UsableStampList { get; init; } = new();
+
+ public static GuildConfig ShippedDefaults() => new()
+ {
+ UsableStampList = Enumerable.Range(100001, 20).ToList(),
+ };
+}
diff --git a/SVSim.UnitTests/Config/GuildConfigDefaultsTests.cs b/SVSim.UnitTests/Config/GuildConfigDefaultsTests.cs
new file mode 100644
index 00000000..65fef399
--- /dev/null
+++ b/SVSim.UnitTests/Config/GuildConfigDefaultsTests.cs
@@ -0,0 +1,31 @@
+using NUnit.Framework;
+using SVSim.Database.Models.Config;
+using System.Linq;
+
+namespace SVSim.UnitTests.Config;
+
+[TestFixture]
+public class GuildConfigDefaultsTests
+{
+ [Test]
+ public void ShippedDefaults_carry_capture_matching_stamps_and_caps()
+ {
+ var c = GuildConfig.ShippedDefaults();
+
+ Assert.That(c.MaxMemberNum, Is.EqualTo(30));
+ Assert.That(c.MaxSubLeaderNum, Is.EqualTo(2));
+ Assert.That(c.SearchResultCap, Is.EqualTo(50));
+ Assert.That(c.UsableStampList, Is.EqualTo(Enumerable.Range(100001, 20).ToList()));
+ }
+
+ [Test]
+ public void Property_initializers_alone_leave_stamp_list_empty()
+ {
+ // Defensive check: if someone moves UsableStampList default off ShippedDefaults
+ // and into a property initializer, the config-section tier merge will silently
+ // empty it. See feedback_config_defaults.md.
+ var c = new GuildConfig();
+ Assert.That(c.UsableStampList, Is.Empty,
+ "UsableStampList must default empty on property init; populated only by ShippedDefaults().");
+ }
+}