mirror of
https://github.com/okieselbach/AutopilotMonitor.git
synced 2026-10-24 12:42:38 +00:00
feat(agent-v2): wire --replay-log-dir CLI flag to ImeLogTracker SimulationMode
V2 had the complete replay infrastructure in place but never wired up: ImeLogTracker.SimulationMode / SpeedFactor properties (ImeLogTracker.cs:66-67) and the ApplySimulationDelay compression loop (ImeLogTracker.Handlers.cs:529-546) were fully implemented, and AgentConfiguration had ReplayLogDir + ReplaySpeedFactor fields (L.128, L.134), but nothing set them from the CLI and nothing read them in the factory. This commit adds: - CLI args --replay-log-dir <path> and --replay-speed-factor <n> in Program.BuildAgentConfiguration (invariant-culture parse, zero/malformed rejected). - DefaultComponentFactory.ImeLogHost ctor accepts a simulation mode + speed factor and applies them to the inner tracker when ReplayLogDir is non-empty. - PrintUsage documents the flags under a new "Dev / Test" section. For the deterministic signal-level replay (V2 ReplayHarness + signal-log.jsonl fixtures) no wiring is needed - that is already the primary V2 test path. The IME- log replay activated here is the V1 compatibility dev-mode for support cases where only raw IME logs are available. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+66
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using AutopilotMonitor.Agent.V2;
|
||||
using AutopilotMonitor.Agent.V2.Core.Configuration;
|
||||
using Xunit;
|
||||
|
||||
namespace AutopilotMonitor.Agent.V2.Core.Tests.Program
|
||||
{
|
||||
/// <summary>
|
||||
/// Verifies that <see cref="AutopilotMonitor.Agent.V2.Program.BuildAgentConfiguration"/>
|
||||
/// propagates the dev-only <c>--replay-log-dir</c> + <c>--replay-speed-factor</c> CLI flags
|
||||
/// onto <see cref="AgentConfiguration"/> so the IME log replay SimulationMode actually
|
||||
/// activates downstream. V2 parity PR-A.
|
||||
/// </summary>
|
||||
public sealed class BuildAgentConfigurationReplayTests
|
||||
{
|
||||
private static AgentConfiguration Build(params string[] args) =>
|
||||
AutopilotMonitor.Agent.V2.Program.BuildAgentConfiguration(
|
||||
args: args,
|
||||
tenantId: "tenant-t",
|
||||
sessionId: "session-s",
|
||||
bootstrapConfig: null,
|
||||
awaitConfig: null);
|
||||
|
||||
[Fact]
|
||||
public void Without_replay_flags_ReplayLogDir_stays_null_and_speed_factor_default()
|
||||
{
|
||||
var cfg = Build();
|
||||
|
||||
Assert.Null(cfg.ReplayLogDir);
|
||||
Assert.Equal(50.0, cfg.ReplaySpeedFactor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Replay_log_dir_populates_configuration()
|
||||
{
|
||||
var cfg = Build("--replay-log-dir", @"C:\tmp\ime-logs");
|
||||
|
||||
Assert.Equal(@"C:\tmp\ime-logs", cfg.ReplayLogDir);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Replay_speed_factor_is_parsed_as_invariant_double()
|
||||
{
|
||||
// Comma locale must NOT flip the meaning — parser uses InvariantCulture.
|
||||
var cfg = Build("--replay-log-dir", @"C:\tmp\x", "--replay-speed-factor", "125.5");
|
||||
|
||||
Assert.Equal(125.5, cfg.ReplaySpeedFactor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Replay_speed_factor_zero_is_rejected_and_default_kept()
|
||||
{
|
||||
var cfg = Build("--replay-log-dir", @"C:\tmp\x", "--replay-speed-factor", "0");
|
||||
|
||||
Assert.Equal(50.0, cfg.ReplaySpeedFactor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Replay_speed_factor_malformed_is_rejected_and_default_kept()
|
||||
{
|
||||
var cfg = Build("--replay-log-dir", @"C:\tmp\x", "--replay-speed-factor", "fast");
|
||||
|
||||
Assert.Equal(50.0, cfg.ReplaySpeedFactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,6 +126,14 @@ namespace AutopilotMonitor.Agent.V2.Core.Orchestration
|
||||
|
||||
hosts.Add(new AadJoinHost(logger, ingress, clock));
|
||||
|
||||
// Dev / test — if --replay-log-dir is set, the tracker reads from the replay folder
|
||||
// with SimulationMode ON + the configured SpeedFactor instead of tailing the live
|
||||
// IME log folder. Production agents leave ReplayLogDir empty.
|
||||
var simulationMode = !string.IsNullOrEmpty(_agentConfig.ReplayLogDir);
|
||||
var imeLogFolder = simulationMode
|
||||
? _agentConfig.ReplayLogDir
|
||||
: _agentConfig.ImeLogPathOverride;
|
||||
|
||||
_imeLogHost = new ImeLogHost(
|
||||
sessionId: sessionId,
|
||||
tenantId: tenantId,
|
||||
@@ -133,11 +141,13 @@ namespace AutopilotMonitor.Agent.V2.Core.Orchestration
|
||||
logger: logger,
|
||||
ingress: ingress,
|
||||
clock: clock,
|
||||
imeLogPathOverride: _agentConfig.ImeLogPathOverride,
|
||||
imeLogPathOverride: imeLogFolder,
|
||||
imeMatchLogPath: _agentConfig.ImeMatchLogPath,
|
||||
imePatterns: _remoteConfig.ImeLogPatterns,
|
||||
stateDirectory: _stateDirectory,
|
||||
whiteGloveSealingPatternIds: whiteGloveSealingPatternIds);
|
||||
whiteGloveSealingPatternIds: whiteGloveSealingPatternIds,
|
||||
simulationMode: simulationMode,
|
||||
simulationSpeedFactor: _agentConfig.ReplaySpeedFactor);
|
||||
hosts.Add(_imeLogHost);
|
||||
|
||||
if (collectors.StallProbeEnabled)
|
||||
@@ -401,6 +411,12 @@ namespace AutopilotMonitor.Agent.V2.Core.Orchestration
|
||||
/// </summary>
|
||||
internal Monitoring.Enrollment.Ime.ImeLogTracker Tracker => _tracker;
|
||||
|
||||
/// <summary>
|
||||
/// Exposes the tracker's simulation flag so the Dev / Test CLI flag
|
||||
/// <c>--replay-log-dir</c> is testable without poking through reflection.
|
||||
/// </summary>
|
||||
internal bool IsSimulationMode => _tracker.SimulationMode;
|
||||
|
||||
public ImeLogHost(
|
||||
string sessionId,
|
||||
string tenantId,
|
||||
@@ -412,7 +428,9 @@ namespace AutopilotMonitor.Agent.V2.Core.Orchestration
|
||||
string? imeMatchLogPath,
|
||||
List<ImeLogPattern>? imePatterns,
|
||||
string stateDirectory,
|
||||
IReadOnlyCollection<string>? whiteGloveSealingPatternIds)
|
||||
IReadOnlyCollection<string>? whiteGloveSealingPatternIds,
|
||||
bool simulationMode = false,
|
||||
double simulationSpeedFactor = 50)
|
||||
{
|
||||
_logger = logger;
|
||||
var logFolder = string.IsNullOrEmpty(imeLogPathOverride) ? DefaultImeLogFolder : imeLogPathOverride!;
|
||||
@@ -428,6 +446,13 @@ namespace AutopilotMonitor.Agent.V2.Core.Orchestration
|
||||
matchLogPath: expandedMatchLogPath,
|
||||
stateDirectory: stateDirectory);
|
||||
|
||||
if (simulationMode)
|
||||
{
|
||||
_tracker.SimulationMode = true;
|
||||
_tracker.SpeedFactor = simulationSpeedFactor;
|
||||
logger.Info($"ImeLogHost: SimulationMode ENABLED (speedFactor={simulationSpeedFactor}, path={logFolder})");
|
||||
}
|
||||
|
||||
_adapter = new ImeLogTrackerAdapter(_tracker, ingress, clock, whiteGloveSealingPatternIds);
|
||||
|
||||
_processWatcher = new ImeProcessWatcher(sessionId, tenantId, onEnrollmentEvent, logger);
|
||||
|
||||
@@ -1113,7 +1113,7 @@ namespace AutopilotMonitor.Agent.V2
|
||||
|
||||
// ---------------------------------------------------------------- Configuration
|
||||
|
||||
private static AgentConfiguration BuildAgentConfiguration(
|
||||
internal static AgentConfiguration BuildAgentConfiguration(
|
||||
string[] args,
|
||||
string tenantId,
|
||||
string sessionId,
|
||||
@@ -1124,6 +1124,20 @@ namespace AutopilotMonitor.Agent.V2
|
||||
var imeLogPathOverride = GetArgValue(args, "--ime-log-path");
|
||||
var imeMatchLogPath = GetArgValue(args, "--ime-match-log");
|
||||
|
||||
// Dev / test — IME log replay (V1 compat mode). Feeds ImeLogTracker.SimulationMode
|
||||
// + SpeedFactor so recorded raw IME logs are replayed at an accelerated rate; signal
|
||||
// timestamps + ingress ordinals are regenerated as the replay runs.
|
||||
var replayLogDir = GetArgValue(args, "--replay-log-dir");
|
||||
var replaySpeedFactorRaw = GetArgValue(args, "--replay-speed-factor");
|
||||
var replaySpeedFactor = 50.0;
|
||||
if (!string.IsNullOrEmpty(replaySpeedFactorRaw)
|
||||
&& double.TryParse(replaySpeedFactorRaw, System.Globalization.NumberStyles.Float,
|
||||
System.Globalization.CultureInfo.InvariantCulture, out var parsedSpeed)
|
||||
&& parsedSpeed > 0)
|
||||
{
|
||||
replaySpeedFactor = parsedSpeed;
|
||||
}
|
||||
|
||||
var bootstrapToken = GetArgValue(args, "--bootstrap-token")
|
||||
?? bootstrapConfig?.BootstrapToken;
|
||||
|
||||
@@ -1169,6 +1183,8 @@ namespace AutopilotMonitor.Agent.V2
|
||||
KeepLogFile = keepLogFile,
|
||||
SelfDestructOnComplete = !noCleanup,
|
||||
CommandLineArgs = FormatArgsForLog(args),
|
||||
ReplayLogDir = replayLogDir,
|
||||
ReplaySpeedFactor = replaySpeedFactor,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1269,6 +1285,10 @@ namespace AutopilotMonitor.Agent.V2
|
||||
Console.Out.WriteLine(" --api-url <URL> Override backend API base URL (alias: --backend-api)");
|
||||
Console.Out.WriteLine(" --ime-log-path <PATH> Override IME logs directory");
|
||||
Console.Out.WriteLine(" --ime-match-log <PATH> Write matched IME log lines to file (debug)");
|
||||
Console.Out.WriteLine();
|
||||
Console.Out.WriteLine("Dev / Test:");
|
||||
Console.Out.WriteLine(" --replay-log-dir <PATH> Replay IME logs from this directory (simulation mode)");
|
||||
Console.Out.WriteLine(" --replay-speed-factor <N> Time-compression factor for log replay (default: 50)");
|
||||
}
|
||||
|
||||
private static void PrintVersion()
|
||||
|
||||
@@ -1 +1 @@
|
||||
104
|
||||
106
|
||||
|
||||
@@ -1 +1 @@
|
||||
1073
|
||||
1074
|
||||
|
||||
Reference in New Issue
Block a user