diff --git a/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/FirstLimitedApplyAutomation.cs b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/FirstLimitedApplyAutomation.cs index 619ed4f..34f4372 100644 --- a/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/FirstLimitedApplyAutomation.cs +++ b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/FirstLimitedApplyAutomation.cs @@ -330,22 +330,17 @@ internal sealed class FirstLimitedApplyAutomationCoordinator { if (exitHandlerSubscribed) AcadApplication.Idle -= OnExitIdle; exitHandlerSubscribed = false; - // LifecycleProbe deliberately opens no drawing. It is already - // executing in the first verified Idle callback, where the managed - // quit API has been runtime-confirmed to terminate AutoCAD cleanly. - if (document is null && string.Equals(config?.Phase, "LifecycleProbe", StringComparison.OrdinalIgnoreCase)) - { - transitions.Add("LifecycleProbeApplicationQuitRequested"); - TryWriteEvidence(state == CoordinatorState.Completed, null); - AcadApplication.Quit(); - return; - } - if (document is null) throw new InvalidOperationException("AUTOMATION_EXIT_DOCUMENT_UNAVAILABLE"); + // LifecycleProbe opens no fixture document, but the real startup + // document is available at this point (observed as Drawing1.dwg). + // Use that live document only to queue native QUIT; never retain it + // past this callback or use it for fixture/Plant work. + var exitDocument = document ?? AcadApplication.DocumentManager.MdiActiveDocument; + if (exitDocument is null) throw new InvalidOperationException("AUTOMATION_EXIT_DOCUMENT_UNAVAILABLE"); transitions.Add("NativeQuitCommandQueued"); // Persist the exit boundary before handing control back to AutoCAD; // process termination can otherwise prevent the final evidence flush. TryWriteEvidence(state == CoordinatorState.Completed, null); - document.SendStringToExecute("_.QUIT _N ", true, false, false); + exitDocument.SendStringToExecute("_.QUIT _N ", true, false, false); document = null; automationOpenedDocuments.Clear(); } diff --git a/Plant3D2026/P_Rec_Annot/tests/PRecAnnot.Core.Tests/FoundationTests.cs b/Plant3D2026/P_Rec_Annot/tests/PRecAnnot.Core.Tests/FoundationTests.cs index e121b67..ceffacd 100644 --- a/Plant3D2026/P_Rec_Annot/tests/PRecAnnot.Core.Tests/FoundationTests.cs +++ b/Plant3D2026/P_Rec_Annot/tests/PRecAnnot.Core.Tests/FoundationTests.cs @@ -105,7 +105,7 @@ public sealed class FoundationTests Assert.Contains("AcadApplication.Idle += OnExitIdle", source); Assert.Contains("NativeQuitCommandQueued", source); Assert.Contains("document.SendStringToExecute(\"_.QUIT _N \", true, false, false);", source); - Assert.Contains("LifecycleProbeApplicationQuitRequested", source); + Assert.Contains("var exitDocument = document ?? AcadApplication.DocumentManager.MdiActiveDocument;", source); } [Fact] public void Callback_AfterDocumentDestroyed_DoesNotAccessDocument() @@ -120,7 +120,7 @@ public sealed class FoundationTests var source = File.ReadAllText(Path.Combine(ProjectRoot, "src", "PRecAnnot.Plant3D2026", "FirstLimitedApplyAutomation.cs")); Assert.DoesNotContain("MdiActiveDocument", source[source.IndexOf("private void DispatchNativeQuit", StringComparison.Ordinal)..]); Assert.Contains("AUTOMATION_EXIT_DOCUMENT_UNAVAILABLE", source); - Assert.Contains("if (document is null && string.Equals(config?.Phase, \"LifecycleProbe\"", source); + Assert.Contains("if (exitDocument is null) throw new InvalidOperationException", source); } [Fact] public void TerminalState_IgnoresFurtherCallbacks() @@ -160,7 +160,7 @@ public sealed class FoundationTests var source = File.ReadAllText(Path.Combine(ProjectRoot, "src", "PRecAnnot.Plant3D2026", "FirstLimitedApplyAutomation.cs")); var controlledExit = source[source.IndexOf("private void RequestControlledExit", StringComparison.Ordinal)..]; Assert.DoesNotContain("document.CloseAndDiscard", controlledExit); - Assert.DoesNotContain("MdiActiveDocument", controlledExit); + Assert.Contains("var exitDocument = document ?? AcadApplication.DocumentManager.MdiActiveDocument;", controlledExit); Assert.Contains("document = null;", controlledExit); }