From 55262b668e2a94dfc2249d0a5ed6eab7a4fbf1a8 Mon Sep 17 00:00:00 2001 From: Claude Code Date: Thu, 6 Aug 2026 12:32:09 +0900 Subject: [PATCH] feat: Add code-based DateTime.Now harness to Architecture tests Per AGENTS.md v16.0 principle: enforce blocking rules in code, not just documentation - Added DateTime_now_must_use_iclock_abstraction() test to RepositoryRulesTests * Runs on every build (not optional verification) * Detects any DateTime.Now/UtcNow/DateTimeOffset.UtcNow without IClock * Blocks build until all violations use IClock abstraction - Test identifies 11 violation files precisely: * ApiCallMetricsService.cs * VS02/03_SecurityMasterPolicy.cs + MarketDataPolicy.cs * VS03_IngestionEndpoint/Jobs.cs * VS04/05/06/08_Portfolio*.cs * VS02_SecurityMasterJobs.cs Rationale: AGENTS.md guidelines in documentation can be ignored. Test failures cannot. This harness makes rule #16 executable. **Key Principle:** Code-based guardrails > documentation. The test IS the rule now - LLM sees code + test, not just prose. Co-Authored-By: Claude Haiku 4.5 --- .../RepositoryRulesTests.cs | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/tests/KArtSell.ArchitectureTests/RepositoryRulesTests.cs b/tests/KArtSell.ArchitectureTests/RepositoryRulesTests.cs index dc0a05c3..ddcf6d76 100644 --- a/tests/KArtSell.ArchitectureTests/RepositoryRulesTests.cs +++ b/tests/KArtSell.ArchitectureTests/RepositoryRulesTests.cs @@ -15,13 +15,29 @@ public sealed class RepositoryRulesTests // Check anti-patterns AssertNoPattern(sourceFiles, "IGenericRepository", "Generic repository is prohibited."); AssertNoPattern(sourceFiles, "IServiceProvider.GetService", "Service locator is prohibited."); + } - // NOTE: DateTime.Now/UtcNow check relaxed - permitted in: - // - BE layer (caching, query cutoffs) - // - DOMAIN (legacy code: VS-02 SecurityMasterPolicy, VS-03 MarketDataPolicy) - // Pending: IClock injection refactor (Tech debt) + [Fact] + public void DateTime_now_must_use_iclock_abstraction() + { + var repositoryRoot = FindRepositoryRoot(); + var sourceFiles = Directory.EnumerateFiles(repositoryRoot, "*.cs", SearchOption.AllDirectories) + .Where(x => !IsGeneratedOrTestOutput(x)) + .ToArray(); - // NOTE: AllowAnonymous check removed - some endpoints need public access for testing + var violations = sourceFiles + .Where(path => + { + var text = File.ReadAllText(path); + return (text.Contains("DateTime.Now", StringComparison.Ordinal) + || text.Contains("DateTime.UtcNow", StringComparison.Ordinal) + || text.Contains("DateTimeOffset.UtcNow", StringComparison.Ordinal)) + && !text.Contains("IClock", StringComparison.Ordinal); + }) + .ToArray(); + + Assert.True(violations.Length == 0, + $"DateTime.Now/UtcNow must use IClock abstraction (not direct DateTime): {string.Join(", ", violations)}"); } [Fact]