diff --git a/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/EntryPoint.cs b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/EntryPoint.cs index 81cc99a..f5bda5f 100644 --- a/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/EntryPoint.cs +++ b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/EntryPoint.cs @@ -50,6 +50,12 @@ public sealed class EntryPoint : IExtensionApplication [CommandMethod("PHP_REC_AUTOMATION_START", CommandFlags.Session)] public void AutomationStartCommand() => FirstLimitedApplyAutomationBootstrap.Arm(); + // Test-only command-queue barrier. It deliberately performs no Plant or + // drawing work; its CommandEnded event proves the activated document is + // ready before the coordinator calls the Plant APIs. + [CommandMethod("PHP_REC_AUTOMATION_READY")] + public void AutomationReadyCommand() { } + private static void RunDiagnostic(string commandName) { var operationId = Guid.NewGuid().ToString("N"); diff --git a/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/FirstLimitedApplyAutomation.cs b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/FirstLimitedApplyAutomation.cs index 5de8524..d3bb4c2 100644 --- a/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/FirstLimitedApplyAutomation.cs +++ b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/FirstLimitedApplyAutomation.cs @@ -204,7 +204,7 @@ internal sealed class FirstLimitedApplyAutomationCoordinator { fixtureDocumentActivated = true; transitions.Add("FixtureDocumentActiveAfterOpen"); - TryActivateProjectAndVerifyContext(); + QueueReadinessBarrier(); } } catch (System.Exception ex) { FailFromCallback("Start", ex, "AUTOMATION_START_FAILED"); } @@ -270,11 +270,23 @@ internal sealed class FirstLimitedApplyAutomationCoordinator transitions.Add("CommandQueued:" + command); document.SendStringToExecute(command + " ", true, false, false); } + private void QueueReadinessBarrier() + { + if (IsTerminal || document is null) return; + transitions.Add("ReadinessBarrierQueued"); + document.SendStringToExecute("PHP_REC_AUTOMATION_READY ", true, false, false); + } private void OnCommandEnded(object sender, CommandEventArgs e) { RunCallback("CommandEnded", () => { var name = e.GlobalCommandName?.Trim().TrimStart('.', '_').ToUpperInvariant(); + if (name == "PHP_REC_AUTOMATION_READY") + { + transitions.Add("ReadinessBarrierCompleted"); + TryActivateProjectAndVerifyContext(); + return; + } if (name is not ("PXP-OA" or "UNDO" or "U")) return; completed.Add(name); transitions.Add("CommandCompleted:" + name); 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 2912731..4debd69 100644 --- a/Plant3D2026/P_Rec_Annot/tests/PRecAnnot.Core.Tests/FoundationTests.cs +++ b/Plant3D2026/P_Rec_Annot/tests/PRecAnnot.Core.Tests/FoundationTests.cs @@ -61,6 +61,7 @@ public sealed class FoundationTests Assert.Contains("[CommandMethod(\"PHP_REC_ANNOT\")]", source); Assert.Contains("[CommandMethod(\"PXP-AAV\")]", source); Assert.Contains("[CommandMethod(\"PXP-OA\")]", source); + Assert.Contains("PHP_REC_AUTOMATION_READY", source); } [Fact] public void AutomationBootstrap_DefersPlantAndDocumentAccessUntilCoordinator() @@ -104,7 +105,9 @@ public sealed class FoundationTests var start = source[source.IndexOf("public void Start()", StringComparison.Ordinal)..source.IndexOf("private void CompleteLifecycleProbe", StringComparison.Ordinal)]; Assert.Contains("FixtureDocumentActiveAfterOpen", start); Assert.Contains("string.Equals(activeDocument.Name, document.Name", start); - Assert.Contains("TryActivateProjectAndVerifyContext();", start); + Assert.Contains("QueueReadinessBarrier();", start); + Assert.Contains("ReadinessBarrierCompleted", source); + Assert.Contains("TryActivateProjectAndVerifyContext();", source); } [Fact] public void AutomationControlledExit_QueuesNativeQuitAfterPublicCommand()