feat(notification-outbox): populate SourceScript on outbound notifications

FU3: thread the executing script identifier from the script-execution
context down to the Notify outbox API so NotifyTarget.Send stamps
NotificationSubmit.SourceScript instead of leaving it null.

- ScriptRuntimeContext / NotifyHelper / NotifyTarget take an optional
  sourceScript value, carried through to NotificationSubmit.SourceScript.
- ScriptExecutionActor supplies "ScriptActor:<scriptName>", matching the
  Site Event Logging "Source" convention used for script error events.
- AlarmExecutionActor builds the context without the S&F engine, so its
  Notify API is inert; sourceScript defaults to null there.
This commit is contained in:
Joseph Doherty
2026-05-19 03:54:09 -04:00
parent a5653b4296
commit 558f9ceb39
3 changed files with 62 additions and 8 deletions

View File

@@ -58,13 +58,16 @@ public class NotifyHelperTests : TestKit, IAsyncLifetime, IDisposable
base.Dispose(disposing);
}
private ScriptRuntimeContext.NotifyHelper CreateHelper(IActorRef siteCommunicationActor)
private ScriptRuntimeContext.NotifyHelper CreateHelper(
IActorRef siteCommunicationActor,
string? sourceScript = null)
{
return new ScriptRuntimeContext.NotifyHelper(
_saf,
siteCommunicationActor,
"site-7",
"Plant.Pump3",
sourceScript,
TimeSpan.FromSeconds(3),
NullLogger.Instance);
}
@@ -113,6 +116,36 @@ public class NotifyHelperTests : TestKit, IAsyncLifetime, IDisposable
Assert.Equal("Plant.Pump3", payload.SourceInstanceId);
}
[Fact]
public async Task Send_WhenHelperHasSourceScript_StampsItOnTheNotificationSubmit()
{
var commProbe = CreateTestProbe();
var notify = CreateHelper(commProbe.Ref, sourceScript: "ScriptActor:MonitorSpeed");
var notificationId = await notify.To("Operators").Send("Pump alarm", "Pump 3 tripped");
var buffered = await _saf.GetMessageByIdAsync(notificationId);
Assert.NotNull(buffered);
var payload = JsonSerializer.Deserialize<NotificationSubmit>(buffered!.PayloadJson);
Assert.NotNull(payload);
// FU3: the executing script name is threaded down and stamped for the audit trail.
Assert.Equal("ScriptActor:MonitorSpeed", payload!.SourceScript);
}
[Fact]
public async Task Send_WhenHelperHasNoSourceScript_LeavesSourceScriptNull()
{
var commProbe = CreateTestProbe();
var notify = CreateHelper(commProbe.Ref, sourceScript: null);
var notificationId = await notify.To("Operators").Send("Pump alarm", "Pump 3 tripped");
var buffered = await _saf.GetMessageByIdAsync(notificationId);
var payload = JsonSerializer.Deserialize<NotificationSubmit>(buffered!.PayloadJson);
Assert.Null(payload!.SourceScript);
}
[Fact]
public async Task Status_WhenStillBufferedAtSite_ReportsForwarding()
{