fix: make p-rec-update initialization load-safe
This commit is contained in:
@@ -1,6 +1,10 @@
|
|||||||
/link/
|
/link/
|
||||||
/link
|
/link
|
||||||
|
|
||||||
|
# Generated build output is never source or package input.
|
||||||
|
**/bin/
|
||||||
|
**/obj/
|
||||||
|
|
||||||
# DocumentAutomation generated files and local source data
|
# DocumentAutomation generated files and local source data
|
||||||
DocumentAutomation/**/bin/
|
DocumentAutomation/**/bin/
|
||||||
DocumentAutomation/**/obj/
|
DocumentAutomation/**/obj/
|
||||||
|
|||||||
@@ -9,9 +9,19 @@ public sealed class EntryPoint : IExtensionApplication
|
|||||||
{
|
{
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
RuntimeMarker.Write("AssemblyInitializeStarted");
|
// Keep the load boundary free of Plant/DataLinks access. Any exception
|
||||||
|
// here must remain observable independently of a project fixture.
|
||||||
|
RuntimeMarker.Write("InitializeEntered");
|
||||||
|
try
|
||||||
|
{
|
||||||
RuntimeMarker.Write("AssemblyInitializeCompleted");
|
RuntimeMarker.Write("AssemblyInitializeCompleted");
|
||||||
}
|
}
|
||||||
|
catch (System.Exception exception)
|
||||||
|
{
|
||||||
|
RuntimeMarker.Write("AssemblyInitializeFailed", exception.GetType().Name + ":" + exception.Message);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Terminate() => RuntimeMarker.Write("AssemblyTerminateCompleted");
|
public void Terminate() => RuntimeMarker.Write("AssemblyTerminateCompleted");
|
||||||
|
|
||||||
@@ -37,8 +47,27 @@ public sealed class EntryPoint : IExtensionApplication
|
|||||||
},
|
},
|
||||||
UpdateExecutionMode.DryRun,
|
UpdateExecutionMode.DryRun,
|
||||||
ControlledFixturePermit: false));
|
ControlledFixturePermit: false));
|
||||||
|
var status = new
|
||||||
|
{
|
||||||
|
schemaVersion = 1,
|
||||||
|
operationId = Environment.GetEnvironmentVariable("P_REC_UPDATE_OPERATION_ID") ?? "unknown",
|
||||||
|
processId = Environment.ProcessId,
|
||||||
|
command,
|
||||||
|
assemblyVersion = typeof(EntryPoint).Assembly.GetName().Version?.ToString(),
|
||||||
|
assemblySha256 = RuntimeMarker.AssemblySha256(),
|
||||||
|
product = "Plant3D",
|
||||||
|
productYear = 2026,
|
||||||
|
activeDocumentPresent = document is not null,
|
||||||
|
activePlantProjectPresent = HasPlantProject(),
|
||||||
|
dryRunInfrastructure = "Available",
|
||||||
|
domainApply = "BlockedByExactFixture",
|
||||||
|
diagnostics = plan.Diagnostics
|
||||||
|
};
|
||||||
document?.Editor.WriteMessage($"\nP_Rec_Update {command}: {(plan.Accepted ? "DryRun planned; no project data changed." : string.Join(", ", plan.Diagnostics))}");
|
document?.Editor.WriteMessage($"\nP_Rec_Update {command}: {(plan.Accepted ? "DryRun planned; no project data changed." : string.Join(", ", plan.Diagnostics))}");
|
||||||
RuntimeMarker.Write(plan.Accepted ? "CommandRegistrationVerified" : "CommandPreflightRejected");
|
// STATUS proves registration and reports preflight state; it must not
|
||||||
|
// be classified as a failed command merely because no controlled Plant
|
||||||
|
// project fixture is open.
|
||||||
|
RuntimeMarker.Write(command == "P-R-UPD-STATUS" || plan.Accepted ? "CommandRegistrationVerified" : "CommandPreflightRejected", System.Text.Json.JsonSerializer.Serialize(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool HasPlantProject()
|
private static bool HasPlantProject()
|
||||||
|
|||||||
@@ -1,19 +1,30 @@
|
|||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace PRecUpdate.Plant3D2026;
|
namespace PRecUpdate.Plant3D2026;
|
||||||
|
|
||||||
internal static class RuntimeMarker
|
internal static class RuntimeMarker
|
||||||
{
|
{
|
||||||
internal static void Write(string state)
|
internal static void Write(string state, string? detail = null)
|
||||||
{
|
{
|
||||||
var root = Environment.GetEnvironmentVariable("P_REC_UPDATE_MARKER_ROOT");
|
var root = Environment.GetEnvironmentVariable("P_REC_UPDATE_MARKER_ROOT");
|
||||||
if (string.IsNullOrWhiteSpace(root)) return;
|
if (string.IsNullOrWhiteSpace(root)) return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(root);
|
Directory.CreateDirectory(root);
|
||||||
var payload = $"{DateTimeOffset.UtcNow:O}|{state}|{typeof(EntryPoint).Assembly.GetName().Name}";
|
var payload = JsonSerializer.Serialize(new
|
||||||
File.WriteAllText(Path.Combine(root, state + ".marker"), payload, new UTF8Encoding(false));
|
{
|
||||||
|
schemaVersion = 1,
|
||||||
|
operationId = Environment.GetEnvironmentVariable("P_REC_UPDATE_OPERATION_ID") ?? "unknown",
|
||||||
|
processId = Environment.ProcessId,
|
||||||
|
timestampUtc = DateTimeOffset.UtcNow,
|
||||||
|
state,
|
||||||
|
detail,
|
||||||
|
assembly = typeof(EntryPoint).Assembly.GetName().Name,
|
||||||
|
assemblySha256 = AssemblySha256()
|
||||||
|
});
|
||||||
|
File.WriteAllText(Path.Combine(root, state + ".marker.json"), payload, new UTF8Encoding(false));
|
||||||
}
|
}
|
||||||
catch { /* Evidence cannot make Plant initialization fail. */ }
|
catch { /* Evidence cannot make Plant initialization fail. */ }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,4 +46,17 @@ public sealed class UpdatePlanBuilderTests
|
|||||||
Assert.True(plan.MayWriteDrawing);
|
Assert.True(plan.MayWriteDrawing);
|
||||||
Assert.True(plan.MayWriteProjectData);
|
Assert.True(plan.MayWriteProjectData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Status_probe_preflight_is_deterministic_and_never_write_capable()
|
||||||
|
{
|
||||||
|
var request = new UpdateRequest(true, false, false, new HashSet<UpdateOperation>(), UpdateExecutionMode.DryRun, false);
|
||||||
|
var first = builder.Build(request);
|
||||||
|
var second = builder.Build(request);
|
||||||
|
Assert.False(first.Accepted);
|
||||||
|
Assert.Equal(first.Diagnostics, second.Diagnostics);
|
||||||
|
Assert.False(first.MayWriteDrawing);
|
||||||
|
Assert.False(first.MayWriteProjectData);
|
||||||
|
Assert.Contains("PLANT_PROJECT_REQUIRED", first.Diagnostics);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user