Merge review R1 fixes: removed driver's resilience tracker released; SDK timed-unshelve no-op (engine owns expiry); commented re-ack stored as AddComment; native-ack Primary verdict published from start; drain gate SharesRowsWithPeer; malformed cache bytes don't adopt the revision; HostAbortedException passthrough; ClusterRoleInfo seed filtered

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
Joseph Doherty
2026-10-08 07:47:57 -04:00
28 changed files with 691 additions and 136 deletions
@@ -97,4 +97,30 @@ public sealed class ClusterRoleInfoMemberEventTests
return Task.CompletedTask;
});
}
/// <summary>
/// Review R1 m6: the initial seed lists only Up / WeaklyUp members. A member already departing at seed
/// time never fires a later Left/Exited/Downed event, so seeding it would list it until MemberRemoved.
/// The Up and WeaklyUp members are the positive control (the seed does list members).
/// </summary>
[Fact]
public async Task Initial_seed_lists_only_up_and_weakly_up_members()
{
await WithInfoAsync(info =>
{
var members = ImmutableSortedSet.Create<Member>(
NewMember(21001, MemberStatus.Up),
NewMember(21002, MemberStatus.WeaklyUp),
NewMember(21003, MemberStatus.Leaving),
NewMember(21004, MemberStatus.Exiting),
NewMember(21005, MemberStatus.Down),
NewMember(21006, MemberStatus.Joining));
info.SeedFrom(new ClusterEvent.CurrentClusterState().Copy(members: members));
info.MembersWithRole("driver").Select(n => n.Value).OrderBy(v => v).ShouldBe(
["127.0.0.1:21001", "127.0.0.1:21002"]);
return Task.CompletedTask;
});
}
}
@@ -79,6 +79,28 @@ public sealed class Part9StateMachineTests
r.Emission.ShouldBe(EmissionKind.None);
}
/// <summary>
/// Gitea #597 review m1 — a COMMENTED re-ack records its comment (as AddComment would) so the comment the
/// OPC UA event advertised is durable; the original acknowledge's ack fields are untouched.
/// </summary>
[Fact]
public void Commented_reack_records_the_comment_without_reacknowledging()
{
var active = Part9StateMachine.ApplyPredicate(Fresh(), true, T0.AddSeconds(1)).State;
var acked = Part9StateMachine.ApplyAcknowledge(active, "alice", "first look", T0.AddSeconds(2)).State;
var r = Part9StateMachine.ApplyAcknowledge(acked, "bob", "still on it", T0.AddSeconds(3));
r.Emission.ShouldBe(EmissionKind.CommentAdded);
r.State.Comments.Count.ShouldBe(2);
r.State.Comments[1].User.ShouldBe("bob");
r.State.Comments[1].Kind.ShouldBe("AddComment");
r.State.Comments[1].Text.ShouldBe("still on it");
r.State.LastAckUser.ShouldBe("alice");
r.State.LastAckComment.ShouldBe("first look");
r.State.LastAckUtc.ShouldBe(T0.AddSeconds(2));
}
/// <summary>Verifies that acknowledging without a user throws ArgumentException.</summary>
[Fact]
public void Acknowledge_without_user_throws()