PR 4b: Apply CA1822 static method modifiers + Gitea Actions secrets guidance

Completed DEBT-001 paydown (1pt) by making three pure-function methods static:
- ScheduleOccurrencePlanner.GetNextDueAt (no instance state accessed)
- PromotionGateEvaluator.Evaluate (evidence gate only, no mutations)
- EvaluationWindowPlanner.Plan (deterministic date calculation)

Changes:
- Added `static` modifier to three domain methods
- Updated call sites: ModelOperationsDispatcherJob, tests
- Removed unnecessary DI registrations (ModelOperationsModule)
- Eliminated instance creation overhead in tests

Test Results: 40/40 PASS (17 ModelOps + 18 SignalEngine + 5 Architecture)

Documentation:
- Updated TECH_DEBT_REGISTER.md: DEBT-001 Completed (PR 4b)
- Added Gitea Actions Secrets section to CLAUDE.md documenting:
  - KRX_API_KEY, OPENDART_API_KEY, KIS_API_KEY storage location
  - CI/CD usage pattern
  - Local dev guidance

Per AGENTS.md v16.0: Code changes are performance improvements, not suppressions.
Quarterly paydown: +1pt (target 4pts for 20% Q3 2026)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-08-02 05:59:01 +09:00
parent ac4ff5cd19
commit 6a31bc3737
11 changed files with 41 additions and 24 deletions
@@ -4,8 +4,7 @@ public sealed class EvaluationWindowPlannerTests
{
[Fact] public void Uses_trading_sessions_not_calendar_days()
{
var planner = new EvaluationWindowPlanner();
var due = planner.Plan("KRX", new DateOnly(2026, 8, 3), new WeekdayCalendar());
var due = EvaluationWindowPlanner.Plan("KRX", new DateOnly(2026, 8, 3), new WeekdayCalendar());
Assert.Equal(new[] { 1, 5, 20, 63, 126, 252 }, due.Select(x => x.WindowTradingDays));
Assert.All(due, x => Assert.DoesNotContain(x.DueSession.DayOfWeek, new[] { DayOfWeek.Saturday, DayOfWeek.Sunday }));
}
@@ -22,7 +22,7 @@ public sealed class PromotionGateEvaluatorTests
true,
DateTimeOffset.UtcNow);
var result = new PromotionGateEvaluator().Evaluate(snapshot, PromotionGateThresholds.ResearchBaseline);
var result = PromotionGateEvaluator.Evaluate(snapshot, PromotionGateThresholds.ResearchBaseline);
Assert.Equal(GateDecision.Pass, result.Decision);
Assert.Empty(result.BlockingReasons);
@@ -49,7 +49,7 @@ public sealed class PromotionGateEvaluatorTests
true,
DateTimeOffset.UtcNow);
var result = new PromotionGateEvaluator().Evaluate(snapshot, PromotionGateThresholds.ResearchBaseline);
var result = PromotionGateEvaluator.Evaluate(snapshot, PromotionGateThresholds.ResearchBaseline);
Assert.Equal(GateDecision.Hold, result.Decision);
Assert.Contains(result.BlockingReasons, reason => reason.Contains("Operational integrity", StringComparison.Ordinal));
@@ -2,17 +2,16 @@ using KArtSell.Modules.ModelOperations.Domain;
namespace KArtSell.ModelOperations.UnitTests;
public sealed class ScheduleOccurrencePlannerTests
{
private readonly ScheduleOccurrencePlanner planner = new();
[Fact] public void Daily_anchor_does_not_drift_to_dispatch_time()
{
var scheduled = new DateTimeOffset(2026, 8, 1, 1, 0, 0, TimeSpan.Zero);
var next = planner.GetNextDueAt(scheduled, "DAILY", "LATEST_ONLY", 1, scheduled.AddHours(10));
var next = ScheduleOccurrencePlanner.GetNextDueAt(scheduled, "DAILY", "LATEST_ONLY", 1, scheduled.AddHours(10));
Assert.Equal(scheduled.AddDays(1), next);
}
[Fact] public void Missed_occurrences_are_skipped_without_dispatch_storm()
{
var scheduled = new DateTimeOffset(2026, 7, 1, 1, 0, 0, TimeSpan.Zero);
var next = planner.GetNextDueAt(scheduled, "DAILY", "LATEST_ONLY", 1, new DateTimeOffset(2026, 8, 1, 4, 0, 0, TimeSpan.Zero));
var next = ScheduleOccurrencePlanner.GetNextDueAt(scheduled, "DAILY", "LATEST_ONLY", 1, new DateTimeOffset(2026, 8, 1, 4, 0, 0, TimeSpan.Zero));
Assert.True(next > new DateTimeOffset(2026, 8, 1, 4, 0, 0, TimeSpan.Zero));
Assert.Equal(1, next.Hour);
}