feat: record p-rec-annot selected-view automation evidence

This commit is contained in:
codex
2026-08-10 15:11:40 +03:00
parent 9aad3662ed
commit 9242d2bb08
2 changed files with 9 additions and 3 deletions
@@ -41,6 +41,7 @@ internal static class AutoAnnotateViewCommand
var bubbles = classifications.Count(x => x.Representation == OrthoAnnotationRepresentation.BubbleBlock); var bubbles = classifications.Count(x => x.Representation == OrthoAnnotationRepresentation.BubbleBlock);
document.Editor.WriteMessage($"\nPXP-AAV preview: examined={plan.Summary.ObjectsExamined}; create={plan.Summary.CreateCount}; update={plan.Summary.UpdateCount}; leaders={leaders}; bubbles={bubbles}; skip={plan.Summary.SkipCount}; conflicts={plan.Summary.ConflictCount}; PlanId={plan.PlanId}. DWG не изменён."); document.Editor.WriteMessage($"\nPXP-AAV preview: examined={plan.Summary.ObjectsExamined}; create={plan.Summary.CreateCount}; update={plan.Summary.UpdateCount}; leaders={leaders}; bubbles={bubbles}; skip={plan.Summary.SkipCount}; conflicts={plan.Summary.ConflictCount}; PlanId={plan.PlanId}. DWG не изменён.");
RuntimeDiagnostics.Write("AutoAnnotateViewPreviewCompleted", commandName: "PXP-AAV", resultStatus: "PreviewCompleted", document: document, details: new Dictionary<string, object?> { ["PlanId"] = plan.PlanId, ["ObjectsExamined"] = plan.Summary.ObjectsExamined, ["MultiLeaderCandidates"] = leaders, ["BubbleCandidates"] = bubbles }); RuntimeDiagnostics.Write("AutoAnnotateViewPreviewCompleted", commandName: "PXP-AAV", resultStatus: "PreviewCompleted", document: document, details: new Dictionary<string, object?> { ["PlanId"] = plan.PlanId, ["ObjectsExamined"] = plan.Summary.ObjectsExamined, ["MultiLeaderCandidates"] = leaders, ["BubbleCandidates"] = bubbles });
ScriptDrivenFirstApplyAutomation.RecordPxpAav(plan.PlanId, objects.Select(value => value.SnapshotId).OrderBy(value => value, StringComparer.Ordinal).ToArray(), viewport.Id, plan.Summary.CreateCount, plan.Summary.SkipCount, permit is not null, plan.Summary.ObjectsExamined, objects.Count(value => value.MembershipStatus == ViewMembershipStatus.Resolved));
if (permit is null) return; if (permit is null) return;
if (!string.Equals(permit.ExpectedPlanId, plan.PlanId, StringComparison.Ordinal)) throw new InvalidOperationException("APPLY_PLAN_ID_MISMATCH"); if (!string.Equals(permit.ExpectedPlanId, plan.PlanId, StringComparison.Ordinal)) throw new InvalidOperationException("APPLY_PLAN_ID_MISMATCH");
var selectedSource = objects.SingleOrDefault(x => string.Equals(x.SnapshotId, permit.TargetSnapshotId, StringComparison.Ordinal)) ?? throw new InvalidOperationException("APPLY_TARGET_NOT_FOUND"); var selectedSource = objects.SingleOrDefault(x => string.Equals(x.SnapshotId, permit.TargetSnapshotId, StringComparison.Ordinal)) ?? throw new InvalidOperationException("APPLY_TARGET_NOT_FOUND");
@@ -60,6 +61,7 @@ internal static class AutoAnnotateViewCommand
var outcome = new FirstLimitedPipeAnnotationWriter().Write(document, preflight.Operation, permit.VisibilityState, permit.AnnotationTemplateDwgPath); var outcome = new FirstLimitedPipeAnnotationWriter().Write(document, preflight.Operation, permit.VisibilityState, permit.AnnotationTemplateDwgPath);
document.Editor.WriteMessage("\nPXP-AAV Apply: " + outcome + "; AutoCAD UNDO is available."); document.Editor.WriteMessage("\nPXP-AAV Apply: " + outcome + "; AutoCAD UNDO is available.");
RuntimeDiagnostics.Write("AutoAnnotateViewApplyCompleted", commandName: "PXP-AAV", resultStatus: outcome.ToString(), document: document, details: new Dictionary<string, object?> { ["PlanId"] = plan.PlanId }); RuntimeDiagnostics.Write("AutoAnnotateViewApplyCompleted", commandName: "PXP-AAV", resultStatus: outcome.ToString(), document: document, details: new Dictionary<string, object?> { ["PlanId"] = plan.PlanId });
ScriptDrivenFirstApplyAutomation.RecordApplyOutcome(outcome);
} }
catch (Exception exception) { RuntimeDiagnostics.Write("AutoAnnotateViewFailed", "ERROR", commandName: "PXP-AAV", resultStatus: exception.Message, exception: exception, document: document); document.Editor.WriteMessage("\nPXP-AAV: " + exception.Message); } catch (Exception exception) { RuntimeDiagnostics.Write("AutoAnnotateViewFailed", "ERROR", commandName: "PXP-AAV", resultStatus: exception.Message, exception: exception, document: document); document.Editor.WriteMessage("\nPXP-AAV: " + exception.Message); }
} }
@@ -14,7 +14,7 @@ namespace PRecAnnot.Plant3D2026;
// Test-only observer. The AutoCAD /b processor, never this type, drives PXP-OA. // Test-only observer. The AutoCAD /b processor, never this type, drives PXP-OA.
internal static class ScriptDrivenFirstApplyAutomation internal static class ScriptDrivenFirstApplyAutomation
{ {
private sealed record Config(string Phase, string OrthoDrawingPath, string EvidencePath, string FixtureMarkerPath, string ExpectedEntryAssemblySha256, bool Diagnostic); private sealed record Config(string Phase, string OrthoDrawingPath, string EvidencePath, string FixtureMarkerPath, string ExpectedEntryAssemblySha256, string TargetCommand, bool Diagnostic);
private sealed record Run(int Sequence, string? PlanId, IReadOnlyList<string> Candidates, string? View, int Create, int Skip, bool? PermitAccepted, string? ApplyOutcome, int? DbmodBefore, int? DbmodAfter, AutomationEntityCounts? Before, AutomationEntityCounts? After, bool WillStart, bool Ended, bool Failed, bool Cancelled, int? SourceRows, int? MembershipResolved); private sealed record Run(int Sequence, string? PlanId, IReadOnlyList<string> Candidates, string? View, int Create, int Skip, bool? PermitAccepted, string? ApplyOutcome, int? DbmodBefore, int? DbmodAfter, AutomationEntityCounts? Before, AutomationEntityCounts? After, bool WillStart, bool Ended, bool Failed, bool Cancelled, int? SourceRows, int? MembershipResolved);
private static Config? config; private static Config? config;
private static Document? fixture; private static Document? fixture;
@@ -93,6 +93,8 @@ internal static class ScriptDrivenFirstApplyAutomation
if (!last.WillStart || last.PlanId is not null) return; if (!last.WillStart || last.PlanId is not null) return;
runs[^1] = last with { PlanId = planId, Candidates = candidates, View = view, Create = create, Skip = skip, PermitAccepted = permitAccepted, SourceRows = sourceRows, MembershipResolved = membershipResolved }; runs[^1] = last with { PlanId = planId, Candidates = candidates, View = view, Create = create, Skip = skip, PermitAccepted = permitAccepted, SourceRows = sourceRows, MembershipResolved = membershipResolved };
} }
internal static void RecordPxpAav(string? planId, IReadOnlyList<string> candidates, string? view, int create, int skip, bool? permitAccepted, int sourceRows, int membershipResolved) =>
RecordPxpOa(planId, candidates, view, create, skip, permitAccepted, sourceRows, membershipResolved);
internal static void RecordApplyOutcome(PipeAnnotationWriteOutcome outcome) internal static void RecordApplyOutcome(PipeAnnotationWriteOutcome outcome)
{ {
@@ -184,7 +186,7 @@ internal static class ScriptDrivenFirstApplyAutomation
private static AutomationCommandCorrelationEvidence Correlate(string kind, object sender, string rawName, bool sequenceAccepted) private static AutomationCommandCorrelationEvidence Correlate(string kind, object sender, string rawName, bool sequenceAccepted)
{ {
var normalized = rawName.Trim(); var normalized = rawName.Trim();
var command = string.Equals(normalized, "PXP-OA", StringComparison.OrdinalIgnoreCase); var command = config is not null && string.Equals(normalized, config.TargetCommand, StringComparison.OrdinalIgnoreCase);
var state = prepared && !terminal && config is not null && fixture is not null && database is not null; var state = prepared && !terminal && config is not null && fixture is not null && database is not null;
var senderDocument = sender as Document; var senderDocument = sender as Document;
var senderPath = senderDocument?.Name; var senderPath = senderDocument?.Name;
@@ -218,7 +220,9 @@ internal static class ScriptDrivenFirstApplyAutomation
{ {
var path = Environment.GetEnvironmentVariable("P_REC_ANNOT_AUTOMATION_CONFIG") ?? throw new InvalidOperationException("AUTOMATION_CONFIG_MISSING"); var path = Environment.GetEnvironmentVariable("P_REC_ANNOT_AUTOMATION_CONFIG") ?? throw new InvalidOperationException("AUTOMATION_CONFIG_MISSING");
using var json = JsonDocument.Parse(File.ReadAllText(path)); var root = json.RootElement; using var json = JsonDocument.Parse(File.ReadAllText(path)); var root = json.RootElement;
return new(root.GetProperty("phase").GetString() ?? "Preview", root.GetProperty("orthoDrawingPath").GetString() ?? throw new InvalidOperationException("AUTOMATION_ORTHO_PATH_REQUIRED"), root.GetProperty("evidencePath").GetString() ?? throw new InvalidOperationException("AUTOMATION_EVIDENCE_PATH_REQUIRED"), root.GetProperty("fixtureMarkerPath").GetString() ?? throw new InvalidOperationException("AUTOMATION_MARKER_PATH_REQUIRED"), root.GetProperty("entryAssemblySha256").GetString() ?? throw new InvalidOperationException("AUTOMATION_ENTRY_ASSEMBLY_HASH_REQUIRED"), root.TryGetProperty("diagnostic", out var diagnostic) && diagnostic.ValueKind == JsonValueKind.True); var target = root.TryGetProperty("targetCommand", out var command) ? command.GetString() : "PXP-OA";
if (string.IsNullOrWhiteSpace(target) || !target.All(value => char.IsAsciiLetterOrDigit(value) || value is '-' or '_')) throw new InvalidOperationException("AUTOMATION_TARGET_COMMAND_INVALID");
return new(root.GetProperty("phase").GetString() ?? "Preview", root.GetProperty("orthoDrawingPath").GetString() ?? throw new InvalidOperationException("AUTOMATION_ORTHO_PATH_REQUIRED"), root.GetProperty("evidencePath").GetString() ?? throw new InvalidOperationException("AUTOMATION_EVIDENCE_PATH_REQUIRED"), root.GetProperty("fixtureMarkerPath").GetString() ?? throw new InvalidOperationException("AUTOMATION_MARKER_PATH_REQUIRED"), root.GetProperty("entryAssemblySha256").GetString() ?? throw new InvalidOperationException("AUTOMATION_ENTRY_ASSEMBLY_HASH_REQUIRED"), target, root.TryGetProperty("diagnostic", out var diagnostic) && diagnostic.ValueKind == JsonValueKind.True);
} }
private static void RequireGate(Config value) private static void RequireGate(Config value)
{ {