diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4f735b2..79c6c24 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+# Changes in 7.1.9
+- Fixed: numeric bounds from `short`/`byte`/`ushort`/`uint`/`ulong`/`sbyte`-typed rules were silently dropped (Issue #222)
+ - `IsNumeric` in the shared core (`MicroElements.OpenApi.FluentValidation`) only recognized `int`/`long`/`float`/`double`/`decimal`/`BigInteger`, so a `Between`/`Comparison` rule whose bound was a small integer type (e.g. `InclusiveBetween((short)1, (short)99)`) matched but produced no `minimum`/`maximum` — even though the generator emits `"type": "integer"` for the property. This could not be worked around at the validator definition site because those rule overloads only accept bounds of the property's own type
+ - Fix: `IsNumeric` now recognizes all integer primitives (`sbyte`/`byte`/`short`/`ushort`/`int`/`uint`/`long`/`ulong`) in addition to the floating/decimal/`BigInteger` types; `NumericToDecimal` already converted them all. One change in the shared core fixes all three providers (Swashbuckle, NSwag, and the native `Microsoft.AspNetCore.OpenApi` transformer)
+
# Changes in 7.1.8
- Security (Issue #220): closed a transitive high-severity advisory in the published package. `Swashbuckle.AspNetCore.SwaggerGen` on the net10.0 target was bumped `10.0.0` → `10.2.1`, which resolves `Microsoft.OpenApi` to the patched `2.7.5` (was `2.3.0`). This clears **GHSA-v5pm-xwqc-g5wc / CVE-2026-49451** (CWE-674 uncontrolled recursion — a circular `$ref` schema could stack-overflow the OpenAPI reader). The net8.0/net9.0 targets use Swashbuckle 8.1.1 → Microsoft.OpenApi v1 and were never in the advisory range
- Media type & file size validation for `IFormFile` uploads (Issue #216): stable rollup of everything in `7.1.8-beta.1` and `7.1.8-beta.2` below (new File-level rules `.FileContentType()`, `.MaxFileSize()`, `.MinFileSize()`, `.FileSizeBetween()`; Swashbuckle / NSwag / Microsoft.AspNetCore.OpenApi emit multipart `encoding.contentType` and description annotations)
diff --git a/src/MicroElements.OpenApi.FluentValidation/Core/Extensions.cs b/src/MicroElements.OpenApi.FluentValidation/Core/Extensions.cs
index aeea6e6..3bbd2d5 100644
--- a/src/MicroElements.OpenApi.FluentValidation/Core/Extensions.cs
+++ b/src/MicroElements.OpenApi.FluentValidation/Core/Extensions.cs
@@ -16,7 +16,15 @@ public static class Extensions
///
/// Is supported swagger numeric type.
///
- internal static bool IsNumeric(this object value) => value is int || value is long || value is float || value is double || value is decimal || value is BigInteger;
+ ///
+ /// Issue #222: all integer primitives must be recognized. `short`/`byte`/`ushort`/`uint`/`ulong`/`sbyte`
+ /// bounds (e.g. from InclusiveBetween((short)1, (short)99)) were dropped because they were absent
+ /// here, so minimum/maximum were never emitted. already
+ /// converts them all via .
+ ///
+ internal static bool IsNumeric(this object value) =>
+ value is sbyte or byte or short or ushort or int or uint or long or ulong
+ or float or double or decimal or BigInteger;
///
/// Convert numeric to decimal.
diff --git a/test/MicroElements.Swashbuckle.FluentValidation.Tests/Issue222SmallIntegerBoundsTest.cs b/test/MicroElements.Swashbuckle.FluentValidation.Tests/Issue222SmallIntegerBoundsTest.cs
new file mode 100644
index 0000000..767f360
--- /dev/null
+++ b/test/MicroElements.Swashbuckle.FluentValidation.Tests/Issue222SmallIntegerBoundsTest.cs
@@ -0,0 +1,113 @@
+// Copyright (c) MicroElements. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using FluentAssertions;
+using FluentValidation;
+using Xunit;
+
+namespace MicroElements.Swashbuckle.FluentValidation.Tests
+{
+ ///
+ /// Issue #222: numeric bounds whose value is a small integer type (sbyte/byte/short/ushort/uint/ulong)
+ /// were silently dropped — the Between/Comparison rules matched, but IsNumeric() did not recognize the
+ /// boxed value, so minimum/maximum were never emitted. For a `short` property FluentValidation's
+ /// InclusiveBetween/GreaterThanOrEqualTo overloads only accept short bounds, so this could not be worked
+ /// around at the validator definition site.
+ /// https://github.com/micro-elements/MicroElements.Swashbuckle.FluentValidation/issues/222
+ ///
+ public class Issue222SmallIntegerBoundsTest : UnitTestBase
+ {
+ public class Model
+ {
+ public sbyte SByteValue { get; set; }
+ public byte ByteValue { get; set; }
+ public short ShortValue { get; set; }
+ public ushort UShortValue { get; set; }
+ public uint UIntValue { get; set; }
+ public ulong ULongValue { get; set; }
+ }
+
+ // A fresh SchemaBuilder per case: its SchemaRepository caches the generated component,
+ // so one builder must generate exactly one rule/schema.
+
+ [Fact]
+ public void InclusiveBetween_SByte_Should_Emit_Bounds()
+ {
+ var schema = new SchemaBuilder().AddRule(x => x.SByteValue, rule => rule.InclusiveBetween((sbyte)1, (sbyte)9));
+ schema.GetMinimum().Should().Be(1);
+ schema.GetMaximum().Should().Be(9);
+ }
+
+ [Fact]
+ public void InclusiveBetween_Byte_Should_Emit_Bounds()
+ {
+ var schema = new SchemaBuilder().AddRule(x => x.ByteValue, rule => rule.InclusiveBetween((byte)2, (byte)200));
+ schema.GetMinimum().Should().Be(2);
+ schema.GetMaximum().Should().Be(200);
+ }
+
+ [Fact]
+ public void InclusiveBetween_Short_Should_Emit_Bounds()
+ {
+ var schema = new SchemaBuilder().AddRule(x => x.ShortValue, rule => rule.InclusiveBetween((short)1, (short)99));
+ schema.GetMinimum().Should().Be(1);
+ schema.GetMaximum().Should().Be(99);
+ }
+
+ [Fact]
+ public void InclusiveBetween_UShort_Should_Emit_Bounds()
+ {
+ var schema = new SchemaBuilder().AddRule(x => x.UShortValue, rule => rule.InclusiveBetween((ushort)3, (ushort)300));
+ schema.GetMinimum().Should().Be(3);
+ schema.GetMaximum().Should().Be(300);
+ }
+
+ [Fact]
+ public void InclusiveBetween_UInt_Should_Emit_Bounds()
+ {
+ var schema = new SchemaBuilder().AddRule(x => x.UIntValue, rule => rule.InclusiveBetween(4u, 400u));
+ schema.GetMinimum().Should().Be(4);
+ schema.GetMaximum().Should().Be(400);
+ }
+
+ [Fact]
+ public void InclusiveBetween_ULong_Should_Emit_Bounds()
+ {
+ var schema = new SchemaBuilder().AddRule(x => x.ULongValue, rule => rule.InclusiveBetween(5ul, 5000ul));
+ schema.GetMinimum().Should().Be(5);
+ schema.GetMaximum().Should().Be(5000);
+ }
+
+ [Fact]
+ public void ExclusiveBetween_Short_Should_Emit_Exclusive_Bounds()
+ {
+ var schema = new SchemaBuilder().AddRule(x => x.ShortValue, rule => rule.ExclusiveBetween((short)1, (short)99));
+ schema.GetMinimum().Should().Be(1);
+ schema.GetMaximum().Should().Be(99);
+ schema.GetExclusiveMinimum().Should().BeTrue();
+ schema.GetExclusiveMaximum().Should().BeTrue();
+ }
+
+ [Fact]
+ public void GreaterThanOrEqualTo_Short_Should_Emit_Minimum()
+ {
+ var schema = new SchemaBuilder().AddRule(x => x.ShortValue, rule => rule.GreaterThanOrEqualTo((short)1));
+ schema.GetMinimum().Should().Be(1);
+ }
+
+ [Fact]
+ public void LessThanOrEqualTo_Byte_Should_Emit_Maximum()
+ {
+ var schema = new SchemaBuilder().AddRule(x => x.ByteValue, rule => rule.LessThanOrEqualTo((byte)200));
+ schema.GetMaximum().Should().Be(200);
+ }
+
+ [Fact]
+ public void GreaterThan_UInt_Should_Emit_Exclusive_Minimum()
+ {
+ var schema = new SchemaBuilder().AddRule(x => x.UIntValue, rule => rule.GreaterThan(4u));
+ schema.GetMinimum().Should().Be(4);
+ schema.GetExclusiveMinimum().Should().BeTrue();
+ }
+ }
+}
diff --git a/version.props b/version.props
index 554c461..54df8a4 100644
--- a/version.props
+++ b/version.props
@@ -1,6 +1,6 @@
- 7.1.8
+ 7.1.9