mirror of
https://github.com/okieselbach/AutopilotMonitor.git
synced 2026-10-25 05:00:07 +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));
|
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(
|
_imeLogHost = new ImeLogHost(
|
||||||
sessionId: sessionId,
|
sessionId: sessionId,
|
||||||
tenantId: tenantId,
|
tenantId: tenantId,
|
||||||
@@ -133,11 +141,13 @@ namespace AutopilotMonitor.Agent.V2.Core.Orchestration
|
|||||||
logger: logger,
|
logger: logger,
|
||||||
ingress: ingress,
|
ingress: ingress,
|
||||||
clock: clock,
|
clock: clock,
|
||||||
imeLogPathOverride: _agentConfig.ImeLogPathOverride,
|
imeLogPathOverride: imeLogFolder,
|
||||||
imeMatchLogPath: _agentConfig.ImeMatchLogPath,
|
imeMatchLogPath: _agentConfig.ImeMatchLogPath,
|
||||||
imePatterns: _remoteConfig.ImeLogPatterns,
|
imePatterns: _remoteConfig.ImeLogPatterns,
|
||||||
stateDirectory: _stateDirectory,
|
stateDirectory: _stateDirectory,
|
||||||
whiteGloveSealingPatternIds: whiteGloveSealingPatternIds);
|
whiteGloveSealingPatternIds: whiteGloveSealingPatternIds,
|
||||||
|
simulationMode: simulationMode,
|
||||||
|
simulationSpeedFactor: _agentConfig.ReplaySpeedFactor);
|
||||||
hosts.Add(_imeLogHost);
|
hosts.Add(_imeLogHost);
|
||||||
|
|
||||||
if (collectors.StallProbeEnabled)
|
if (collectors.StallProbeEnabled)
|
||||||
@@ -401,6 +411,12 @@ namespace AutopilotMonitor.Agent.V2.Core.Orchestration
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal Monitoring.Enrollment.Ime.ImeLogTracker Tracker => _tracker;
|
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(
|
public ImeLogHost(
|
||||||
string sessionId,
|
string sessionId,
|
||||||
string tenantId,
|
string tenantId,
|
||||||
@@ -412,7 +428,9 @@ namespace AutopilotMonitor.Agent.V2.Core.Orchestration
|
|||||||
string? imeMatchLogPath,
|
string? imeMatchLogPath,
|
||||||
List<ImeLogPattern>? imePatterns,
|
List<ImeLogPattern>? imePatterns,
|
||||||
string stateDirectory,
|
string stateDirectory,
|
||||||
IReadOnlyCollection<string>? whiteGloveSealingPatternIds)
|
IReadOnlyCollection<string>? whiteGloveSealingPatternIds,
|
||||||
|
bool simulationMode = false,
|
||||||
|
double simulationSpeedFactor = 50)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
var logFolder = string.IsNullOrEmpty(imeLogPathOverride) ? DefaultImeLogFolder : imeLogPathOverride!;
|
var logFolder = string.IsNullOrEmpty(imeLogPathOverride) ? DefaultImeLogFolder : imeLogPathOverride!;
|
||||||
@@ -428,6 +446,13 @@ namespace AutopilotMonitor.Agent.V2.Core.Orchestration
|
|||||||
matchLogPath: expandedMatchLogPath,
|
matchLogPath: expandedMatchLogPath,
|
||||||
stateDirectory: stateDirectory);
|
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);
|
_adapter = new ImeLogTrackerAdapter(_tracker, ingress, clock, whiteGloveSealingPatternIds);
|
||||||
|
|
||||||
_processWatcher = new ImeProcessWatcher(sessionId, tenantId, onEnrollmentEvent, logger);
|
_processWatcher = new ImeProcessWatcher(sessionId, tenantId, onEnrollmentEvent, logger);
|
||||||
|
|||||||
@@ -1113,7 +1113,7 @@ namespace AutopilotMonitor.Agent.V2
|
|||||||
|
|
||||||
// ---------------------------------------------------------------- Configuration
|
// ---------------------------------------------------------------- Configuration
|
||||||
|
|
||||||
private static AgentConfiguration BuildAgentConfiguration(
|
internal static AgentConfiguration BuildAgentConfiguration(
|
||||||
string[] args,
|
string[] args,
|
||||||
string tenantId,
|
string tenantId,
|
||||||
string sessionId,
|
string sessionId,
|
||||||
@@ -1124,6 +1124,20 @@ namespace AutopilotMonitor.Agent.V2
|
|||||||
var imeLogPathOverride = GetArgValue(args, "--ime-log-path");
|
var imeLogPathOverride = GetArgValue(args, "--ime-log-path");
|
||||||
var imeMatchLogPath = GetArgValue(args, "--ime-match-log");
|
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")
|
var bootstrapToken = GetArgValue(args, "--bootstrap-token")
|
||||||
?? bootstrapConfig?.BootstrapToken;
|
?? bootstrapConfig?.BootstrapToken;
|
||||||
|
|
||||||
@@ -1169,6 +1183,8 @@ namespace AutopilotMonitor.Agent.V2
|
|||||||
KeepLogFile = keepLogFile,
|
KeepLogFile = keepLogFile,
|
||||||
SelfDestructOnComplete = !noCleanup,
|
SelfDestructOnComplete = !noCleanup,
|
||||||
CommandLineArgs = FormatArgsForLog(args),
|
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(" --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-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(" --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()
|
private static void PrintVersion()
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
104
|
106
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1073
|
1074
|
||||||
|
|||||||
Reference in New Issue
Block a user