Resolve all 46 low-severity architecture review findings

This commit is contained in:
Joseph Doherty
2026-09-09 22:56:36 -04:00
parent fef3e7675f
commit 9ee402bbcd
139 changed files with 2621 additions and 1082 deletions
@@ -615,32 +615,31 @@ public class ScriptRuntimeContextTraceEmissionTests : TestKit
}
[Fact]
public async Task RuntimeWarning_InsideATracedWrite_IsAttributedToThatWriteStep()
public async Task TraceWriteFailure_DoesNotCreateDiagnosticTraceRows()
{
var probe = CreateTestProbe();
var collector = new FlowTraceCollector();
// The throwing writer makes EmitTrace log its best-effort "write failed" warning while the
// AttributeWrite step scope is open — exactly the runtime line D6 exists to attribute.
//
// It also PINS THE ANTI-RECURSION PROPERTY: EmitLog's own write fails against this writer
// too, so its "log-line write failed" warning must go to the UNDECORATED logger. Routed
// through the capturing decorator instead, each warning would emit another row whose write
// fails again — an unbounded loop, and this test would hang or blow the row count rather
// than see exactly one ScriptLog row.
var ctx = CreateContext(probe.Ref, new ThrowingAuditWriter(), traced: true, collector);
var call = ctx.SetAttribute("Setpoint", "42");
var cmd = probe.ExpectMsg<SetStaticAttributeCommand>(TimeSpan.FromSeconds(5));
probe.Reply(new SetStaticAttributeResponse(cmd.CorrelationId, InstanceName, "Setpoint", true, null, DateTimeOffset.UtcNow));
await call;
Assert.Single(collector.Snapshot());
Assert.Equal(AuditKind.AttributeWrite, Row(collector.Snapshot().Single()).Kind);
}
var rows = collector.Snapshot();
var write = rows.Single(e => Row(e).Kind == AuditKind.AttributeWrite);
var log = rows.Single(e => Row(e).Kind == AuditKind.ScriptLog);
var extra = ScriptTraceExtra.TryParse(Row(log).Extra)!;
Assert.Equal("runtime", extra.LogSource);
Assert.Equal("warn", extra.LogLevel);
Assert.Equal(write.EventId, extra.StepEventId);
[Fact]
public void Helpers_AreCachedPerContext()
{
var ctx = CreateContext(CreateTestProbe().Ref, null, traced: false, collector: null);
Assert.Same(ctx.Scripts, ctx.Scripts);
Assert.Same(ctx.ExternalSystem, ctx.ExternalSystem);
Assert.Same(ctx.Database, ctx.Database);
Assert.Same(ctx.Notify, ctx.Notify);
Assert.Same(ctx.Alarms, ctx.Alarms);
Assert.Same(ctx.Tracking, ctx.Tracking);
var child = ctx.CreateChildContextForSharedScript(1);
Assert.NotSame(ctx.Scripts, child.Scripts);
}
[Fact]
@@ -784,12 +783,11 @@ public class ScriptRuntimeContextTraceEmissionTests : TestKit
}
/// <summary>
/// Review item 4: step scopes NEST — the batch leg's lines name the batch row, the wait leg's
/// name the wait row, and both unwind so a later line falls back to the run anchor. The
/// throwing writer is again what provokes a runtime line inside each leg.
/// The batch and wait scopes unwind even when trace writes fail; their internal
/// diagnostics stay out of the collector, and the later script line belongs to the run.
/// </summary>
[Fact]
public async Task NestedStepScopes_AttributeEachLegSeparately_AndUnwind()
public async Task NestedStepScopes_IgnoreTraceDiagnostics_AndUnwind()
{
var probe = CreateTestProbe();
var collector = new FlowTraceCollector();
@@ -816,10 +814,8 @@ public class ScriptRuntimeContextTraceEmissionTests : TestKit
var logs = rows.Where(e => Row(e).Kind == AuditKind.ScriptLog)
.Select(e => ScriptTraceExtra.TryParse(Row(e).Extra)!)
.ToList();
Assert.Equal(3, logs.Count);
Assert.Equal(write.EventId, logs[0].StepEventId);
Assert.Equal(wait.EventId, logs[1].StepEventId);
Assert.Null(logs[2].StepEventId);
Assert.Equal(["runtime", "runtime", "script"], logs.Select(l => l.LogSource));
Assert.Single(logs);
Assert.Null(logs[0].StepEventId);
Assert.Equal("script", logs[0].LogSource);
}
}