fix(site-runtime): a faulted seed trigger-expression eval adopts nothing instead of replaying as a real false (review 2026-10-21 follow-up L4)

This commit is contained in:
Joseph Doherty
2026-10-22 09:50:31 -04:00
parent d646f816a4
commit 89d8568fdf
3 changed files with 51 additions and 4 deletions
@@ -447,7 +447,7 @@ public class ScriptActor : ReceiveActor, IWithTimers
}
}).PipeTo(self,
success: r => new ExpressionEvalResult(r, seedOnly),
failure: ex => new ExpressionEvalFailed(ex));
failure: ex => new ExpressionEvalFailed(ex, seedOnly));
}
/// <summary>
@@ -483,11 +483,26 @@ public class ScriptActor : ReceiveActor, IWithTimers
/// existing error path (which also increments the health counter), then reuses the
/// false-result path — clearing in-flight, applying the false edge, and draining any
/// pending evaluation — so a transient scheduler fault cannot permanently park the trigger.
/// A faulted SEED evaluation (review 2026-10-21 follow-up L4) carries no truth value at all:
/// it only clears in-flight and drains the pending evaluation, adopting nothing — replaying it
/// as a real false stopped a running WhileTrue timer, and even as a seeded false it would make
/// the next true evaluation look like a fresh edge and fire spuriously.
/// </summary>
private void HandleExpressionEvalFailed(ExpressionEvalFailed msg)
{
LogExpressionError(msg.Cause);
HandleExpressionEvalResult(new ExpressionEvalResult(false));
if (!msg.SeedOnly)
{
HandleExpressionEvalResult(new ExpressionEvalResult(false));
return;
}
_evalInFlight = false;
if (_evalPending)
{
_evalPending = false;
StartExpressionEvaluation(_evalPendingSeedOnly);
}
}
/// <summary>
@@ -929,7 +944,12 @@ public class ScriptActor : ReceiveActor, IWithTimers
/// mapping the actor receives an unhandled Status.Failure and _evalInFlight
/// stays true forever, permanently parking the expression trigger (N2).
/// </summary>
internal sealed record ExpressionEvalFailed(Exception Cause);
/// <param name="Cause">The task fault.</param>
/// <param name="SeedOnly">
/// Whether the faulted evaluation was a seed (01/SR-U1); a faulted seed adopts nothing
/// (review 2026-10-21 follow-up L4).
/// </param>
internal sealed record ExpressionEvalFailed(Exception Cause, bool SeedOnly = false);
}
// ── Trigger config types ──