Merge #574/#576/#577/#584: AB forms preserve unknown keys + write factory ms keys, /raw device-name + prerender fixes, CLI read prints Bad status, docs dot-form

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
Joseph Doherty
2026-10-07 23:03:48 -04:00
19 changed files with 587 additions and 34 deletions
@@ -64,6 +64,9 @@ public sealed class AbCipTransportSwitchTests
"ab1", """{"devices":[{"hostAddress":"ab://10.0.0.1/1,0","plcFamily":"Bogus"}]}"""));
existing.GetType().ShouldBe(bad.GetType());
existing.Message.ShouldContain("unknown PlcFamily 'Bogus'");
// #574: a device-level field must not be reported as a tag named 'device'.
existing.Message.ShouldNotContain("tag '");
existing.Message.ShouldStartWith("AB CIP config in 'ab1' has unknown PlcFamily 'Bogus'");
}
/// <summary>
@@ -145,6 +148,9 @@ public sealed class AbCipTransportSwitchTests
native.Message.ShouldNotBeNull();
native.Message!.ShouldContain("CIP handshake failed: Connection lost");
lib.Message!.ShouldNotContain("Connection lost");
// Positive (#574): the libplctag path ran and reported its own outcome (the bounded probe timeout),
// not merely "something other than the native text".
lib.Message!.ShouldContain("timed out");
}
/// <summary>
@@ -180,6 +186,9 @@ public sealed class AbCipTransportSwitchTests
absent.Ok.ShouldBeFalse();
absent.Message!.ShouldContain("CIP handshake failed: Connection lost");
lib.Message!.ShouldNotContain("Connection lost");
// Positive (#574): the libplctag path ran and reported its own outcome (the bounded probe timeout),
// not merely "something other than the native text".
lib.Message!.ShouldContain("timed out");
}
/// <summary>The probe deserialises with its own string-enum converter; a bad transport is a config error.</summary>
@@ -259,6 +268,7 @@ public sealed class AbCipTransportSwitchTests
unpinned.Message!.ShouldContain("CIP handshake failed: Connection lost");
pinned.Ok.ShouldBeFalse();
pinned.Message!.ShouldNotContain("Connection lost");
pinned.Message!.ShouldContain("timed out"); // positive: libplctag's own outcome (#574)
}
/// <summary>Gitea #572: <c>browsePageDelayMs</c> parses (default 5 ms, 0 allowed, negative clamps to 0).</summary>