diff --git a/CLAUDE.md b/CLAUDE.md
index 5115dc0..f11227b 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -21,7 +21,7 @@ so moving a project cannot silently retarget a test.
- `test/CodoMetis.ValueRanges.EFCore.PostgreSQL.Tests/` — EF Core SQL translation tests (no database)
- `test/CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTime.Tests/` — NodaTime EF translation tests (no database)
- `test/CodoMetis.ValueRanges.EFCore.PostgreSQL.IntegrationTests/` — Live PostgreSQL via Testcontainers (needs Docker; Inconclusive without, but hard failure under CI=true). Covers BCL and NodaTime types. Authority on PostgreSQL semantics — run when changing translations or range algebra
-- `test/CodoMetis.ValueRanges.Conventions.Tests/` — Repo-level conventions: changelog consistency, packaging metadata, value set contract compliance, EF mapping parity. Everything is discovered (projects by globbing `src/`, types by reflection), so adding a package or a type needs no edit here
+- `test/CodoMetis.ValueRanges.Conventions.Tests/` — Repo-level conventions: changelog consistency, packaging metadata, release wiring, the SECURITY.md supported-versions table, value set contract compliance, EF mapping parity. Everything is discovered (projects by globbing `src/`, types by reflection), so adding a package or a type needs no edit here
- `docs/` — Agent docs (read relevant doc before starting work)
## Commands
diff --git a/SECURITY.md b/SECURITY.md
index ea36ca5..54a38a5 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -51,8 +51,8 @@ remedy for those is to upgrade.
| Version | Supported |
|---|---|
-| 6.1.x | ✅ |
-| < 6.1 | ❌ |
+| 6.2.x | ✅ |
+| < 6.2 | ❌ |
## Where this package sits
diff --git a/test/CodoMetis.ValueRanges.Conventions.Tests/SecurityPolicyConventionTests.cs b/test/CodoMetis.ValueRanges.Conventions.Tests/SecurityPolicyConventionTests.cs
new file mode 100644
index 0000000..4507445
--- /dev/null
+++ b/test/CodoMetis.ValueRanges.Conventions.Tests/SecurityPolicyConventionTests.cs
@@ -0,0 +1,68 @@
+using System.Text.RegularExpressions;
+
+namespace CodoMetis.ValueRanges.Conventions.Tests;
+
+///
+/// SECURITY.md promises fixes for "the latest released minor version" and tabulates which line that
+/// is. The table is prose: nothing ties it to Directory.Build.props, so a release that bumps
+/// the version and forgets the table leaves the policy pointing a reporter at a line that no longer
+/// receives fixes. That is not hypothetical — 6.2.0 shipped with the table still saying 6.1.x. A
+/// supported-versions table that is wrong is worse than none: it reads as a considered statement.
+///
+[TestClass]
+public sealed class SecurityPolicyConventionTests
+{
+ private static FileInfo SecurityPolicy => new(Path.Combine(RepoLayout.Root.FullName, "SECURITY.md"));
+
+ /// "| 6.2.x | ✅ |" — the one line that receives fixes.
+ private static readonly Regex SupportedRow =
+ new(@"^\|\s*(?\d+)\.(?\d+)\.x\s*\|\s*✅\s*\|", RegexOptions.Multiline);
+
+ /// "| < 6.2 | ❌ |" — everything before it.
+ private static readonly Regex UnsupportedRow =
+ new(@"^\|\s*<\s*(?\d+)\.(?\d+)\s*\|\s*❌\s*\|", RegexOptions.Multiline);
+
+ [TestMethod]
+ public void SecurityPolicy_Exists()
+ {
+ Assert.IsTrue(SecurityPolicy.Exists, $"No SECURITY.md at the repository root ({SecurityPolicy.FullName}).");
+ }
+
+ [TestMethod]
+ public void TheSupportedVersionsTable_NamesTheShippedMinor()
+ {
+ var text = File.ReadAllText(SecurityPolicy.FullName);
+ var shipped = Version.Parse(RepoLayout.ShippedVersion);
+ var expected = $"{shipped.Major}.{shipped.Minor}";
+
+ var supported = SupportedRow.Matches(text);
+
+ Assert.AreEqual(
+ 1, supported.Count,
+ "SECURITY.md should have exactly one '| x.y.x | ✅ |' row — the policy is that fixes land "
+ + "on the latest released minor only, so there is one supported line to name.");
+
+ var supportedLine = $"{supported[0].Groups["major"].Value}.{supported[0].Groups["minor"].Value}";
+
+ Assert.AreEqual(
+ expected, supportedLine,
+ $"SECURITY.md lists {supportedLine}.x as the supported line, but Directory.Build.props ships "
+ + $"{shipped}. The table is part of the version bump: a reporter reads it to decide whether "
+ + "their version still receives fixes.");
+
+ var unsupported = UnsupportedRow.Match(text);
+
+ Assert.IsTrue(
+ unsupported.Success,
+ "SECURITY.md should have a '| < x.y | ❌ |' row saying that everything before the supported "
+ + "line is unmaintained.");
+
+ var unsupportedBelow = $"{unsupported.Groups["major"].Value}.{unsupported.Groups["minor"].Value}";
+
+ Assert.AreEqual(
+ expected, unsupportedBelow,
+ $"SECURITY.md says versions below {unsupportedBelow} are unsupported, but the supported line "
+ + $"is {expected}.x — the two rows should meet at the same minor, or a range is left "
+ + "described by neither.");
+ }
+}