Merge wt/step-logs-t7: Task 7 Log on compile surface, sandboxes, editor hosts

This commit is contained in:
Joseph Doherty
2026-09-09 12:34:29 -04:00
7 changed files with 213 additions and 0 deletions
@@ -28,6 +28,14 @@ public class InboundScriptHost
/// </summary>
public DatabaseAccessor Database { get; } = new();
/// <summary>
/// Leveled per-run logging. Editor mirror of
/// ZB.MOM.WW.ScadaBridge.InboundAPI.InboundScriptLogger (step logs design 2026-09-09 D4);
/// shares <see cref="SandboxLog"/> with the Test Run sandbox because only the signatures
/// matter here — analysis never invokes it.
/// </summary>
public SandboxLog Log { get; } = new();
/// <summary>
/// The cancellation token for the operation.
/// </summary>
@@ -26,6 +26,13 @@ public class SandboxInboundScriptHost
/// <summary>Gets the database accessor; every call throws <see cref="ScriptSandboxException"/> in a test run.</summary>
public DatabaseAccessor Database { get; } = new();
/// <summary>
/// Sandbox mirror of the inbound runtime's <c>Log</c> global (step logs design 2026-09-09 D4).
/// Present so a method script that logs BINDS in the Test Run editor; lines go to the Test Run
/// console pane and are never audited.
/// </summary>
public SandboxLog Log { get; } = new();
/// <summary>
/// Mirror of ZB.MOM.WW.ScadaBridge.InboundAPI.InboundDatabaseHelper — signatures match
/// the runtime helper so the same user code compiles, but every call throws because a
@@ -87,6 +87,58 @@ public class SandboxScriptHost
/// would show a spurious CS1061 on a script that deploys and runs perfectly.
/// </summary>
public SandboxAlarmsAccessor Alarms { get; } = new();
/// <summary>
/// Sandbox mirror of the site runtime's <c>Log</c> 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. Delegates to <see cref="SandboxInstanceContext.Log"/>
/// exactly as the runtime's <c>ScriptGlobals.Log =&gt; Instance.Log</c> does, so
/// <c>Log</c> and <c>Instance.Log</c> are the same object here too.
/// </summary>
public SandboxLog Log => Instance.Log;
}
/// <summary>
/// Sandbox mirror of <c>ZB.MOM.WW.ScadaBridge.SiteRuntime.Scripts.ScriptLogger</c> (step logs
/// design 2026-09-09 D4). Signature-faithful so the same script body compiles here and at a site,
/// but a Test Run has no execution to trace and no audit trail: every line is written to
/// <see cref="Console.Out"/>, which the sandbox captures into
/// <c>SandboxRunResult.ConsoleOutput</c> (see <see cref="SandboxConsoleCapture"/>) and shows in
/// the editor's console pane. Nothing here reaches the node log or the audit log.
/// </summary>
public class SandboxLog
{
/// <summary>Writes a debug-level line to the Test Run console pane.</summary>
/// <param name="message">The message text.</param>
/// <param name="exception">An optional exception, rendered on a following line.</param>
public void Debug(string message, Exception? exception = null) => Write("debug", message, exception);
/// <summary>Writes an information-level line to the Test Run console pane.</summary>
/// <param name="message">The message text.</param>
/// <param name="exception">An optional exception, rendered on a following line.</param>
public void Info(string message, Exception? exception = null) => Write("info", message, exception);
/// <summary>Writes a warning-level line to the Test Run console pane.</summary>
/// <param name="message">The message text.</param>
/// <param name="exception">An optional exception, rendered on a following line.</param>
public void Warn(string message, Exception? exception = null) => Write("warn", message, exception);
/// <summary>
/// Writes an error-level line to the Test Run console pane. Like the runtime logger, this
/// does NOT fail the run — it is a message, not a throw.
/// </summary>
/// <param name="message">The message text.</param>
/// <param name="exception">An optional exception, rendered on a following line.</param>
public void Error(string message, Exception? exception = null) => Write("error", message, exception);
private static void Write(string level, string message, Exception? exception)
{
Console.Out.WriteLine($"[{level}] {message}");
if (exception != null)
{
Console.Out.WriteLine(exception.ToString());
}
}
}
/// <summary>
@@ -193,6 +245,12 @@ public class SandboxInstanceContext
/// </summary>
public SandboxScriptCallHelper Scripts { get; }
/// <summary>
/// Sandbox mirror of <c>ScriptRuntimeContext.Log</c> (step logs design 2026-09-09 D4), so
/// <c>Instance.Log.Info("…")</c> binds and prints in the Test Run console pane.
/// </summary>
public SandboxLog Log { get; } = new();
/// <summary>
/// Initializes a new instance of the SandboxInstanceContext.
/// </summary>
@@ -67,6 +67,9 @@ public sealed class ScriptCompileSurface
/// <summary>Mirrors <c>ScriptGlobals.Alarms</c>.</summary>
public CompileAlarmsAccessor Alarms => throw new NotSupportedException(CompileOnly);
/// <summary>Mirrors <c>ScriptGlobals.Log</c>.</summary>
public CompileLog Log => throw new NotSupportedException(CompileOnly);
/// <summary>Compile-only mirror of <c>ScriptRuntimeContext</c> (the <c>Instance</c> global).</summary>
public sealed class CompileInstance
{
@@ -104,6 +107,38 @@ public sealed class ScriptCompileSurface
/// <summary>Mirrors <c>ScriptRuntimeContext.Alarms</c>.</summary>
public CompileAlarmsAccessor Alarms => throw new NotSupportedException(CompileOnly);
/// <summary>Mirrors <c>ScriptRuntimeContext.Log</c>.</summary>
public CompileLog Log => throw new NotSupportedException(CompileOnly);
}
/// <summary>
/// Compile-only mirror of <c>ScriptLogger</c> (step logs design 2026-09-09 D4) — the
/// <c>Log</c> global a script writes leveled lines through. The optional
/// <c>exception</c> parameter is mirrored so <c>Log.Warn("…", ex)</c> binds at design
/// time exactly as it does at the site.
/// </summary>
public sealed class CompileLog
{
/// <summary>Mirrors <c>ScriptLogger.Debug</c>.</summary>
/// <param name="message">The message text.</param>
/// <param name="exception">An optional exception to attach to the line.</param>
public void Debug(string message, Exception? exception = null) => throw new NotSupportedException(CompileOnly);
/// <summary>Mirrors <c>ScriptLogger.Info</c>.</summary>
/// <param name="message">The message text.</param>
/// <param name="exception">An optional exception to attach to the line.</param>
public void Info(string message, Exception? exception = null) => throw new NotSupportedException(CompileOnly);
/// <summary>Mirrors <c>ScriptLogger.Warn</c>.</summary>
/// <param name="message">The message text.</param>
/// <param name="exception">An optional exception to attach to the line.</param>
public void Warn(string message, Exception? exception = null) => throw new NotSupportedException(CompileOnly);
/// <summary>Mirrors <c>ScriptLogger.Error</c>.</summary>
/// <param name="message">The message text.</param>
/// <param name="exception">An optional exception to attach to the line.</param>
public void Error(string message, Exception? exception = null) => throw new NotSupportedException(CompileOnly);
}
/// <summary>