Files
ExperionCrawler/tests/ExperionCrawler.Tests/FeedforwardFrontTests.cs
windpacer 7c26aa7361 feat: Phase II auto-write (WriteGuard, audit, auth) + WO-2~7 완료
Phase II:
- FfOperatorAction entity + ff_operator_action DDL/DbSet
- IFeedforwardWriteGuard + FeedforwardWriteGuard (SP bounds, grade C, transient, NaN)
- IFeedforwardAuditService + FeedforwardAuditService (raw ADO insert/query)
- FeedforwardSupervisor.AutoWriteAsync (per-stream OPC UA after Tick, rate-limited)
- FeedforwardConfigStore: advisory_only now read/writes DB, sp_node_id column
- FeedforwardController: auth (X-Kb-Token) on config/delete/write/audit;
  POST write/{id}/{key} manual SP write; GET audit; write results in MapColumn
- ff.js: token header, auto-write badge, per-stream write result, spNodeId, advisoryOnly
- ff.css: .ff-write-badge, .ff-write, .ff-write-err, .ff-wg-blocked
- Program.cs: register audit (Scoped) + write guard (Singleton)

WO-2~7 (build 0W/0E, test 22/22):
- PCT monitor, θ auto-tune, slow bias, front position indicator,
  total reflux recovery, config form expansion
2026-05-31 20:30:06 +09:00

41 lines
1.4 KiB
C#

using ExperionCrawler.Core.Application.Feedforward;
using ExperionCrawler.Infrastructure.Control;
using Xunit;
namespace ExperionCrawler.Tests;
public class FeedforwardFrontTests
{
[Fact]
public void Front_stable_within_band()
{
var ind = new FrontPositionIndicator(bandwidth: 0.3);
for (int i = 0; i < 50; i++) ind.Update(100.0, tsSec: 2, refTauSec: 60, strongSignal: true);
var (state, trim, grade) = ind.Update(100.1, 2, 60, true);
Assert.Contains("정상", state);
Assert.Null(trim);
Assert.Equal(Confidence.B, grade);
}
[Fact]
public void Front_rise_triggers_reflux_advice()
{
var ind = new FrontPositionIndicator(bandwidth: 0.3);
for (int i = 0; i < 200; i++) ind.Update(100.0, tsSec: 2, refTauSec: 60, strongSignal: false);
var (state, trim, grade) = ind.Update(105.0, 2, 60, false);
Assert.Contains("상승", state);
Assert.Equal("환류↑ 권장", trim);
Assert.Equal(Confidence.C, grade);
}
[Fact]
public void Front_fall_triggers_boilup_advice()
{
var ind = new FrontPositionIndicator(bandwidth: 0.3);
for (int i = 0; i < 200; i++) ind.Update(100.0, tsSec: 2, refTauSec: 60, strongSignal: true);
var (state, trim, _) = ind.Update(95.0, 2, 60, true);
Assert.Contains("하강", state);
Assert.Contains("boilup", trim);
}
}