diff --git a/src/ZB.MOM.WW.ScadaBridge.CentralUI/ScriptAnalysis/InboundScriptHost.cs b/src/ZB.MOM.WW.ScadaBridge.CentralUI/ScriptAnalysis/InboundScriptHost.cs index 98212fbb..984425ae 100644 --- a/src/ZB.MOM.WW.ScadaBridge.CentralUI/ScriptAnalysis/InboundScriptHost.cs +++ b/src/ZB.MOM.WW.ScadaBridge.CentralUI/ScriptAnalysis/InboundScriptHost.cs @@ -28,6 +28,14 @@ public class InboundScriptHost /// public DatabaseAccessor Database { get; } = new(); + /// + /// Leveled per-run logging. Editor mirror of + /// ZB.MOM.WW.ScadaBridge.InboundAPI.InboundScriptLogger (step logs design 2026-09-09 D4); + /// shares with the Test Run sandbox because only the signatures + /// matter here — analysis never invokes it. + /// + public SandboxLog Log { get; } = new(); + /// /// The cancellation token for the operation. /// diff --git a/src/ZB.MOM.WW.ScadaBridge.CentralUI/ScriptAnalysis/SandboxScriptHost.cs b/src/ZB.MOM.WW.ScadaBridge.CentralUI/ScriptAnalysis/SandboxScriptHost.cs index 9153edab..cce4cda0 100644 --- a/src/ZB.MOM.WW.ScadaBridge.CentralUI/ScriptAnalysis/SandboxScriptHost.cs +++ b/src/ZB.MOM.WW.ScadaBridge.CentralUI/ScriptAnalysis/SandboxScriptHost.cs @@ -91,9 +91,11 @@ public class SandboxScriptHost /// /// Sandbox mirror of the site runtime's Log global (step logs design 2026-09-09 D4). /// Present so a script that logs BINDS in the Test Run editor; lines go to the Test Run - /// console pane and are never audited. + /// console pane and are never audited. Delegates to + /// exactly as the runtime's ScriptGlobals.Log => Instance.Log does, so + /// Log and Instance.Log are the same object here too. /// - public SandboxLog Log { get; } = new(); + public SandboxLog Log => Instance.Log; } /// diff --git a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/ScriptAnalysis/ScriptAnalysisServiceTests.cs b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/ScriptAnalysis/ScriptAnalysisServiceTests.cs index 257aba65..9601c2e4 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/ScriptAnalysis/ScriptAnalysisServiceTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/ScriptAnalysis/ScriptAnalysisServiceTests.cs @@ -695,6 +695,40 @@ public class ScriptAnalysisServiceTests Assert.DoesNotContain(resp.Markers, m => m.Code.StartsWith("SCADA")); } + [Fact] + public void InboundScript_Log_DiagnosesClean() + { + // Flow Debugger step logs (design 2026-09-09 D4): `Log` is a shipped inbound-script + // global (InboundScriptContext.Log). The EDITOR host is a third mirror alongside the + // compile surface and the Test Run sandbox — without `Log` on InboundScriptHost a + // logging method script shows a spurious CS0103 while deploying and running fine. + var resp = _svc.Diagnose(new DiagnoseRequest( + Code: "Log.Info(\"x\");\n" + + "Log.Debug(\"d\");\n" + + "Log.Warn(\"w\", new System.Exception(\"boom\"));\n" + + "Log.Error(\"e\");", + Kind: ScriptKind.InboundApi)); + + Assert.DoesNotContain(resp.Markers, m => m.Code.StartsWith("CS")); + Assert.DoesNotContain(resp.Markers, m => m.Code.StartsWith("SCADA")); + } + + [Fact] + public void SiteScript_Log_DiagnosesClean() + { + // The other half of GlobalsTypeFor: every non-inbound kind analyses against + // SandboxScriptHost, so the same `Log` global must resolve there too — both at + // the top level and via `Instance.Log`. + var resp = _svc.Diagnose(new DiagnoseRequest( + Code: "Log.Info(\"x\");\n" + + "Log.Warn(\"w\", new System.Exception(\"boom\"));\n" + + "Instance.Log.Info(\"via instance\");", + Kind: ScriptKind.Template)); + + Assert.DoesNotContain(resp.Markers, m => m.Code.StartsWith("CS")); + Assert.DoesNotContain(resp.Markers, m => m.Code.StartsWith("SCADA")); + } + [Fact] public void InboundScript_Database_DiagnosesClean() { diff --git a/tests/ZB.MOM.WW.ScadaBridge.ScriptAnalysis.Tests/RoslynScriptCompilerTests.cs b/tests/ZB.MOM.WW.ScadaBridge.ScriptAnalysis.Tests/RoslynScriptCompilerTests.cs index 7ca28a7b..ff4deb26 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.ScriptAnalysis.Tests/RoslynScriptCompilerTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.ScriptAnalysis.Tests/RoslynScriptCompilerTests.cs @@ -140,7 +140,7 @@ public class RoslynScriptCompilerTests } [Fact] - public void Compile_Empty_ForTheLogGlobal() + public void CompilesCleanly_ForTheLogGlobal() { // Flow Debugger step logs (design 2026-09-09 D4): `Log` is a script-reachable // global on the runtime ScriptGlobals AND on ScriptRuntimeContext, so both the