namespace PRecAnnot.Abstractions; public sealed record RuntimeDiagnostic { public required string Code { get; init; } public required string Message { get; init; } public string Severity { get; init; } = "Warning"; } public enum OrthoDetectionStatus { Confirmed, NotOrtho, Ambiguous, Unsupported, Failed } public enum PlantProjectDetectionStatus { NotFound, FoundWithName, FoundWithoutDisplayName, Ambiguous, Failed } public sealed record OrthoDetectionResult { public required OrthoDetectionStatus Status { get; init; } public required IReadOnlyList Evidence { get; init; } public required IReadOnlyList Diagnostics { get; init; } } public readonly record struct Point2Dto(double X, double Y); public readonly record struct Point3Dto(double X, double Y, double Z); public readonly record struct Vector2Dto(double X, double Y); public sealed record Bounds2Dto(Point2Dto Minimum, Point2Dto Maximum); public sealed record Bounds3Dto(Point3Dto Minimum, Point3Dto Maximum); public enum ExtentsIntersectionType { DoNotIntersect, Intersect, ExtentsMatch, FirstExtentsInsideSecondExtents, SecondExtentsInsideFirstExtents } public sealed record LineNumberAnnotationSettings { public required string NullOrEmpty { get; init; } public required IReadOnlyList Annotations { get; init; } } public sealed record LineNumberAnnotationDefinition { public required string Nickname { get; init; } public IReadOnlyDictionary Variables { get; init; } = new Dictionary(); public required IReadOnlyList Tags { get; init; } } public sealed record LineNumberAnnotationTag { public required string Field { get; init; } public string Divider { get; init; } = string.Empty; public bool SaveWhenEmpty { get; init; } = true; public string IgnoreValue { get; init; } = string.Empty; public string ProcessingXml { get; init; } = string.Empty; } public sealed record LineNumberFormattingResult(bool Success, string Text, string? ErrorCode = null); public interface ILineNumberAnnotationFormatter { LineNumberFormattingResult Format(LineNumberAnnotationDefinition definition, IReadOnlyDictionary fields); } public sealed record DataLinksPropertyReadResult(bool Success, IReadOnlyDictionary Properties, string? FailureCode = null); public interface IDataLinksPropertyReader { DataLinksPropertyReadResult ReadProperties(long rowId); } public sealed record LineNumberFieldResolution(bool Success, IReadOnlyDictionary Values, string? FailureCode = null); public sealed record LineNumberCandidate(string StableId, long RowId, AnnotationPoint Position, double Rotation, string Layer, string TextStyle, IReadOnlyDictionary Properties); public sealed record ExistingLineNumberAnnotation(string StableId, string SourceStableId, string Text); public sealed record LineNumberCommandOperation(string StableId, AnnotationOperationKind Kind, string? Text, AnnotationPoint Position, double Rotation, string Layer, string TextStyle, IReadOnlyList Reasons); public sealed record LineNumberCommandPlan(IReadOnlyList Operations); public sealed record LineNumberApplyPreflight(string StableId, int MarkerNumber, string Text, AnnotationPoint Position, double Rotation, string Layer, string TextStyle); public sealed record LineNumberApplyResult(int Created, int Updated, int Unchanged); public sealed record LineNumberListApplyPreflight(string StableId, AnnotationPoint Position, double Rotation, IReadOnlyList Rows); public sealed record LineNumberPreviewResult(bool Success, LineNumberCommandPlan? Plan, IReadOnlyList Apply, string? FailureCode = null); public sealed record LineNumberCandidateReadResult(bool Success, LineNumberCandidate? Candidate, string? FailureCode = null); public sealed record ElevationCandidate(string StableId, double ModelElevation, double DatumOffset, AnnotationPoint Position, double Rotation, string Layer, string TextStyle); public sealed record ExistingElevationAnnotation(string StableId, string SourceStableId, string Text, AnnotationPoint Position); public sealed record ElevationAnnotationOperation(string StableId, AnnotationOperationKind Kind, string? Text, AnnotationPoint Position, double Rotation, string Layer, string TextStyle, IReadOnlyList Reasons); public sealed record ElevationAnnotationPlan(IReadOnlyList Operations); public sealed record LineConnectionCandidate(string StableId, string LineNumber, Point3Dto FirstEndpoint, Point3Dto SecondEndpoint, Bounds3Dto Bounds, AnnotationPoint Position, double Rotation); public sealed record LineConnectionGroup(string LineNumber, IReadOnlyList Members, AnnotationPoint Placement, double Rotation); public sealed record LineNumberOwnedRow(string SourceStableId, int MarkerNumber, string Text, AnnotationPoint MarkerAttributePosition); public sealed record LineNumberRowMutation(string SourceStableId, int PreviousMarkerNumber, int MarkerNumber, string Text, AnnotationPoint? MarkerAttributePosition); public sealed record LineNumberTextAsset(string Layer, string TextStyle, double Size, string TextValue, Point2Dto Position); public sealed record LineNumberLineAsset(string Layer, Point2Dto Start, Point2Dto End); public sealed record LineNumberMarkerAsset(string Layer, double MaskScaleFactor, IReadOnlyList Texts, IReadOnlyList Lines); public sealed record LineNumberListAsset(string Layer, double MaskScaleFactor, double LineHeight, double LineSpacingDistance, LineNumberTextAsset MarkerText, LineNumberTextAsset LineNumberText, LineNumberLineAsset Line); public sealed record AnnotateLineNumbersAssets(LineNumberMarkerAsset Marker, LineNumberListAsset List); public sealed record GeometrySnapshot { public Point3Dto? WorldPosition { get; init; } public Point2Dto? PaperPosition { get; init; } public Bounds2Dto? ProjectedBounds { get; init; } public double? Rotation { get; init; } public double? Elevation { get; init; } } public sealed record OrthoViewportInfo { public required string Id { get; init; } public required string DisplayName { get; init; } public double CenterX { get; init; } public double CenterY { get; init; } public double Width { get; init; } public double Height { get; init; } public double Scale { get; init; } public double TwistAngle { get; init; } public bool IsOn { get; init; } public bool IsLocked { get; init; } public string? SourceDrawingName { get; init; } public string? ViewName { get; init; } } public sealed record PlantObjectSnapshot { public required string SnapshotId { get; init; } public required string ObjectClass { get; init; } public string? Tag { get; init; } public string? LineNumber { get; init; } public string? SupportNumber { get; init; } public string? EquipmentNumber { get; init; } public required GeometrySnapshot Geometry { get; init; } public IReadOnlyDictionary Properties { get; init; } = new Dictionary(); public IReadOnlyList Diagnostics { get; init; } = Array.Empty(); public ViewMembershipStatus MembershipStatus { get; init; } = ViewMembershipStatus.NotResolved; public IReadOnlyList MembershipEvidenceCodes { get; init; } = Array.Empty(); } public enum ViewMembershipStatus { NotResolved, Resolved, PartiallyResolved, ObjectOutsideView, Unsupported, Failed } public sealed record SourceObjectViewportMembership { public required string SourceObjectStableKey { get; init; } public required string ViewStableKey { get; init; } public required ViewMembershipStatus Status { get; init; } public IReadOnlyList EvidenceCodes { get; init; } = Array.Empty(); public string? ReasonCode { get; init; } } public sealed record PlantRuntimeContext { public bool HasActiveDocument { get; init; } public bool HasPlantProject { get; init; } public bool IsOrthoDrawing { get; init; } public string? DrawingName { get; init; } public string? ProjectDisplayName { get; init; } public PlantProjectDetectionStatus ProjectDetectionStatus { get; init; } = PlantProjectDetectionStatus.NotFound; public IReadOnlyList Viewports { get; init; } = Array.Empty(); public IReadOnlyList Diagnostics { get; init; } = Array.Empty(); public OrthoDetectionResult Detection { get; init; } = new() { Status = OrthoDetectionStatus.Unsupported, Evidence = Array.Empty(), Diagnostics = Array.Empty() }; } public interface IPlantRuntimeContextReader { PlantRuntimeContext ReadCurrentContext(); } public interface IOrthoViewportReader { IReadOnlyList ReadViewports(CancellationToken cancellationToken); } public enum SourceDrawingResolutionStatus { Resolved, NotReferenced, Ambiguous, MissingFromProject, Unsupported, Failed } public sealed record OrthoSourceDrawingReference { public required string StableId { get; init; } public required string DisplayName { get; init; } public string? ProjectRelativePath { get; init; } public long? ProjectDrawingRowId { get; init; } public required SourceDrawingResolutionStatus Status { get; init; } public IReadOnlyList EvidenceCodes { get; init; } = Array.Empty(); } public sealed record SourcePlantObjectSnapshot { public required string StableObjectKey { get; init; } public required string ClassName { get; init; } public string? SourceDrawingStableId { get; init; } public string? LineGroupStableKey { get; init; } public IReadOnlyDictionary Properties { get; init; } = new Dictionary(); } public sealed record SourceDrawingReadResult { public required OrthoSourceDrawingReference Source { get; init; } public IReadOnlyList Objects { get; init; } = Array.Empty(); public IReadOnlyList Diagnostics { get; init; } = Array.Empty(); } public interface IOrthoSourceDrawingResolver { IReadOnlyList Resolve(OrthoDrawingSnapshot drawing); } public sealed record OrthoDrawingSnapshot { public required string StableId { get; init; } public IReadOnlyList Views { get; init; } = Array.Empty(); } public sealed record OrthoViewSourceSnapshot { public required string ViewStableId { get; init; } public IReadOnlyList ReferencedDrawingPaths { get; init; } = Array.Empty(); } public interface ISourceDrawingDataLinksReader { SourceDrawingReadResult Read(PlantProjectContext project, OrthoSourceDrawingReference source); } public sealed record PlantProjectContext { public required string StableProjectId { get; init; } public string? ProjectDisplayName { get; init; } } public enum AnnotationOperationKind { Create, Update, Skip, Conflict, Unsupported } public sealed record AnnotationOperationPlan { public required string SourceSnapshotId { get; init; } public required AnnotationOperationKind Kind { get; init; } public string? AnnotationType { get; init; } public string? Text { get; init; } public Point2Dto? Position { get; init; } public double? Rotation { get; init; } public string? ExistingAnnotationId { get; init; } public required IReadOnlyList Reasons { get; init; } } public sealed record AnnotationPlanSummary { public int ObjectsExamined { get; init; } public int CreateCount { get; init; } public int UpdateCount { get; init; } public int SkipCount { get; init; } public int ConflictCount { get; init; } public int UnsupportedCount { get; init; } public int WarningCount { get; init; } public int ErrorCount { get; init; } } public sealed record AnnotationPlanningRequest { public required string CommandName { get; init; } public required OrthoViewportInfo Viewport { get; init; } public IReadOnlyList Objects { get; init; } = Array.Empty(); public IReadOnlyList Existing { get; init; } = Array.Empty(); // Test-only limited Apply intent. It is part of the canonical plan and is // deliberately explicit: the planner must never choose an arbitrary Pipe. public string? LimitedApplyTargetSnapshotId { get; init; } public string? LimitedApplyRuleId { get; init; } } public interface IAnnotationPlanBuilder { AnnotationPlan Build(AnnotationPlanningRequest request); } public enum PRecAnnotExecutionMode { Smoke, DryRun, Apply } public interface IRuntimeWriteGuard { void EnsureWriteAllowed(string operation); } public sealed record CreatePipeAnnotationOperation { public required string OperationId { get; init; } public required string SourceObjectStableKey { get; init; } public required string ViewStableKey { get; init; } public required string RuleId { get; init; } public required AnnotationPoint Placement { get; init; } public required string DuplicateKey { get; init; } } public sealed record FirstLimitedApplyPermit { public required string FixtureMarker { get; init; } public required bool AllowApply { get; init; } public required string TargetSnapshotId { get; init; } public required string ExpectedPlanId { get; init; } } public sealed record FirstLimitedApplyPreflight { public required string PlanId { get; init; } public required CreatePipeAnnotationOperation Operation { get; init; } } public sealed record OrthoViewportRef(string DrawingId, string ViewportId); public sealed record PlantObjectData { public required string ObjectId { get; init; } public required string ClassName { get; init; } public string? LineNumber { get; init; } public string? Tag { get; init; } public string? DisplayName { get; init; } public required AnnotationPoint Position { get; init; } public double Rotation { get; init; } } public readonly record struct AnnotationPoint(double X, double Y, double Z = 0); public sealed record ExistingAnnotation(string StableKey, string? Text, AnnotationPoint Position); public sealed record AnnotationRequest { public required OrthoViewportRef Viewport { get; init; } public required IReadOnlyList Objects { get; init; } public required IReadOnlyList Existing { get; init; } } public sealed record AnnotationIntent { public required string StableKey { get; init; } public required string Text { get; init; } public required AnnotationPoint Position { get; init; } public required double Rotation { get; init; } public required string ClassName { get; init; } public required string Layer { get; init; } } public sealed record AnnotationPlan { public int PlanSchemaVersion { get; init; } public string PlanId { get; init; } = string.Empty; public string CommandName { get; init; } = string.Empty; public IReadOnlyList Operations { get; init; } = Array.Empty(); public IReadOnlyList Diagnostics { get; init; } = Array.Empty(); public AnnotationPlanSummary Summary { get; init; } = new(); public required IReadOnlyList Create { get; init; } public required IReadOnlyList Update { get; init; } public required IReadOnlyList Delete { get; init; } public required IReadOnlyList SkipReasons { get; init; } public int ExaminedCount { get; init; } public bool IsDeterministic { get; init; } = true; } public interface IPlantProjectContext { bool IsPlantProjectOpen { get; } string? ProjectName { get; } } public interface IOrthoDrawingContext { bool IsOrthoDrawing { get; } IReadOnlyList GetViewports(); } public interface IPlantObjectReader { IReadOnlyList ReadObjects(OrthoViewportInfo viewport, CancellationToken cancellationToken); } public interface IAnnotationRepository { IReadOnlyList FindExisting(OrthoViewportRef viewport); AnnotationWriteResult Apply(AnnotationPlan plan, CancellationToken cancellationToken); } public sealed record AnnotationWriteResult(int Created, int Updated, int Deleted, int Skipped); public interface IAnnotationRuleEngine { AnnotationPlan BuildPlan(AnnotationRequest request); } public sealed record CommandUsageEvent { public required string CommandName { get; init; } public required string ResultStatus { get; init; } public int ObjectsExamined { get; init; } public int AnnotationsCreated { get; init; } public int AnnotationsUpdated { get; init; } public int AnnotationsDeleted { get; init; } public int AnnotationsSkipped { get; init; } public int WarningCount { get; init; } public int ErrorCount { get; init; } public long DurationMilliseconds { get; init; } public DateTimeOffset TimestampUtc { get; init; } = DateTimeOffset.UtcNow; } public interface ICommandUsageSink { void Record(CommandUsageEvent usageEvent); }