diff --git a/.gitignore b/.gitignore index 0a7b712b..0075c1c1 100644 --- a/.gitignore +++ b/.gitignore @@ -62,3 +62,6 @@ lib/ # Subagent-driven-development git worktrees .worktrees/ + +# Local OPC UA validation runs; selected receipts belong under docs/plans/evidence. +/artifacts/opcua2/ diff --git a/docs/plans/evidence/2026-11-10-sdk1-terminal-disposal.json b/docs/plans/evidence/2026-11-10-sdk1-terminal-disposal.json new file mode 100644 index 00000000..07716962 --- /dev/null +++ b/docs/plans/evidence/2026-11-10-sdk1-terminal-disposal.json @@ -0,0 +1,349 @@ +{ + "issue": 807, + "scope": "SDK1 host terminal-disposal repair; independent of SDK2 migration release acceptance.", + "originalMaster": "52d1373e8129b7f4f0ea2e35f86a8a5d0ed1de36", + "redSource": "84bfe6cd20285ccf136998998ef5c051917d8201", + "greenSource": "10edc44f94afc42300518f1504091c58217a89a9", + "redProductionEqualsOriginalMaster": true, + "redOriginalProductionSha256": "346362c8c18b5bcdb90757f654c02c68bad44fc5875abc8b4672f4c7ac49b381", + "greenProductionSha256": "c4934b15e695a4110e8cea8fbdef8faabad80aadeca4ccfb007b11400057ff9b", + "resolvedSdkPackages": [ + "OPCFoundation.NetStandard.Opc.Ua.Configuration/1.5.378.182", + "OPCFoundation.NetStandard.Opc.Ua.Core/1.5.378.182", + "OPCFoundation.NetStandard.Opc.Ua.Security.Certificates/1.5.378.182", + "OPCFoundation.NetStandard.Opc.Ua.Server/1.5.378.182", + "OPCFoundation.NetStandard.Opc.Ua.Types/1.5.378.182" + ], + "builds": [ + { + "rawLogPath": "/tmp/opcua-sdk1-terminal-red-build.log", + "sha256": "38f5561a0db2a2d26f8462f36e114ced057c189effcd6e87dc5a62a42c06d52e", + "warnings": 0, + "errors": 0 + }, + { + "rawLogPath": "/tmp/opcua-sdk1-terminal-green-build.log", + "sha256": "5fae318d45d9b5b8b4ba2812ef87869edf6d851e09848154d5f4a51f47ed68d2", + "warnings": 0, + "errors": 0 + }, + { + "rawLogPath": "/tmp/opcua-sdk1-terminal-solution-build.log", + "sha256": "13317ee89238730216874531fad82e3591a6d0d1b5503c8bd896dcc95c885daf", + "warnings": 0, + "errors": 0 + } + ], + "runs": [ + { + "source": "84bfe6cd20285ccf136998998ef5c051917d8201", + "rawDirectory": "artifacts/opcua2/84bfe6cd/sdk1-terminal-red", + "command": [ + "dotnet", + "test", + "tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.csproj", + "-c", + "Release", + "--no-build", + "--no-restore", + "--filter", + "FullyQualifiedName~OpcUaApplicationHostDisposalTests", + "--logger", + "trx;LogFileName=close.trx", + "--results-directory", + "artifacts/opcua2/84bfe6cd/sdk1-terminal-red" + ], + "testExit": 1, + "guardPassed": true, + "runnerSeconds": 3.8918902919394895, + "counters": { + "total": "5", + "executed": "5", + "passed": "0", + "failed": "5", + "error": "0", + "timeout": "0", + "aborted": "0", + "inconclusive": "0", + "passedButRunAborted": "0", + "notRunnable": "0", + "notExecuted": "0", + "disconnected": "0", + "warning": "0", + "completed": "0", + "inProgress": "0", + "pending": "0" + }, + "selectedResults": [ + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostDisposalTests.Host_terminally_disposes_its_booted_server_once", + "outcome": "Failed", + "error": "Shouldly.ShouldAssertException : server.TerminalDisposals\r\n should be\r\n1\r\n but was\r\n0" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostDisposalTests.Concurrent_disposers_share_completion_and_one_cleanup_owner", + "outcome": "Failed", + "error": "Shouldly.ShouldAssertException : server.StopCalls\r\n should be\r\n1\r\n but was\r\n4" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostDisposalTests.Disposed_host_rejects_start_without_taking_server_ownership", + "outcome": "Failed", + "error": "Shouldly.ShouldAssertException : Task `host.StartAsync(server, Ct)`\r\n should throw\r\nSystem.ObjectDisposedException\r\n but did not" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostDisposalTests.Stop_failure_still_terminally_disposes_the_server", + "outcome": "Failed", + "error": "Shouldly.ShouldAssertException : server.TerminalDisposals\r\n should be\r\n1\r\n but was\r\n0" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostDisposalTests.Partial_startup_failure_does_not_strand_the_server", + "outcome": "Failed", + "error": "Shouldly.ShouldAssertException : server.TerminalDisposals\r\n should be\r\n1\r\n but was\r\n0" + } + ], + "rawHashes": { + "close.trx": "ec832633adf184a07f31075ff342bb2c1b9d3f3893c518f5737dc02526f886bb", + "run.log": "cdb7c4982d45807de53f70dfc22fad69ccda1db740db05407cef8df8b6b6d904", + "receipt.json": "4469c071c0d178446ccfdbdca4bf11ebad43c33feb91d8a8c5f2fa891579f2dc" + } + }, + { + "source": "10edc44f94afc42300518f1504091c58217a89a9", + "rawDirectory": "artifacts/opcua2/10edc44f/sdk1-terminal-green", + "command": [ + "dotnet", + "test", + "tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.csproj", + "-c", + "Release", + "--no-build", + "--no-restore", + "--filter", + "FullyQualifiedName~OpcUaApplicationHostDisposalTests", + "--logger", + "trx;LogFileName=close.trx", + "--results-directory", + "artifacts/opcua2/10edc44f/sdk1-terminal-green" + ], + "testExit": 0, + "guardPassed": true, + "runnerSeconds": 3.336757709039375, + "counters": { + "total": "5", + "executed": "5", + "passed": "5", + "failed": "0", + "error": "0", + "timeout": "0", + "aborted": "0", + "inconclusive": "0", + "passedButRunAborted": "0", + "notRunnable": "0", + "notExecuted": "0", + "disconnected": "0", + "warning": "0", + "completed": "0", + "inProgress": "0", + "pending": "0" + }, + "selectedResults": [ + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostDisposalTests.Partial_startup_failure_does_not_strand_the_server", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostDisposalTests.Concurrent_disposers_share_completion_and_one_cleanup_owner", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostDisposalTests.Host_terminally_disposes_its_booted_server_once", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostDisposalTests.Stop_failure_still_terminally_disposes_the_server", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostDisposalTests.Disposed_host_rejects_start_without_taking_server_ownership", + "outcome": "Passed" + } + ], + "rawHashes": { + "close.trx": "c44ba287659af567fcba1209c147aa5bfb6f2fc27753c0923d08b92372c007b4", + "run.log": "7f68723461a5ac4154c247b8bdfcc6d3770a5c1c1a88016051ef492f1684c88e", + "receipt.json": "bea02609e11dcc4569a26add9ae5836b101bf107d0346dd34514fc1d114ba525" + } + }, + { + "source": "10edc44f94afc42300518f1504091c58217a89a9", + "rawDirectory": "artifacts/opcua2/10edc44f/sdk1-server-suite", + "command": [ + "dotnet", + "test", + "tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.csproj", + "-c", + "Release", + "--no-build", + "--no-restore", + "--logger", + "trx;LogFileName=close.trx", + "--results-directory", + "artifacts/opcua2/10edc44f/sdk1-server-suite" + ], + "testExit": 0, + "guardPassed": true, + "runnerSeconds": 119.36682745895814, + "counters": { + "total": "1033", + "executed": "1032", + "passed": "1032", + "failed": "0", + "error": "0", + "timeout": "0", + "aborted": "0", + "inconclusive": "0", + "passedButRunAborted": "0", + "notRunnable": "0", + "notExecuted": "0", + "disconnected": "0", + "warning": "0", + "completed": "0", + "inProgress": "0", + "pending": "0" + }, + "selectedResults": [ + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.AddressSpaceComposerDeviceHostTests.Compose_resolves_driver_device_and_device_host", + "outcome": "NotExecuted", + "error": "v3: equipment no longer binds a driver/device \u2014 Equipment lost DriverInstanceId/DeviceId and Compose no longer takes a devices list, so EquipmentNode's DriverInstanceId/DeviceId/DeviceHost projection is always null. Equipment references raw tags via UnsTagReference. The device-endpoint merge this suite characterized now lives in Runtime.Tests DeploymentArtifactRawPathTests; the host-extraction unit is Commons.Tests DeviceConfigIntentTests." + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostDisposalTests.Host_terminally_disposes_its_booted_server_once", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostSecurityTests.BuildSecurityPolicies_empty_input_falls_back_to_none", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostTests.StartAsync_creates_application_certificate_in_pki_own", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostQuotaTests.Configured_transport_quotas_replace_only_what_is_set", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostSecurityTests.BuildSecurityPolicies_default_set_emits_all_three_baseline_profiles", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostDisposalTests.Partial_startup_failure_does_not_strand_the_server", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostSecurityTests.BuildUserTokenPolicies_withholds_anonymous_when_disallowed", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostImpersonationTests.NullOpcUaUserAuthenticator_always_denies", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostQuotaTests.Configured_request_quotas_are_applied", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostImpersonationTests.HandleImpersonation_anonymous_token_is_rejected_when_disallowed", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostImpersonationTests.HandleImpersonation_username_success_sets_identity_and_no_validation_error", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostDisposalTests.Disposed_host_rejects_start_without_taking_server_ownership", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostServerArrayTests.ServerArray_contains_local_uri_and_configured_peers_after_start", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostQuotaTests.Default_request_quotas_are_the_former_hard_coded_values", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostSecurityTests.StartAsync_with_only_signandencrypt_omits_None_endpoint", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostDisposalTests.Concurrent_disposers_share_completion_and_one_cleanup_owner", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostQuotaTests.Unset_transport_quotas_keep_the_sdk_defaults", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostDisposalTests.Stop_failure_still_terminally_disposes_the_server", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostImpersonationTests.HandleImpersonation_anonymous_token_is_admitted_with_a_role_carrying_identity", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostSecurityTests.StartAsync_populates_ServerConfiguration_with_all_enabled_profiles", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostTests.StartAsync_reuses_existing_certificate_on_second_boot", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostImpersonationTests.HandleImpersonation_username_denial_sets_validation_error_and_no_identity", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostQuotaTests.History_read_batch_cap_default_scales_with_the_machine", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostSecurityTests.BuildSecurityPolicies_dedupes_repeated_profiles", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostImpersonationTests.HandleImpersonation_authenticator_throwing_results_in_rejection", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostImpersonationTests.HandleImpersonation_null_username_treated_as_empty_string", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostImpersonationTests.HandleImpersonation_username_success_carries_roles_on_identity", + "outcome": "Passed" + }, + { + "name": "ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests.OpcUaApplicationHostSecurityTests.BuildUserTokenPolicies_emits_anonymous_and_username", + "outcome": "Passed" + } + ], + "rawHashes": { + "close.trx": "800ac4134f48fc901da2c3519573184337c3f9a22cc5e7a5f4859a6b586fbf70", + "run.log": "253457c47f8801d37ce5fafc5c95cb9f5f0a9bbcead363c4ad0f5256e18fc7df", + "receipt.json": "b0db91f846ca883c8b8d48a946021f5e99785a26c37ff1087187b83575f62c96" + } + } + ], + "existingSkip": "AddressSpaceComposerDeviceHostTests.Compose_resolves_driver_device_and_device_host", + "newSkips": 0, + "ownership": "One caller owns detach/Stop/terminal Dispose; all Dispose callers await shared completion; Start after disposal begins is rejected.", + "limits": [ + "Does not serialize an already-running asynchronous Start against Dispose.", + "Does not alter immutable83ed880e baseline publications or aggregate regression oracles.", + "Does not establish any relative RSS denominator, #799 acceptance or SDK2 release approval." + ], + "review": "Astra approved the isolated SDK1 source/result/package gate: byte-identical original production RED; five expected REDs and five GREENs; 1032 owning-suite passes with one existing skip; all build hashes and selected security/PKI results verified. No SDK2 release or performance-baseline approval." +}