fix(deploy): hold the Applied ack until the address-space apply outcome is known (#601)

DriverHostActor no longer acks Applied the moment the revision advances. It
asks OpcUaPublishActor for the outcome (RebuildAddressSpace.ReportOutcome) and
acks Applied+Degraded(reason) when the apply was degraded; a missing outcome
times out (60 s, inside the coordinator's 2 min deadline) to a degraded ack,
never a clean one. Re-dispatching a revision whose apply was degraded or is
still unconfirmed re-applies instead of taking the clean idempotent
short-circuit - that re-apply is also what repairs the degraded nodes.
Tests with a bare publish probe use a clean-outcome auto-pilot probe.

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
Joseph Doherty
2026-10-08 17:29:45 -04:00
parent 521e1eb89b
commit 90d7f6dfca
13 changed files with 421 additions and 24 deletions
@@ -112,7 +112,7 @@ public sealed class DriverHostActorDbLessTests : RuntimeActorTestBase
var cache = new RecordingArtifactCache();
var fetcher = new RecordingFetcher(ArtifactBytes());
var deploymentId = DeploymentId.NewId();
var publish = CreateTestProbe();
var publish = this.CreateCleanOutcomePublishProbe();
var coordinator = CreateTestProbe();
var actor = Sys.ActorOf(DriverHostActor.Props(
@@ -141,7 +141,7 @@ public sealed class DriverHostActorDbLessTests : RuntimeActorTestBase
[Fact]
public void DbLessNode_WithLocalDbStore_SpawnsScriptedAlarmHost()
{
var publish = CreateTestProbe();
var publish = this.CreateCleanOutcomePublishProbe();
var actor = Sys.ActorOf(DriverHostActor.Props(
dbFactory: null,
TestNode,
@@ -162,7 +162,7 @@ public sealed class DriverHostActorDbLessTests : RuntimeActorTestBase
[Fact]
public void DbLessNode_WithNoStoreAndNoDbFactory_SkipsScriptedAlarmHost()
{
var publish = CreateTestProbe();
var publish = this.CreateCleanOutcomePublishProbe();
var actor = Sys.ActorOf(DriverHostActor.Props(
dbFactory: null,
TestNode,
@@ -185,7 +185,7 @@ public sealed class DriverHostActorDbLessTests : RuntimeActorTestBase
[Fact]
public void DbBackedNode_WithNoStore_SkipsScriptedAlarmHost()
{
var publish = CreateTestProbe();
var publish = this.CreateCleanOutcomePublishProbe();
var actor = Sys.ActorOf(DriverHostActor.Props(
dbFactory: NewInMemoryDbFactory(),
TestNode,